@@ -26,8 +26,12 @@ const nid_secp256k1 = C.NID_secp256k1
26
26
27
27
// #define NID_X9_62_id_ecPublicKey 408
28
28
const nid_ec_publickey = C.NID_X9_62_ id_ecPublicKey
29
+ // C.EVP_PKEY_EC = NID_X9_62_id_ecPublicKey
30
+ const nid_evp_pkey_ec = C.EVP_PKEY_EC
31
+ // we only support this
32
+ const openssl_ec_named_curve = C.OPENSSL_EC_NAMED_CURVE
29
33
30
- // The list of supported curve(s)
34
+ // Nid is an enumeration of the supported curves
31
35
pub enum Nid {
32
36
prime256 v1
33
37
secp384 r1
@@ -46,69 +50,34 @@ pub mut:
46
50
fixed_size bool
47
51
}
48
52
49
- // enum flag to allow flexible PrivateKey size
53
+ // HashConfig is an enumeration of the possible options for key signing (verifying).
54
+ pub enum HashConfig {
55
+ with_recommended_hash
56
+ with_no_hash
57
+ with_custom_hash
58
+ }
59
+
60
+ // SignerOpts represents configuration options to drive signing and verifying process.
61
+ @[params]
62
+ pub struct SignerOpts {
63
+ pub mut :
64
+ // default to .with_recommended_hash
65
+ hash_config HashConfig = .with_recommended_hash
66
+ // make sense when HashConfig != with_recommended_hash
67
+ allow_smaller_size bool
68
+ allow_custom_hash bool
69
+ // set to non-nil if allow_custom_hash was true
70
+ custom_hash & hash.Hash = unsafe { nil }
71
+ }
72
+
73
+ // KeyFlag is an enumeration of possible options to support flexible of PrivateKey key size.
50
74
enum KeyFlag {
51
75
// flexible flag to allow flexible-size of seed bytes
52
76
flexible
53
77
// fixed flag for using underlying curve key size
54
78
fixed
55
79
}
56
80
57
- // PrivateKey represents ECDSA private key. Actually its a key pair,
58
- // contains private key and public key parts.
59
- pub struct PrivateKey {
60
- // The new high level of keypair opaque, set to nil now.
61
- evpkey & C.EVP_PKEY = unsafe { nil }
62
- // TODO: when all has been migrated to the new one,
63
- // removes this low level declarations.
64
- key & C.EC_KEY
65
- mut :
66
- // ks_flag with .flexible value allowing
67
- // flexible-size seed bytes as key.
68
- // When it is `.fixed`, it will use the underlying key size.
69
- ks_flag KeyFlag = .flexible
70
- // ks_size stores size of the seed bytes when ks_flag was .flexible.
71
- // You should set it to a non zero value
72
- ks_size int
73
- }
74
-
75
- // PublicKey represents ECDSA public key for verifying message.
76
- pub struct PublicKey {
77
- // The new high level of keypair opaque, set to nil now.
78
- evpkey & C.EVP_PKEY = unsafe { nil }
79
- // Remove this when its fully obsoleted by the new one.
80
- key & C.EC_KEY
81
- }
82
-
83
- // PrivateKey.new creates a new key pair. By default, it would create a prime256v1 based key.
84
- pub fn PrivateKey .new (opt CurveOptions) ! PrivateKey {
85
- // creates new empty key
86
- ec_key := new_curve (opt)
87
- if ec_key == 0 {
88
- C.EC_KEY_free (ec_key)
89
- return error ('Failed to create new EC_KEY' )
90
- }
91
- // Generates new public and private key for the supplied ec_key object.
92
- res := C.EC_KEY_generate_key (ec_key)
93
- if res != 1 {
94
- C.EC_KEY_free (ec_key)
95
- return error ('Failed to generate EC_KEY' )
96
- }
97
- // performs explicit check
98
- chk := C.EC_KEY_check_key (ec_key)
99
- if chk == 0 {
100
- C.EC_KEY_free (ec_key)
101
- return error ('EC_KEY_check_key failed' )
102
- }
103
- // when using default EC_KEY_generate_key, its using underlying curve key size
104
- // and discarded opt.fixed_size flag when its not set.
105
- priv_key := PrivateKey{
106
- key: ec_key
107
- ks_flag: .fixed
108
- }
109
- return priv_key
110
- }
111
-
112
81
// generate_key generates a new key pair. If opt was not provided, its default to prime256v1 curve.
113
82
// If you want another curve, use in the following manner: `pubkey, pivkey := ecdsa.generate_key(nid: .secp384r1)!`
114
83
pub fn generate_key (opt CurveOptions) ! (PublicKey, PrivateKey) {
@@ -250,7 +219,7 @@ pub fn new_key_from_seed(seed []u8, opt CurveOptions) !PrivateKey {
250
219
// EC_KEY_check_key return 1 on success or 0 on error.
251
220
chk := C.EC_KEY_check_key (ec_key)
252
221
if chk == 0 {
253
- key_free (ec_key)
222
+ C. EC_KEY_free (ec_key)
254
223
return error ('EC_KEY_check_key failed' )
255
224
}
256
225
C.EC_POINT_free (pub_key_point)
@@ -271,6 +240,99 @@ pub fn new_key_from_seed(seed []u8, opt CurveOptions) !PrivateKey {
271
240
return pvkey
272
241
}
273
242
243
+ // PrivateKey represents ECDSA private key. Actually its a key pair,
244
+ // contains private key and public key parts.
245
+ pub struct PrivateKey {
246
+ // The new high level of keypair opaque, set to nil now.
247
+ evpkey & C.EVP_PKEY = unsafe { nil }
248
+ // TODO: when all has been migrated to the new one,
249
+ // removes this low level declarations.
250
+ key & C.EC_KEY
251
+ mut :
252
+ // ks_flag with .flexible value allowing
253
+ // flexible-size seed bytes as key.
254
+ // When it is `.fixed`, it will use the underlying key size.
255
+ ks_flag KeyFlag = .flexible
256
+ // ks_size stores size of the seed bytes when ks_flag was .flexible.
257
+ // You should set it to a non zero value
258
+ ks_size int
259
+ }
260
+
261
+ // PrivateKey.new creates a new key pair. By default, it would create a prime256v1 based key.
262
+ // Dont forget to call `.free()` after finish with your key.
263
+ pub fn PrivateKey .new (opt CurveOptions) ! PrivateKey {
264
+ // Default to prime256v1 based key
265
+ mut group_nid := nid_prime256 v1
266
+ match opt.nid {
267
+ .prime256 v1 {}
268
+ .secp384 r1 {
269
+ group_nid = nid_secp384 r1
270
+ }
271
+ .secp521 r1 {
272
+ group_nid = nid_secp521 r1
273
+ }
274
+ .secp256 k1 {
275
+ group_nid = nid_secp256 k1
276
+ }
277
+ }
278
+ // New high level keypair generator
279
+ evpkey := C.EVP_PKEY_new ()
280
+ pctx := C.EVP_PKEY_CTX_new_id (nid_evp_pkey_ec, 0 )
281
+ if pctx == 0 {
282
+ C.EVP_PKEY_free (evpkey)
283
+ C.EVP_PKEY_CTX_free (pctx)
284
+ return error ('C.EVP_PKEY_CTX_new_id failed' )
285
+ }
286
+ nt := C.EVP_PKEY_keygen_init (pctx)
287
+ if nt < = 0 {
288
+ C.EVP_PKEY_free (evpkey)
289
+ C.EVP_PKEY_CTX_free (pctx)
290
+ return error ('EVP_PKEY_keygen_init failed' )
291
+ }
292
+ // set the group (curve)
293
+ cn := C.EVP_PKEY_CTX_set_ec_paramgen_curve_nid (pctx, group_nid)
294
+ if cn < = 0 {
295
+ C.EVP_PKEY_free (evpkey)
296
+ C.EVP_PKEY_CTX_free (pctx)
297
+ return error ('EVP_PKEY_CTX_set_ec_paramgen_curve_nid' )
298
+ }
299
+ // explicitly only allowing named curve, likely its the default on 3.0.
300
+ pn := C.EVP_PKEY_CTX_set_ec_param_enc (pctx, openssl_ec_named_curve)
301
+ if pn < = 0 {
302
+ C.EVP_PKEY_free (evpkey)
303
+ C.EVP_PKEY_CTX_free (pctx)
304
+ return error ('EVP_PKEY_CTX_set_ec_param_enc failed' )
305
+ }
306
+ // generates keypair
307
+ nr := C.EVP_PKEY_keygen (pctx, & evpkey)
308
+ if nr < = 0 {
309
+ C.EVP_PKEY_free (evpkey)
310
+ C.EVP_PKEY_CTX_free (pctx)
311
+ return error ('EVP_PKEY_keygen failed' )
312
+ }
313
+
314
+ // EVP_PKEY_get1_EC_KEY was deprecated in 3.0. Its used here for compatibility purposes
315
+ // to support the old key function.
316
+ // TODO: removes this when its ready to obsolete.
317
+ eckey := C.EVP_PKEY_get1_EC_KEY (evpkey)
318
+ if eckey == 0 {
319
+ C.EVP_PKEY_CTX_free (pctx)
320
+ C.EC_KEY_free (eckey)
321
+ C.EVP_PKEY_free (evpkey)
322
+ return error ('EVP_PKEY_get1_EC_KEY failed' )
323
+ }
324
+ // Cleans up the context
325
+ C.EVP_PKEY_CTX_free (pctx)
326
+ // when using default this function, its using underlying curve key size
327
+ // and discarded opt.fixed_size flag when its not set.
328
+ priv_key := PrivateKey{
329
+ evpkey: evpkey
330
+ key: eckey
331
+ ks_flag: .fixed
332
+ }
333
+ return priv_key
334
+ }
335
+
274
336
// sign performs signing the message with the options. By default options,
275
337
// it will perform hashing before signing the message.
276
338
pub fn (pv PrivateKey) sign (message []u8 , opt SignerOpts) ! []u8 {
@@ -303,18 +365,6 @@ fn (priv_key PrivateKey) sign_message(message []u8) ![]u8 {
303
365
return signed_data.clone ()
304
366
}
305
367
306
- // verify verifies a message with the signature are valid with public key provided .
307
- // You should provide it with the same SignerOpts used with the `.sign()` call.
308
- // or verify would fail (false).
309
- pub fn (pub_key PublicKey) verify (message []u8 , sig []u8 , opt SignerOpts) ! bool {
310
- digest := calc_digest (pub_key.key, message, opt)!
311
- res := C.ECDSA_verify (0 , digest.data, digest.len, sig.data, sig.len, pub_key.key)
312
- if res == - 1 {
313
- return error ('Failed to verify signature' )
314
- }
315
- return res == 1
316
- }
317
-
318
368
// bytes represent private key as bytes.
319
369
pub fn (priv_key PrivateKey) bytes () ! []u8 {
320
370
bn := voidptr (C.EC_KEY_get0_private_key (priv_key.key))
@@ -413,6 +463,33 @@ pub fn (priv_key PrivateKey) equal(other PrivateKey) bool {
413
463
return false
414
464
}
415
465
466
+ // free clears out allocated memory for PrivateKey
467
+ // Dont use PrivateKey after calling `.free()`
468
+ pub fn (pv &PrivateKey) free () {
469
+ C.EC_KEY_free (pv.key)
470
+ C.EVP_PKEY_free (pv.evpkey)
471
+ }
472
+
473
+ // PublicKey represents ECDSA public key for verifying message.
474
+ pub struct PublicKey {
475
+ // The new high level of keypair opaque, set to nil now.
476
+ evpkey & C.EVP_PKEY = unsafe { nil }
477
+ // Remove this when its fully obsoleted by the new one.
478
+ key & C.EC_KEY
479
+ }
480
+
481
+ // verify verifies a message with the signature are valid with public key provided .
482
+ // You should provide it with the same SignerOpts used with the `.sign()` call.
483
+ // or verify would fail (false).
484
+ pub fn (pub_key PublicKey) verify (message []u8 , sig []u8 , opt SignerOpts) ! bool {
485
+ digest := calc_digest (pub_key.key, message, opt)!
486
+ res := C.ECDSA_verify (0 , digest.data, digest.len, sig.data, sig.len, pub_key.key)
487
+ if res == - 1 {
488
+ return error ('Failed to verify signature' )
489
+ }
490
+ return res == 1
491
+ }
492
+
416
493
// Compare two public keys
417
494
pub fn (pub_key PublicKey) equal (other PublicKey) bool {
418
495
// TODO: check validity of the group
@@ -443,6 +520,13 @@ pub fn (pub_key PublicKey) equal(other PublicKey) bool {
443
520
return false
444
521
}
445
522
523
+ // free clears out allocated memory for PublicKey.
524
+ // Dont use PublicKey after calling `.free()`
525
+ pub fn (pb &PublicKey) free () {
526
+ C.EC_KEY_free (pb.key)
527
+ C.EVP_PKEY_free (pb.evpkey)
528
+ }
529
+
446
530
// Helpers
447
531
//
448
532
// new_curve creates a new empty curve based on curve NID, default to prime256v1 (or secp256r1).
@@ -492,24 +576,6 @@ fn recommended_hash(key &C.EC_KEY) !crypto.Hash {
492
576
}
493
577
}
494
578
495
- pub enum HashConfig {
496
- with_recommended_hash
497
- with_no_hash
498
- with_custom_hash
499
- }
500
-
501
- @[params]
502
- pub struct SignerOpts {
503
- pub mut :
504
- // default to .with_recommended_hash
505
- hash_config HashConfig = .with_recommended_hash
506
- // make sense when HashConfig != with_recommended_hash
507
- allow_smaller_size bool
508
- allow_custom_hash bool
509
- // set to non-nil if allow_custom_hash was true
510
- custom_hash & hash.Hash = unsafe { nil }
511
- }
512
-
513
579
fn calc_digest_with_recommended_hash (key & C.EC_KEY, msg []u8 ) ! []u8 {
514
580
h := recommended_hash (key)!
515
581
match h {
@@ -591,15 +657,3 @@ fn calc_digest(key &C.EC_KEY, message []u8, opt SignerOpts) ![]u8 {
591
657
fn key_free (ec_key & C.EC_KEY) {
592
658
C.EC_KEY_free (ec_key)
593
659
}
594
-
595
- // free clears out allocated memory for PublicKey.
596
- // Dont use PublicKey after calling `.free()`
597
- pub fn (pb &PublicKey) free () {
598
- C.EC_KEY_free (pb.key)
599
- }
600
-
601
- // free clears out allocated memory for PrivateKey
602
- // Dont use PrivateKey after calling `.free()`
603
- pub fn (pv &PrivateKey) free () {
604
- C.EC_KEY_free (pv.key)
605
- }
0 commit comments