@@ -101,6 +101,12 @@ pub fn (mut pv PrivateKey) x25519(point []u8) ![]u8 {
101
101
if point.len != point_size {
102
102
return error ('bad point size, should be 32' )
103
103
}
104
+ // We reject and disallow zero-bytes point to be passed
105
+ // and check it here as a quick exit before heavy math
106
+ // calculation on `x25519` call
107
+ if is_zero (point) {
108
+ return error ('x25519: get zeros point' )
109
+ }
104
110
// even technically its possible, but we limit to unallow it
105
111
if subtle.constant_time_compare (pv.key, point) == 1 {
106
112
return error ('pv.key identical with point' )
@@ -121,6 +127,12 @@ pub fn (pv PrivateKey) bytes() ![]u8 {
121
127
// free releases underlying key. Dont use the key after calling .free
122
128
@[unsafe ]
123
129
pub fn (mut pv PrivateKey) free () {
130
+ // when private key has been marked as done (freed),
131
+ // calling free on already freed key would lead to undefined behavior.
132
+ // so, we check it
133
+ if pv.done {
134
+ return
135
+ }
124
136
unsafe { pv.key.free () }
125
137
// sets flag to finish
126
138
pv.done = true
@@ -143,7 +155,7 @@ pub fn PublicKey.new_from_bytes(bytes []u8) !&PublicKey {
143
155
// in curve25519 is generally not needed for Diffie-Hellman key exchange.
144
156
// See https://cr.yp.to/ecdh.html#validate
145
157
// But there are availables suggestion to do validation on them spreads on the internet, likes
146
- // bytes return the clone of the bytes of the underlying PublicKey
158
+ // - blacklisting the known bad public keys
147
159
// - check the shared value and to raise exception if it is zero.
148
160
// - You can also bind the exchanged public keys to the shared keys, i.e.,
149
161
// instead of using H(abG) as the shared keys, you should use H(aG || bG || abG)
@@ -209,6 +221,7 @@ fn (rd RawDerivator) derive(sec []u8, opt DeriveOpts) ![]u8 {
209
221
// 6. Diffie-Hellman with Curve25519
210
222
// See https://datatracker.ietf.org/doc/html/rfc7748#section-6
211
223
pub fn derive_shared_secret (mut local PrivateKey, remote PublicKey, opt SharedOpts) ! []u8 {
224
+ // TODO: should this check be relaxed ?
212
225
// check for safety
213
226
local_pubkey := local.public_key ()!
214
227
if local_pubkey.equal (remote) {
@@ -220,6 +233,8 @@ pub fn derive_shared_secret(mut local PrivateKey, remote PublicKey, opt SharedOp
220
233
// Both now share shared = X25519(local_privkey, remote_pubkey) = X25519(remote_privkey, local_pubkey)
221
234
// as a shared secret, which is then used as a key or input to a key derivation function.
222
235
sec := local.x25519 (remote.key)!
236
+ // Internally, x25519 has builtin check for zeros result
237
+ // but only for non base point branch on x25519_generic routine
223
238
if is_zero (sec) {
224
239
return error ('zeroes shared secret' )
225
240
}
@@ -247,6 +262,11 @@ pub fn derive_shared_secret(mut local PrivateKey, remote PublicKey, opt SharedOp
247
262
// be either `base_point` or the output of another `x25519` call.
248
263
@[direct_array_access]
249
264
pub fn x25519 (mut scalar []u8 , point []u8 ) ! []u8 {
265
+ // likes the previous comment, we add zeroes point check here
266
+ // and reject if it happen.
267
+ if is_zero (point) || is_zero (scalar) {
268
+ return error ('x25519: unallowed zeros/scalar point' )
269
+ }
250
270
mut dst := []u8 {len: 32 }
251
271
// we do bytes clamping here, to make sure scalar was ready to use
252
272
clamp (mut scalar)!
@@ -264,8 +284,8 @@ fn x25519_generic(mut dst []u8, mut scalar []u8, point []u8) ![]u8 {
264
284
return error ('dst: get base_point' )
265
285
}
266
286
} else {
267
- // base := point.clone()
268
287
scalar_mult (mut dst, mut scalar, point)!
288
+ // check for zeros point result
269
289
if is_zero_point (dst) {
270
290
return error ('bad input point: low order point' )
271
291
}
0 commit comments