ecdh.ha (2891B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use bytes; 5 use crypto::ec; 6 use crypto::random; 7 use io; 8 9 10 // Size of the shared secret in bytes when using p256 curves. 11 export def P256_SHAREDSZ = ec::P256_POINTSZ / 2; 12 13 // Size of the shared secret in bytes when using p384 curves. 14 export def P384_SHAREDSZ = ec::P384_POINTSZ / 2; 15 16 // Size of the shared secret in bytes when using p521 curves. 17 export def P521_SHAREDSZ = ec::P521_POINTSZ / 2; 18 19 // Key is either not of expected size or is not a valid point on given curve. 20 export type invalidkey = !void; 21 22 export type privkey = struct { 23 curve: *ec::curve, 24 get_x: *fn (priv: *privkey) []u8, 25 }; 26 27 fn p256_get_x(priv: *privkey) []u8 = (priv: *p256key).x; 28 fn p384_get_x(priv: *privkey) []u8 = (priv: *p384key).x; 29 fn p521_get_x(priv: *privkey) []u8 = (priv: *p521key).x; 30 31 export type p256key = struct { 32 priv: privkey, 33 x: [ec::P256_SCALARSZ]u8, 34 }; 35 36 export type p384key = struct { 37 priv: privkey, 38 x: [ec::P384_SCALARSZ]u8, 39 }; 40 41 export type p521key = struct { 42 priv: privkey, 43 x: [ec::P521_SCALARSZ]u8, 44 }; 45 46 // Creates an unitialized p256 key. The curve is also known as secp256r1 or 47 // prime256. The key must be initialized using [[newkey]]. 48 export fn p256() p256key = p256key { 49 priv = privkey { 50 curve = ec::p256, 51 get_x = &p256_get_x, 52 }, 53 ... 54 }; 55 56 // Creates an unitialized p384 key. The curve is also known as secp384r1. The 57 // key must be initialized using [[newkey]]. 58 export fn p384() p384key = p384key { 59 priv = privkey { 60 curve = ec::p384, 61 get_x = &p384_get_x, 62 }, 63 ... 64 }; 65 66 // Creates an unitialized p521 key. The curve is also known as secp521r1. The 67 // key must be initialized using [[newkey]]. 68 export fn p521() p521key = p521key { 69 priv = privkey { 70 curve = ec::p521, 71 get_x = &p521_get_x, 72 }, 73 ... 74 }; 75 76 // Generates a key seeding from the 'rand' stream and stores it in 'priv'. 77 // 'rand' must be a cryptographic random generator like 78 // [[crypto::random::stream]]. 79 export fn newkey(priv: *privkey, rand: io::handle) (void | io::error) = 80 ec::keygen(priv.curve, priv.get_x(priv), rand)?; 81 82 // Derives the public key from given 'priv' and stores it into 'pub'. Returns 83 // the number of key bytes written to 'pub'. 84 export fn pubkey(pub: []u8, priv: *privkey) size = 85 priv.curve.mulgen(pub, priv.get_x(priv)); 86 87 // Derives a shared secret with the private key 'priv' and the peer's public 88 // key 'pub' and stores it in 'shared'. 89 export fn derive( 90 shared: []u8, 91 priv: *privkey, 92 pub: []u8 93 ) (size | invalidkey) = { 94 match (ec::validate_pointformat(priv.curve, pub)) { 95 case ec::invalid => 96 return invalidkey; 97 case void => void; 98 }; 99 100 let buf: [ec::MAX_POINTSZ]u8 = [0...]; 101 let buf = buf[..len(pub)]; 102 buf[..] = pub[..]; 103 104 if (priv.curve.mul(buf, priv.get_x(priv)) == 0) { 105 return invalidkey; 106 }; 107 108 const csz = priv.curve.pointsz / 2; 109 shared[..] = buf[1..csz + 1]; 110 bytes::zero(buf); 111 return csz; 112 };