@@ -111,3 +111,352 @@ where
111
111
{
112
112
agree ( & my_private_key. 0 , peer_public_key, error_value, kdf)
113
113
}
114
+
115
+ #[ cfg( test) ]
116
+ mod tests {
117
+ use crate :: error:: Unspecified ;
118
+ use crate :: { agreement, rand, test, test_file} ;
119
+
120
+ #[ test]
121
+ fn test_agreement_ecdh_x25519_rfc_iterated ( ) {
122
+ fn expect_iterated_x25519 (
123
+ expected_result : & str ,
124
+ range : core:: ops:: Range < usize > ,
125
+ k : & mut Vec < u8 > ,
126
+ u : & mut Vec < u8 > ,
127
+ ) {
128
+ for _ in range {
129
+ let new_k = x25519 ( k, u) ;
130
+ * u = k. clone ( ) ;
131
+ * k = new_k;
132
+ }
133
+ assert_eq ! ( & h( expected_result) , k) ;
134
+ }
135
+
136
+ let mut k = h ( "0900000000000000000000000000000000000000000000000000000000000000" ) ;
137
+ let mut u = k. clone ( ) ;
138
+
139
+ expect_iterated_x25519 (
140
+ "422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079" ,
141
+ 0 ..1 ,
142
+ & mut k,
143
+ & mut u,
144
+ ) ;
145
+ expect_iterated_x25519 (
146
+ "684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51" ,
147
+ 1 ..1_000 ,
148
+ & mut k,
149
+ & mut u,
150
+ ) ;
151
+
152
+ // The spec gives a test vector for 1,000,000 iterations but it takes
153
+ // too long to do 1,000,000 iterations by default right now. This
154
+ // 10,000 iteration vector is self-computed.
155
+ expect_iterated_x25519 (
156
+ "2c125a20f639d504a7703d2e223c79a79de48c4ee8c23379aa19a62ecd211815" ,
157
+ 1_000 ..10_000 ,
158
+ & mut k,
159
+ & mut u,
160
+ ) ;
161
+
162
+ if cfg ! ( feature = "slow_tests" ) {
163
+ expect_iterated_x25519 (
164
+ "7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424" ,
165
+ 10_000 ..1_000_000 ,
166
+ & mut k,
167
+ & mut u,
168
+ ) ;
169
+ }
170
+ }
171
+
172
+ #[ test]
173
+ fn test_agreement_x25519 ( ) {
174
+ let alg = & agreement:: X25519 ;
175
+ let peer_public = agreement:: UnparsedPublicKey :: new (
176
+ alg,
177
+ test:: from_dirty_hex (
178
+ "e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c" ,
179
+ ) ,
180
+ ) ;
181
+
182
+ let my_private = test:: from_dirty_hex (
183
+ "a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4" ,
184
+ ) ;
185
+
186
+ let my_private = {
187
+ let rng = test:: rand:: FixedSliceRandom { bytes : & my_private } ;
188
+ agreement:: EphemeralPrivateKey :: generate_for_test ( alg, & rng) . unwrap ( )
189
+ } ;
190
+
191
+ let my_public = test:: from_dirty_hex (
192
+ "1c9fd88f45606d932a80c71824ae151d15d73e77de38e8e000852e614fae7019" ,
193
+ ) ;
194
+ let output = test:: from_dirty_hex (
195
+ "c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552" ,
196
+ ) ;
197
+
198
+ assert_eq ! ( my_private. algorithm( ) , alg) ;
199
+
200
+ let computed_public = my_private. compute_public_key ( ) . unwrap ( ) ;
201
+ assert_eq ! ( computed_public. as_ref( ) , & my_public[ ..] ) ;
202
+
203
+ assert_eq ! ( computed_public. algorithm( ) , alg) ;
204
+
205
+ let result = agreement:: agree_ephemeral ( my_private, & peer_public, ( ) , |key_material| {
206
+ assert_eq ! ( key_material, & output[ ..] ) ;
207
+ Ok ( ( ) )
208
+ } ) ;
209
+ assert_eq ! ( result, Ok ( ( ) ) ) ;
210
+ }
211
+
212
+ #[ test]
213
+ fn test_agreement_ecdh_p256 ( ) {
214
+ let alg = & agreement:: ECDH_P256 ;
215
+ let peer_public = agreement:: UnparsedPublicKey :: new (
216
+ alg,
217
+ test:: from_dirty_hex (
218
+ "04D12DFB5289C8D4F81208B70270398C342296970A0BCCB74C736FC7554494BF6356FBF3CA366CC23E8157854C13C58D6AAC23F046ADA30F8353E74F33039872AB" ,
219
+ ) ,
220
+ ) ;
221
+ assert_eq ! ( peer_public. algorithm( ) , alg) ;
222
+ assert_eq ! ( peer_public. bytes( ) , & peer_public. bytes) ;
223
+
224
+ let my_private = test:: from_dirty_hex (
225
+ "C88F01F510D9AC3F70A292DAA2316DE544E9AAB8AFE84049C62A9C57862D1433" ,
226
+ ) ;
227
+
228
+ let my_private = {
229
+ let rng = test:: rand:: FixedSliceRandom { bytes : & my_private } ;
230
+ agreement:: EphemeralPrivateKey :: generate_for_test ( alg, & rng) . unwrap ( )
231
+ } ;
232
+
233
+ let my_public = test:: from_dirty_hex (
234
+ "04DAD0B65394221CF9B051E1FECA5787D098DFE637FC90B9EF945D0C37725811805271A0461CDB8252D61F1C456FA3E59AB1F45B33ACCF5F58389E0577B8990BB3" ,
235
+ ) ;
236
+ let output = test:: from_dirty_hex (
237
+ "D6840F6B42F6EDAFD13116E0E12565202FEF8E9ECE7DCE03812464D04B9442DE" ,
238
+ ) ;
239
+
240
+ assert_eq ! ( my_private. algorithm( ) , alg) ;
241
+
242
+ let computed_public = my_private. compute_public_key ( ) . unwrap ( ) ;
243
+ assert_eq ! ( computed_public. as_ref( ) , & my_public[ ..] ) ;
244
+
245
+ assert_eq ! ( computed_public. algorithm( ) , alg) ;
246
+
247
+ let result = agreement:: agree_ephemeral ( my_private, & peer_public, ( ) , |key_material| {
248
+ assert_eq ! ( key_material, & output[ ..] ) ;
249
+ Ok ( ( ) )
250
+ } ) ;
251
+ assert_eq ! ( result, Ok ( ( ) ) ) ;
252
+ }
253
+
254
+ #[ test]
255
+ fn test_agreement_ecdh_p384 ( ) {
256
+ let alg = & agreement:: ECDH_P384 ;
257
+ let peer_public = agreement:: UnparsedPublicKey :: new (
258
+ alg,
259
+ test:: from_dirty_hex (
260
+ "04E558DBEF53EECDE3D3FCCFC1AEA08A89A987475D12FD950D83CFA41732BC509D0D1AC43A0336DEF96FDA41D0774A3571DCFBEC7AACF3196472169E838430367F66EEBE3C6E70C416DD5F0C68759DD1FFF83FA40142209DFF5EAAD96DB9E6386C" ,
261
+ ) ,
262
+ ) ;
263
+
264
+ let my_private = test:: from_dirty_hex (
265
+ "099F3C7034D4A2C699884D73A375A67F7624EF7C6B3C0F160647B67414DCE655E35B538041E649EE3FAEF896783AB194" ,
266
+ ) ;
267
+
268
+ let my_private = {
269
+ let rng = test:: rand:: FixedSliceRandom { bytes : & my_private } ;
270
+ agreement:: EphemeralPrivateKey :: generate_for_test ( alg, & rng) . unwrap ( )
271
+ } ;
272
+
273
+ let my_public = test:: from_dirty_hex (
274
+ "04667842D7D180AC2CDE6F74F37551F55755C7645C20EF73E31634FE72B4C55EE6DE3AC808ACB4BDB4C88732AEE95F41AA9482ED1FC0EEB9CAFC4984625CCFC23F65032149E0E144ADA024181535A0F38EEB9FCFF3C2C947DAE69B4C634573A81C" ,
275
+ ) ;
276
+ let output = test:: from_dirty_hex (
277
+ "11187331C279962D93D604243FD592CB9D0A926F422E47187521287E7156C5C4D603135569B9E9D09CF5D4A270F59746" ,
278
+ ) ;
279
+
280
+ assert_eq ! ( my_private. algorithm( ) , alg) ;
281
+
282
+ let computed_public = my_private. compute_public_key ( ) . unwrap ( ) ;
283
+ assert_eq ! ( computed_public. as_ref( ) , & my_public[ ..] ) ;
284
+
285
+ assert_eq ! ( computed_public. algorithm( ) , alg) ;
286
+
287
+ let result = agreement:: agree_ephemeral ( my_private, & peer_public, ( ) , |key_material| {
288
+ assert_eq ! ( key_material, & output[ ..] ) ;
289
+ Ok ( ( ) )
290
+ } ) ;
291
+ assert_eq ! ( result, Ok ( ( ) ) ) ;
292
+ }
293
+
294
+ #[ test]
295
+ fn test_agreement_ecdh_p521 ( ) {
296
+ let alg = & agreement:: ECDH_P521 ;
297
+ let peer_public = agreement:: UnparsedPublicKey :: new (
298
+ alg,
299
+ test:: from_dirty_hex (
300
+ "0401a32099b02c0bd85371f60b0dd20890e6c7af048c8179890fda308b359dbbc2b7a832bb8c6526c4af99a7ea3f0b3cb96ae1eb7684132795c478ad6f962e4a6f446d017627357b39e9d7632a1370b3e93c1afb5c851b910eb4ead0c9d387df67cde85003e0e427552f1cd09059aad0262e235cce5fba8cedc4fdc1463da76dcd4b6d1a46" ,
301
+ ) ,
302
+ ) ;
303
+
304
+ let my_private = test:: from_dirty_hex (
305
+ "00df14b1f1432a7b0fb053965fd8643afee26b2451ecb6a8a53a655d5fbe16e4c64ce8647225eb11e7fdcb23627471dffc5c2523bd2ae89957cba3a57a23933e5a78" ,
306
+ ) ;
307
+
308
+ let my_private = {
309
+ let rng = test:: rand:: FixedSliceRandom { bytes : & my_private } ;
310
+ agreement:: EphemeralPrivateKey :: generate_for_test ( alg, & rng) . unwrap ( )
311
+ } ;
312
+
313
+ let my_public = test:: from_dirty_hex (
314
+ "04004e8583bbbb2ecd93f0714c332dff5ab3bc6396e62f3c560229664329baa5138c3bb1c36428abd4e23d17fcb7a2cfcc224b2e734c8941f6f121722d7b6b9415457601cf0874f204b0363f020864672fadbf87c8811eb147758b254b74b14fae742159f0f671a018212bbf25b8519e126d4cad778cfff50d288fd39ceb0cac635b175ec0" ,
315
+ ) ;
316
+ let output = test:: from_dirty_hex (
317
+ "01aaf24e5d47e4080c18c55ea35581cd8da30f1a079565045d2008d51b12d0abb4411cda7a0785b15d149ed301a3697062f42da237aa7f07e0af3fd00eb1800d9c41" ,
318
+ ) ;
319
+
320
+ assert_eq ! ( my_private. algorithm( ) , alg) ;
321
+
322
+ let computed_public = my_private. compute_public_key ( ) . unwrap ( ) ;
323
+ assert_eq ! ( computed_public. as_ref( ) , & my_public[ ..] ) ;
324
+
325
+ assert_eq ! ( computed_public. algorithm( ) , alg) ;
326
+
327
+ let result = agreement:: agree_ephemeral ( my_private, & peer_public, ( ) , |key_material| {
328
+ assert_eq ! ( key_material, & output[ ..] ) ;
329
+ Ok ( ( ) )
330
+ } ) ;
331
+ assert_eq ! ( result, Ok ( ( ) ) ) ;
332
+ }
333
+
334
+ #[ test]
335
+ fn agreement_traits ( ) {
336
+ use crate :: test;
337
+
338
+ let rng = rand:: SystemRandom :: new ( ) ;
339
+
340
+ let ephemeral_private_key =
341
+ agreement:: EphemeralPrivateKey :: generate_for_test ( & agreement:: ECDH_P256 , & rng) . unwrap ( ) ;
342
+
343
+ test:: compile_time_assert_send :: < agreement:: EphemeralPrivateKey > ( ) ;
344
+ test:: compile_time_assert_sync :: < agreement:: EphemeralPrivateKey > ( ) ;
345
+
346
+ assert_eq ! (
347
+ format!( "{:?}" , & ephemeral_private_key) ,
348
+ "EphemeralPrivateKey { algorithm: Algorithm { curve: P256 } }"
349
+ ) ;
350
+ }
351
+
352
+ #[ test]
353
+ fn agreement_agree_ephemeral ( ) {
354
+ let rng = rand:: SystemRandom :: new ( ) ;
355
+
356
+ test:: run (
357
+ test_file ! ( "data/agreement_tests.txt" ) ,
358
+ |section, test_case| {
359
+ assert_eq ! ( section, "" ) ;
360
+
361
+ let curve_name = test_case. consume_string ( "Curve" ) ;
362
+ let alg = alg_from_curve_name ( & curve_name) ;
363
+ let peer_public =
364
+ agreement:: UnparsedPublicKey :: new ( alg, test_case. consume_bytes ( "PeerQ" ) ) ;
365
+
366
+ match test_case. consume_optional_string ( "Error" ) {
367
+ None => {
368
+ let my_private_bytes = test_case. consume_bytes ( "D" ) ;
369
+ let my_private = {
370
+ let rng = test:: rand:: FixedSliceRandom {
371
+ bytes : & my_private_bytes,
372
+ } ;
373
+ agreement:: EphemeralPrivateKey :: generate_for_test ( alg, & rng) ?
374
+ } ;
375
+ let my_public = test_case. consume_bytes ( "MyQ" ) ;
376
+ let output = test_case. consume_bytes ( "Output" ) ;
377
+
378
+ assert_eq ! ( my_private. algorithm( ) , alg) ;
379
+
380
+ let computed_public = my_private. compute_public_key ( ) . unwrap ( ) ;
381
+ assert_eq ! ( computed_public. as_ref( ) , & my_public[ ..] ) ;
382
+
383
+ assert_eq ! ( my_private. algorithm( ) , alg) ;
384
+
385
+ let result = agreement:: agree_ephemeral (
386
+ my_private,
387
+ & peer_public,
388
+ ( ) ,
389
+ |key_material| {
390
+ assert_eq ! ( key_material, & output[ ..] ) ;
391
+ Ok ( ( ) )
392
+ } ,
393
+ ) ;
394
+ assert_eq ! (
395
+ result,
396
+ Ok ( ( ) ) ,
397
+ "Failed on private key: {:?}" ,
398
+ test:: to_hex( my_private_bytes)
399
+ ) ;
400
+ }
401
+
402
+ Some ( _) => {
403
+ fn kdf_not_called ( _: & [ u8 ] ) -> Result < ( ) , ( ) > {
404
+ panic ! (
405
+ "The KDF was called during ECDH when the peer's \
406
+ public key is invalid."
407
+ ) ;
408
+ }
409
+ let dummy_private_key =
410
+ agreement:: EphemeralPrivateKey :: generate ( alg, & rng) ?;
411
+ assert ! ( agreement:: agree_ephemeral(
412
+ dummy_private_key,
413
+ & peer_public,
414
+ ( ) ,
415
+ kdf_not_called
416
+ )
417
+ . is_err( ) ) ;
418
+ }
419
+ }
420
+
421
+ Ok ( ( ) )
422
+ } ,
423
+ ) ;
424
+ }
425
+
426
+ fn h ( s : & str ) -> Vec < u8 > {
427
+ match test:: from_hex ( s) {
428
+ Ok ( v) => v,
429
+ Err ( msg) => {
430
+ panic ! ( "{msg} in {s}" ) ;
431
+ }
432
+ }
433
+ }
434
+
435
+ fn alg_from_curve_name ( curve_name : & str ) -> & ' static agreement:: Algorithm {
436
+ if curve_name == "P-256" {
437
+ & agreement:: ECDH_P256
438
+ } else if curve_name == "P-384" {
439
+ & agreement:: ECDH_P384
440
+ } else if curve_name == "P-521" {
441
+ & agreement:: ECDH_P521
442
+ } else if curve_name == "X25519" {
443
+ & agreement:: X25519
444
+ } else {
445
+ panic ! ( "Unsupported curve: {curve_name}" ) ;
446
+ }
447
+ }
448
+
449
+ fn x25519 ( private_key : & [ u8 ] , public_key : & [ u8 ] ) -> Vec < u8 > {
450
+ x25519_ ( private_key, public_key) . unwrap ( )
451
+ }
452
+
453
+ fn x25519_ ( private_key : & [ u8 ] , public_key : & [ u8 ] ) -> Result < Vec < u8 > , Unspecified > {
454
+ let rng = test:: rand:: FixedSliceRandom { bytes : private_key } ;
455
+ let private_key =
456
+ agreement:: EphemeralPrivateKey :: generate_for_test ( & agreement:: X25519 , & rng) ?;
457
+ let public_key = agreement:: UnparsedPublicKey :: new ( & agreement:: X25519 , public_key) ;
458
+ agreement:: agree_ephemeral ( private_key, & public_key, Unspecified , |agreed_value| {
459
+ Ok ( Vec :: from ( agreed_value) )
460
+ } )
461
+ }
462
+ }
0 commit comments