mirror of
https://github.com/vlang/v.git
synced 2025-09-14 23:12:33 +03:00
crypto.ecdsa: improve safety checking, unify signing (and verifying) api to accept options (#23463)
This commit is contained in:
parent
3c4878063e
commit
c2b7dbf9b4
8 changed files with 752 additions and 109 deletions
|
@ -8,6 +8,10 @@ import crypto
|
|||
import crypto.sha256
|
||||
import crypto.sha512
|
||||
|
||||
// See https://docs.openssl.org/master/man7/openssl_user_macros/#description
|
||||
// should be 0x30000000L, but a lot of EC_KEY method was deprecated on version 3.0
|
||||
// #define OPENSSL_API_COMPAT 0x10100000L
|
||||
|
||||
#flag darwin -L /opt/homebrew/opt/openssl/lib -I /opt/homebrew/opt/openssl/include
|
||||
|
||||
#flag -I/usr/include/openssl
|
||||
|
@ -21,31 +25,32 @@ import crypto.sha512
|
|||
|
||||
// C function declarations
|
||||
fn C.EC_KEY_new_by_curve_name(nid int) &C.EC_KEY
|
||||
fn C.EC_KEY_dup(src &C.EC_KEY) &C.EC_KEY
|
||||
fn C.EC_KEY_generate_key(key &C.EC_KEY) int
|
||||
fn C.EC_KEY_free(key &C.EC_KEY)
|
||||
fn C.BN_bin2bn(s &u8, len int, ret &C.BIGNUM) &C.BIGNUM
|
||||
fn C.EC_KEY_set_public_key(key &C.EC_KEY, &C.EC_POINT) int
|
||||
fn C.EC_KEY_set_private_key(key &C.EC_KEY, prv &C.BIGNUM) int
|
||||
fn C.EC_KEY_get0_group(key &C.EC_KEY) &C.EC_GROUP
|
||||
fn C.EC_KEY_get0_private_key(key &C.EC_KEY) &C.BIGNUM
|
||||
fn C.EC_KEY_get0_public_key(key &C.EC_KEY) &C.EC_POINT
|
||||
fn C.EC_KEY_check_key(key &C.EC_KEY) int
|
||||
fn C.EC_KEY_up_ref(key &C.EC_KEY) int
|
||||
fn C.EC_POINT_new(group &C.EC_GROUP) &C.EC_POINT
|
||||
fn C.EC_POINT_mul(group &C.EC_GROUP, r &C.EC_POINT, n &C.BIGNUM, q &C.EC_POINT, m &C.BIGNUM, ctx &C.BN_CTX) int
|
||||
fn C.EC_KEY_set_public_key(key &C.EC_KEY, &C.EC_POINT) int
|
||||
fn C.EC_POINT_cmp(group &C.EC_GROUP, a &C.EC_POINT, b &C.EC_POINT, ctx &C.BN_CTX) int
|
||||
fn C.EC_POINT_free(point &C.EC_POINT)
|
||||
fn C.EC_GROUP_cmp(a &C.EC_GROUP, b &C.EC_GROUP, ctx &C.BN_CTX) int
|
||||
fn C.BN_num_bits(a &C.BIGNUM) int
|
||||
fn C.BN_bn2bin(a &C.BIGNUM, to &u8) int
|
||||
fn C.BN_bn2binpad(a &C.BIGNUM, to &u8, tolen int) int
|
||||
fn C.BN_cmp(a &C.BIGNUM, b &C.BIGNUM) int
|
||||
fn C.BN_CTX_new() &C.BN_CTX
|
||||
fn C.BN_CTX_free(ctx &C.BN_CTX)
|
||||
fn C.BN_bin2bn(s &u8, len int, ret &C.BIGNUM) &C.BIGNUM
|
||||
fn C.BN_free(a &C.BIGNUM)
|
||||
fn C.ECDSA_size(key &C.EC_KEY) u32
|
||||
fn C.ECDSA_sign(type_ int, dgst &u8, dgstlen int, sig &u8, siglen &u32, eckey &C.EC_KEY) int
|
||||
fn C.ECDSA_verify(type_ int, dgst &u8, dgstlen int, sig &u8, siglen int, eckey &C.EC_KEY) int
|
||||
fn C.EC_KEY_get0_private_key(key &C.EC_KEY) &C.BIGNUM
|
||||
fn C.BN_num_bits(a &C.BIGNUM) int
|
||||
fn C.BN_bn2bin(a &C.BIGNUM, to &u8) int
|
||||
fn C.EC_KEY_up_ref(key &C.EC_KEY) int
|
||||
fn C.BN_cmp(a &C.BIGNUM, b &C.BIGNUM) int
|
||||
fn C.EC_KEY_get0_public_key(key &C.EC_KEY) &C.EC_POINT
|
||||
fn C.EC_POINT_cmp(group &C.EC_GROUP, a &C.EC_POINT, b &C.EC_POINT, ctx &C.BN_CTX) int
|
||||
fn C.BN_CTX_new() &C.BN_CTX
|
||||
fn C.BN_CTX_free(ctx &C.BN_CTX)
|
||||
|
||||
// for checking the key
|
||||
fn C.EC_KEY_check_key(key &C.EC_KEY) int
|
||||
|
||||
// NID constants
|
||||
//
|
||||
|
@ -74,7 +79,12 @@ pub enum Nid {
|
|||
@[params]
|
||||
pub struct CurveOptions {
|
||||
pub mut:
|
||||
nid Nid = .prime256v1 // default to NIST P-256 curve
|
||||
// default to NIST P-256 curve
|
||||
nid Nid = .prime256v1
|
||||
// by default, allow arbitrary size of seed bytes as key.
|
||||
// Set it to `true` when you need fixed size, using the curve key size.
|
||||
// Its main purposes is to support the `.new_key_from_seed` call.
|
||||
fixed_size bool
|
||||
}
|
||||
|
||||
@[typedef]
|
||||
|
@ -95,42 +105,155 @@ struct C.ECDSA_SIG {}
|
|||
@[typedef]
|
||||
struct C.BN_CTX {}
|
||||
|
||||
pub struct PrivateKey {
|
||||
key &C.EC_KEY
|
||||
// enum flag to allow flexible PrivateKey size
|
||||
enum KeyFlag {
|
||||
// flexible flag to allow flexible-size of seed bytes
|
||||
flexible
|
||||
// fixed flag for using underlying curve key size
|
||||
fixed
|
||||
}
|
||||
|
||||
// PrivateKey represents ECDSA private key. Actually its a key pair,
|
||||
// contains private key and public key parts.
|
||||
pub struct PrivateKey {
|
||||
key &C.EC_KEY
|
||||
mut:
|
||||
// ks_flag with .flexible value allowing
|
||||
// flexible-size seed bytes as key.
|
||||
// When it is `.fixed`, it will use the underlying key size.
|
||||
ks_flag KeyFlag = .flexible
|
||||
// ks_size stores size of the seed bytes when ks_flag was .flexible.
|
||||
// You should set it to a non zero value
|
||||
ks_size int
|
||||
}
|
||||
|
||||
// PublicKey represents ECDSA public key for verifying message.
|
||||
pub struct PublicKey {
|
||||
key &C.EC_KEY
|
||||
}
|
||||
|
||||
// Generate a new key pair. If opt was not provided, its default to prime256v1 curve.
|
||||
pub fn generate_key(opt CurveOptions) !(PublicKey, PrivateKey) {
|
||||
// PrivateKey.new creates a new key pair. By default, it would create a prime256v1 based key.
|
||||
pub fn PrivateKey.new(opt CurveOptions) !PrivateKey {
|
||||
// creates new empty key
|
||||
ec_key := new_curve(opt)
|
||||
if ec_key == 0 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('Failed to create new EC_KEY')
|
||||
}
|
||||
// Generates new public and private key for the supplied ec_key object.
|
||||
res := C.EC_KEY_generate_key(ec_key)
|
||||
if res != 1 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('Failed to generate EC_KEY')
|
||||
}
|
||||
|
||||
// performs explicit check
|
||||
chk := C.EC_KEY_check_key(ec_key)
|
||||
if chk == 0 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('EC_KEY_check_key failed')
|
||||
}
|
||||
// when using default EC_KEY_generate_key, its using underlying curve key size
|
||||
// and discarded opt.fixed_size flag when its not set.
|
||||
priv_key := PrivateKey{
|
||||
key: ec_key
|
||||
key: ec_key
|
||||
ks_flag: .fixed
|
||||
}
|
||||
return priv_key
|
||||
}
|
||||
|
||||
// generate_key generates a new key pair. If opt was not provided, its default to prime256v1 curve.
|
||||
// If you want another curve, use in the following manner: `pubkey, pivkey := ecdsa.generate_key(nid: .secp384r1)!`
|
||||
pub fn generate_key(opt CurveOptions) !(PublicKey, PrivateKey) {
|
||||
// creates new empty key
|
||||
ec_key := new_curve(opt)
|
||||
if ec_key == 0 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('Failed to create new EC_KEY')
|
||||
}
|
||||
// we duplicate the empty ec_key and shares similiar curve infos
|
||||
// and used this as public key
|
||||
pbkey := C.EC_KEY_dup(ec_key)
|
||||
if pbkey == 0 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
C.EC_KEY_free(pbkey)
|
||||
return error('Failed on EC_KEY_dup')
|
||||
}
|
||||
res := C.EC_KEY_generate_key(ec_key)
|
||||
if res != 1 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
C.EC_KEY_free(pbkey)
|
||||
return error('Failed to generate EC_KEY')
|
||||
}
|
||||
// we take public key bits from above generated key
|
||||
// and stored in duplicated public key object before.
|
||||
pubkey_point := voidptr(C.EC_KEY_get0_public_key(ec_key))
|
||||
if pubkey_point == 0 {
|
||||
C.EC_POINT_free(pubkey_point)
|
||||
C.EC_KEY_free(ec_key)
|
||||
C.EC_KEY_free(pbkey)
|
||||
return error('Failed to get public key BIGNUM')
|
||||
}
|
||||
np := C.EC_KEY_set_public_key(pbkey, pubkey_point)
|
||||
if np != 1 {
|
||||
C.EC_POINT_free(pubkey_point)
|
||||
C.EC_KEY_free(ec_key)
|
||||
C.EC_KEY_free(pbkey)
|
||||
return error('Failed to set public key')
|
||||
}
|
||||
// when using default generate_key, its using underlying curve key size
|
||||
// and discarded opt.fixed_size flag when its not set.
|
||||
priv_key := PrivateKey{
|
||||
key: ec_key
|
||||
ks_flag: .fixed
|
||||
}
|
||||
pub_key := PublicKey{
|
||||
key: ec_key
|
||||
key: pbkey
|
||||
}
|
||||
return pub_key, priv_key
|
||||
}
|
||||
|
||||
// Create a new private key from a seed. If opt was not provided, its default to prime256v1 curve.
|
||||
// new_key_from_seed creates a new private key from the seed bytes. If opt was not provided,
|
||||
// its default to prime256v1 curve.
|
||||
//
|
||||
// Notes on the seed:
|
||||
// You should make sure, the seed bytes come from a cryptographically secure random generator,
|
||||
// likes the `crypto.rand` or other trusted sources.
|
||||
// Internally, the seed size's would be checked to not exceed the key size of underlying curve,
|
||||
// ie, 32 bytes length for p-256 and secp256k1, 48 bytes length for p-384 and 64 bytes length for p-521.
|
||||
// Its recommended to use seed with bytes length matching with underlying curve key size.
|
||||
pub fn new_key_from_seed(seed []u8, opt CurveOptions) !PrivateKey {
|
||||
// Early exit check
|
||||
if seed.len == 0 {
|
||||
return error('Seed with null-length was not allowed')
|
||||
}
|
||||
// Create a new EC_KEY object with the specified curve
|
||||
ec_key := new_curve(opt)
|
||||
if ec_key == 0 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('Failed to create new EC_KEY')
|
||||
}
|
||||
// Retrieve the EC_GROUP object associated with the EC_KEY
|
||||
// Note: cast with voidptr() to allow -cstrict checks to pass
|
||||
group := voidptr(C.EC_KEY_get0_group(ec_key))
|
||||
if group == 0 {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('Unable to load group')
|
||||
}
|
||||
// Adds early check for upper size, so, we dont hit unnecessary
|
||||
// call to math intensive calculation, conversion and checking routines.
|
||||
num_bits := C.EC_GROUP_get_degree(group)
|
||||
key_size := (num_bits + 7) / 8
|
||||
if seed.len > key_size {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('Seed length exceeds key size')
|
||||
}
|
||||
// Check if its using fixed key size or flexible one
|
||||
if opt.fixed_size {
|
||||
if seed.len != key_size {
|
||||
C.EC_KEY_free(ec_key)
|
||||
return error('seed size doesnt match with curve key size')
|
||||
}
|
||||
}
|
||||
// Convert the seed bytes into a BIGNUM
|
||||
bn := C.BN_bin2bn(seed.data, seed.len, 0)
|
||||
if bn == 0 {
|
||||
|
@ -146,17 +269,6 @@ pub fn new_key_from_seed(seed []u8, opt CurveOptions) !PrivateKey {
|
|||
}
|
||||
// Now compute the public key
|
||||
//
|
||||
// Retrieve the EC_GROUP object associated with the EC_KEY
|
||||
// Note:
|
||||
// Its cast-ed with voidptr() to workaround the strictness of the type system,
|
||||
// ie, cc backend with `-cstrict` option behaviour. Without this cast,
|
||||
// C.EC_KEY_get0_group expected to return `const EC_GROUP *`,
|
||||
// ie expected to return pointer into constant of EC_GROUP on C parts,
|
||||
// so, its make cgen not happy with this and would fail with error.
|
||||
group := voidptr(C.EC_KEY_get0_group(ec_key))
|
||||
if group == 0 {
|
||||
return error('failed to load group')
|
||||
}
|
||||
// Create a new EC_POINT object for the public key
|
||||
pub_key_point := C.EC_POINT_new(group)
|
||||
// Create a new BN_CTX object for efficient BIGNUM operations
|
||||
|
@ -195,14 +307,38 @@ pub fn new_key_from_seed(seed []u8, opt CurveOptions) !PrivateKey {
|
|||
}
|
||||
C.EC_POINT_free(pub_key_point)
|
||||
C.BN_free(bn)
|
||||
return PrivateKey{
|
||||
|
||||
mut pvkey := PrivateKey{
|
||||
key: ec_key
|
||||
}
|
||||
// we set the flag information on the key
|
||||
if opt.fixed_size {
|
||||
// using fixed one
|
||||
pvkey.ks_flag = .fixed
|
||||
pvkey.ks_size = key_size
|
||||
} else {
|
||||
pvkey.ks_size = seed.len
|
||||
}
|
||||
|
||||
return pvkey
|
||||
}
|
||||
|
||||
// Sign a message with private key
|
||||
// FIXME: should the message should be hashed?
|
||||
pub fn (priv_key PrivateKey) sign(message []u8) ![]u8 {
|
||||
// sign performs signing the message with the options. By default options,
|
||||
// it will perform hashing before signing the message.
|
||||
pub fn (pv PrivateKey) sign(message []u8, opt SignerOpts) ![]u8 {
|
||||
digest := calc_digest(pv.key, message, opt)!
|
||||
return pv.sign_message(digest)!
|
||||
}
|
||||
|
||||
// sign_with_options signs message with the options. It will be deprecated,
|
||||
// Use `PrivateKey.sign()` instead.
|
||||
@[deprecated: 'use PrivateKey.sign() instead']
|
||||
pub fn (pv PrivateKey) sign_with_options(message []u8, opt SignerOpts) ![]u8 {
|
||||
return pv.sign(message, opt)
|
||||
}
|
||||
|
||||
// sign_message sign a message with private key.
|
||||
fn (priv_key PrivateKey) sign_message(message []u8) ![]u8 {
|
||||
if message.len == 0 {
|
||||
return error('Message cannot be null or empty')
|
||||
}
|
||||
|
@ -219,49 +355,95 @@ pub fn (priv_key PrivateKey) sign(message []u8) ![]u8 {
|
|||
return signed_data.clone()
|
||||
}
|
||||
|
||||
// Verify a signature with public key
|
||||
pub fn (pub_key PublicKey) verify(message []u8, sig []u8) !bool {
|
||||
res := C.ECDSA_verify(0, message.data, message.len, sig.data, sig.len, pub_key.key)
|
||||
// verify verifies a message with the signature are valid with public key provided .
|
||||
// You should provide it with the same SignerOpts used with the `.sign()` call.
|
||||
// or verify would fail (false).
|
||||
pub fn (pub_key PublicKey) verify(message []u8, sig []u8, opt SignerOpts) !bool {
|
||||
digest := calc_digest(pub_key.key, message, opt)!
|
||||
res := C.ECDSA_verify(0, digest.data, digest.len, sig.data, sig.len, pub_key.key)
|
||||
if res == -1 {
|
||||
return error('Failed to verify signature')
|
||||
}
|
||||
return res == 1
|
||||
}
|
||||
|
||||
// Get the seed (private key bytes)
|
||||
pub fn (priv_key PrivateKey) seed() ![]u8 {
|
||||
// bytes represent private key as bytes.
|
||||
pub fn (priv_key PrivateKey) bytes() ![]u8 {
|
||||
bn := voidptr(C.EC_KEY_get0_private_key(priv_key.key))
|
||||
if bn == 0 {
|
||||
return error('Failed to get private key BIGNUM')
|
||||
}
|
||||
num_bytes := (C.BN_num_bits(bn) + 7) / 8
|
||||
mut buf := []u8{len: int(num_bytes)}
|
||||
res := C.BN_bn2bin(bn, buf.data)
|
||||
// Get the buffer size to store the seed.
|
||||
size := if priv_key.ks_flag == .flexible {
|
||||
// should be non zero
|
||||
priv_key.ks_size
|
||||
} else {
|
||||
num_bytes
|
||||
}
|
||||
mut buf := []u8{len: int(size)}
|
||||
res := C.BN_bn2binpad(bn, buf.data, size)
|
||||
if res == 0 {
|
||||
return error('Failed to convert BIGNUM to bytes')
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
// Get the public key from private key
|
||||
// seed gets the seed (private key bytes). It will be deprecated.
|
||||
// Use `PrivateKey.bytes()` instead.
|
||||
@[deprecated: 'use PrivateKey.bytes() instead']
|
||||
pub fn (priv_key PrivateKey) seed() ![]u8 {
|
||||
return priv_key.bytes()
|
||||
}
|
||||
|
||||
// Get the public key from private key.
|
||||
pub fn (priv_key PrivateKey) public_key() !PublicKey {
|
||||
// Increase reference count
|
||||
res := C.EC_KEY_up_ref(priv_key.key)
|
||||
if res != 1 {
|
||||
return error('Failed to increment EC_KEY reference count')
|
||||
// There are some issues concerned when returning PublicKey directly using underlying
|
||||
// `PrivateKey.key`. This private key containing sensitive information inside it, so return
|
||||
// this without care maybe can lead to some serious security impact.
|
||||
// See https://discord.com/channels/592103645835821068/592320321995014154/1329261267965448253
|
||||
// So, we instead return a new EC_KEY opaque based information availables on private key object
|
||||
// without private key bits has been set on this new opaque.
|
||||
group := voidptr(C.EC_KEY_get0_group(priv_key.key))
|
||||
if group == 0 {
|
||||
return error('Failed to load group from priv_key')
|
||||
}
|
||||
nid := C.EC_GROUP_get_curve_name(group)
|
||||
if nid != nid_prime256v1 && nid != nid_secp384r1 && nid != nid_secp521r1 && nid != nid_secp256k1 {
|
||||
return error('Get unsupported curve nid')
|
||||
}
|
||||
// get public key point from private key opaque
|
||||
pubkey_point := voidptr(C.EC_KEY_get0_public_key(priv_key.key))
|
||||
if pubkey_point == 0 {
|
||||
// C.EC_POINT_free(pubkey_point)
|
||||
// todo: maybe its not set, just calculates new one
|
||||
return error('Failed to get public key BIGNUM')
|
||||
}
|
||||
// creates a new EC_KEY opaque based on the same NID with private key and
|
||||
// sets public key on it.
|
||||
pub_key := C.EC_KEY_new_by_curve_name(nid)
|
||||
np := C.EC_KEY_set_public_key(pub_key, pubkey_point)
|
||||
if np != 1 {
|
||||
// C.EC_POINT_free(pubkey_point)
|
||||
C.EC_KEY_free(pub_key)
|
||||
return error('Failed to set public key')
|
||||
}
|
||||
// performs explicit check
|
||||
chk := C.EC_KEY_check_key(pub_key)
|
||||
if chk == 0 {
|
||||
C.EC_KEY_free(pub_key)
|
||||
return error('EC_KEY_check_key failed')
|
||||
}
|
||||
// OK ?
|
||||
return PublicKey{
|
||||
key: priv_key.key
|
||||
key: pub_key
|
||||
}
|
||||
}
|
||||
|
||||
// EC_GROUP_cmp() for comparing two group (curve).
|
||||
// EC_GROUP_cmp returns 0 if the curves are equal, 1 if they are not equal, or -1 on error.
|
||||
fn C.EC_GROUP_cmp(a &C.EC_GROUP, b &C.EC_GROUP, ctx &C.BN_CTX) int
|
||||
|
||||
// equal compares two private keys was equal. Its checks for two things, ie:
|
||||
// - whether both of private keys lives under the same group (curve)
|
||||
// - compares if two private key bytes was equal
|
||||
//
|
||||
// - whether both of private keys lives under the same group (curve),
|
||||
// - compares if two private key bytes was equal.
|
||||
pub fn (priv_key PrivateKey) equal(other PrivateKey) bool {
|
||||
group1 := voidptr(C.EC_KEY_get0_group(priv_key.key))
|
||||
group2 := voidptr(C.EC_KEY_get0_group(other.key))
|
||||
|
@ -335,10 +517,10 @@ fn new_curve(opt CurveOptions) &C.EC_KEY {
|
|||
return C.EC_KEY_new_by_curve_name(nid)
|
||||
}
|
||||
|
||||
// Gets recommended hash function of the current PrivateKey.
|
||||
// Its purposes for hashing message to be signed
|
||||
fn (pv PrivateKey) recommended_hash() !crypto.Hash {
|
||||
group := voidptr(C.EC_KEY_get0_group(pv.key))
|
||||
// Gets recommended hash function of the key.
|
||||
// Its purposes for hashing message to be signed.
|
||||
fn recommended_hash(key &C.EC_KEY) !crypto.Hash {
|
||||
group := voidptr(C.EC_KEY_get0_group(key))
|
||||
if group == 0 {
|
||||
return error('Unable to load group')
|
||||
}
|
||||
|
@ -363,7 +545,7 @@ fn (pv PrivateKey) recommended_hash() !crypto.Hash {
|
|||
}
|
||||
|
||||
pub enum HashConfig {
|
||||
with_recomended_hash
|
||||
with_recommended_hash
|
||||
with_no_hash
|
||||
with_custom_hash
|
||||
}
|
||||
|
@ -371,44 +553,46 @@ pub enum HashConfig {
|
|||
@[params]
|
||||
pub struct SignerOpts {
|
||||
pub mut:
|
||||
hash_config HashConfig = .with_recomended_hash
|
||||
// make sense when HashConfig != with_recomended_hash
|
||||
// default to .with_recommended_hash
|
||||
hash_config HashConfig = .with_recommended_hash
|
||||
// make sense when HashConfig != with_recommended_hash
|
||||
allow_smaller_size bool
|
||||
allow_custom_hash bool
|
||||
// set to non-nil if allow_custom_hash was true
|
||||
custom_hash &hash.Hash = unsafe { nil }
|
||||
}
|
||||
|
||||
// sign_with_options sign the message with the options. By default, it would precompute
|
||||
// hash value from message, with recommended_hash function, and then sign the hash value.
|
||||
pub fn (pv PrivateKey) sign_with_options(message []u8, opts SignerOpts) ![]u8 {
|
||||
// calc_digest tries to calculates digest (hash) of the message based on options provided.
|
||||
// If the options was with_no_hash, its return default message without hashing.
|
||||
fn calc_digest(key &C.EC_KEY, message []u8, opt SignerOpts) ![]u8 {
|
||||
if message.len == 0 {
|
||||
return error('null-length messages')
|
||||
}
|
||||
// we're working on mutable copy of SignerOpts, with some issues when make it as a mutable.
|
||||
// ie, declaring a mutable parameter that accepts a struct with the `@[params]` attribute is not allowed.
|
||||
mut cfg := opts
|
||||
mut cfg := opt
|
||||
match cfg.hash_config {
|
||||
.with_recomended_hash {
|
||||
h := pv.recommended_hash()!
|
||||
.with_no_hash {
|
||||
// return original message
|
||||
return message
|
||||
}
|
||||
.with_recommended_hash {
|
||||
h := recommended_hash(key)!
|
||||
match h {
|
||||
.sha256 {
|
||||
digest := sha256.sum256(message)
|
||||
return pv.sign(digest)!
|
||||
return sha256.sum256(message)
|
||||
}
|
||||
.sha384 {
|
||||
digest := sha512.sum384(message)
|
||||
return pv.sign(digest)!
|
||||
return sha512.sum384(message)
|
||||
}
|
||||
.sha512 {
|
||||
digest := sha512.sum512(message)
|
||||
return pv.sign(digest)!
|
||||
return sha512.sum512(message)
|
||||
}
|
||||
else {
|
||||
return error('Unsupported hash')
|
||||
}
|
||||
}
|
||||
}
|
||||
.with_no_hash {
|
||||
return pv.sign(message)!
|
||||
}
|
||||
.with_custom_hash {
|
||||
if !cfg.allow_custom_hash {
|
||||
return error('custom hash was not allowed, set it into true')
|
||||
|
@ -417,7 +601,7 @@ pub fn (pv PrivateKey) sign_with_options(message []u8, opts SignerOpts) ![]u8 {
|
|||
return error('Custom hasher was not defined')
|
||||
}
|
||||
// check key size bits
|
||||
group := voidptr(C.EC_KEY_get0_group(pv.key))
|
||||
group := voidptr(C.EC_KEY_get0_group(key))
|
||||
if group == 0 {
|
||||
return error('fail to load group')
|
||||
}
|
||||
|
@ -431,16 +615,27 @@ pub fn (pv PrivateKey) sign_with_options(message []u8, opts SignerOpts) ![]u8 {
|
|||
return error('Hash into smaller size than current key size was not allowed')
|
||||
}
|
||||
}
|
||||
// otherwise, just hash the message and sign
|
||||
digest := cfg.custom_hash.sum(message)
|
||||
defer { unsafe { cfg.custom_hash.free() } }
|
||||
return pv.sign(digest)!
|
||||
return digest
|
||||
}
|
||||
}
|
||||
return error('Not should be here')
|
||||
}
|
||||
|
||||
// Clear allocated memory for key
|
||||
pub fn key_free(ec_key &C.EC_KEY) {
|
||||
fn key_free(ec_key &C.EC_KEY) {
|
||||
C.EC_KEY_free(ec_key)
|
||||
}
|
||||
|
||||
// free clears out allocated memory for PublicKey.
|
||||
// Dont use PublicKey after calling `.free()`
|
||||
pub fn (pb &PublicKey) free() {
|
||||
C.EC_KEY_free(pb.key)
|
||||
}
|
||||
|
||||
// free clears out allocated memory for PrivateKey
|
||||
// Dont use PrivateKey after calling `.free()`
|
||||
pub fn (pv &PrivateKey) free() {
|
||||
C.EC_KEY_free(pv.key)
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue