Skip to content

Commit

Permalink
Updates to pass strict cc option
Browse files Browse the repository at this point in the history
  • Loading branch information
blackshirt committed Jan 10, 2025
1 parent 1e68a82 commit d915f15
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 23 deletions.
2 changes: 1 addition & 1 deletion vlib/crypto/ecdsa/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ Its currently (expanded) to support the following curves:
- NIST P-256 curve, commonly referred as prime256v1 or secp256r1
- NIST P-384 curve, commonly referred as secp384r1
- NIST P-521 curve, commonly referred as secp521r1
- A famous BITCOIN curve, commonly referred as secp256k1
- A famous Bitcoin curve, commonly referred as secp256k1
51 changes: 38 additions & 13 deletions vlib/crypto/ecdsa/ecdsa.v
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ fn C.EC_POINT_cmp(group &C.EC_GROUP, a &C.EC_POINT, b &C.EC_POINT, ctx &C.BN_CTX
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
//
// NIST P-256 is refered to as secp256r1 and prime256v1, defined as #define NID_X9_62_prime256v1 415
Expand Down Expand Up @@ -111,6 +114,7 @@ pub fn generate_key(opt CurveOptions) !(PublicKey, PrivateKey) {
C.EC_KEY_free(ec_key)
return error('Failed to generate EC_KEY')
}

priv_key := PrivateKey{
key: ec_key
}
Expand Down Expand Up @@ -143,7 +147,16 @@ 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
group := C.EC_KEY_get0_group(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
Expand Down Expand Up @@ -173,6 +186,13 @@ pub fn new_key_from_seed(seed []u8, opt CurveOptions) !PrivateKey {
C.EC_KEY_free(ec_key)
return error('Failed to set public key')
}
// Add key check
// EC_KEY_check_key return 1 on success or 0 on error.
chk := C.EC_KEY_check_key(ec_key)
if chk == 0 {
key_free(ec_key)
return error('EC_KEY_check_key failed')
}
C.EC_POINT_free(pub_key_point)
C.BN_free(bn)
return PrivateKey{
Expand Down Expand Up @@ -210,7 +230,7 @@ pub fn (pub_key PublicKey) verify(message []u8, sig []u8) !bool {

// Get the seed (private key bytes)
pub fn (priv_key PrivateKey) seed() ![]u8 {
bn := C.EC_KEY_get0_private_key(priv_key.key)
bn := voidptr(C.EC_KEY_get0_private_key(priv_key.key))
if bn == 0 {
return error('Failed to get private key BIGNUM')
}
Expand Down Expand Up @@ -243,8 +263,8 @@ fn C.EC_GROUP_cmp(a &C.EC_GROUP, b &C.EC_GROUP, ctx &C.BN_CTX) int
// - 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 := C.EC_KEY_get0_group(priv_key.key)
group2 := C.EC_KEY_get0_group(other.key)
group1 := voidptr(C.EC_KEY_get0_group(priv_key.key))
group2 := voidptr(C.EC_KEY_get0_group(other.key))
ctx := C.BN_CTX_new()
if ctx == 0 {
return false
Expand All @@ -255,8 +275,8 @@ pub fn (priv_key PrivateKey) equal(other PrivateKey) bool {
gres := C.EC_GROUP_cmp(group1, group2, ctx)
// Its lives on the same group
if gres == 0 {
bn1 := C.EC_KEY_get0_private_key(priv_key.key)
bn2 := C.EC_KEY_get0_private_key(other.key)
bn1 := voidptr(C.EC_KEY_get0_private_key(priv_key.key))
bn2 := voidptr(C.EC_KEY_get0_private_key(other.key))
res := C.BN_cmp(bn1, bn2)
return res == 0
}
Expand All @@ -266,9 +286,11 @@ pub fn (priv_key PrivateKey) equal(other PrivateKey) bool {
// Compare two public keys
pub fn (pub_key PublicKey) equal(other PublicKey) bool {
// TODO: check validity of the group
group1 := C.EC_KEY_get0_group(pub_key.key)
group2 := C.EC_KEY_get0_group(other.key)

group1 := voidptr(C.EC_KEY_get0_group(pub_key.key))
group2 := voidptr(C.EC_KEY_get0_group(other.key))
if group1 == 0 || group2 == 0 {
return false
}
ctx := C.BN_CTX_new()
if ctx == 0 {
return false
Expand All @@ -279,8 +301,11 @@ pub fn (pub_key PublicKey) equal(other PublicKey) bool {
gres := C.EC_GROUP_cmp(group1, group2, ctx)
// Its lives on the same group
if gres == 0 {
point1 := C.EC_KEY_get0_public_key(pub_key.key)
point2 := C.EC_KEY_get0_public_key(other.key)
point1 := voidptr(C.EC_KEY_get0_public_key(pub_key.key))
point2 := voidptr(C.EC_KEY_get0_public_key(other.key))
if point1 == 0 || point2 == 0 {
return false
}
res := C.EC_POINT_cmp(group1, point1, point2, ctx)
return res == 0
}
Expand Down Expand Up @@ -313,7 +338,7 @@ fn new_curve(opt CurveOptions) &C.EC_KEY {
// Gets recommended hash function of the current PrivateKey.
// Its purposes for hashing message to be signed
fn (pv PrivateKey) recommended_hash() !crypto.Hash {
group := C.EC_KEY_get0_group(pv.key)
group := voidptr(C.EC_KEY_get0_group(pv.key))
if group == 0 {
return error('Unable to load group')
}
Expand Down Expand Up @@ -392,7 +417,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 := C.EC_KEY_get0_group(pv.key)
group := voidptr(C.EC_KEY_get0_group(pv.key))
if group == 0 {
return error('fail to load group')
}
Expand Down
2 changes: 0 additions & 2 deletions vlib/crypto/ecdsa/ecdsa_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -146,5 +146,3 @@ fn test_different_keys_not_equal() ! {
key_free(priv_key1.key)
key_free(priv_key2.key)
}

// Example was taken from https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/P384_SHA384.pdf
15 changes: 8 additions & 7 deletions vlib/crypto/ecdsa/util.v
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ module ecdsa

#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/x509.h>

// #define NID_X9_62_id_ecPublicKey 408
// #define NID_X9_62_id_ecPublicKey 408
const nid_ec_publickey = C.NID_X9_62_id_ecPublicKey

@[typedef]
Expand All @@ -19,7 +20,7 @@ fn C.EVP_PKEY_free(key &C.EVP_PKEY)
fn C.EVP_PKEY_get1_EC_KEY(pkey &C.EVP_PKEY) &C.EC_KEY

// EVP_PKEY *d2i_PUBKEY(EVP_PKEY **a, const unsigned char **pp, long length);
fn C.d2i_PUBKEY(mut k &C.EVP_PKEY, pp &u8, length u32) &C.EVP_PKEY
fn C.d2i_PUBKEY(k &&C.EVP_PKEY, pp &&u8, length u32) &C.EVP_PKEY

// point_conversion_form_t EC_KEY_get_conv_form(const EC_KEY *key);
fn C.EC_KEY_get_conv_form(k &C.EC_KEY) int
Expand Down Expand Up @@ -63,7 +64,7 @@ pub fn pubkey_from_bytes(bytes []u8) !PublicKey {
return error('Invalid bytes')
}
mut pub_key := C.EVP_PKEY_new()
pub_key = C.d2i_PUBKEY(mut &pub_key, &bytes.data, bytes.len)
pub_key = C.d2i_PUBKEY(&pub_key, voidptr(&bytes.data), bytes.len)
if pub_key == 0 {
C.EVP_PKEY_free(pub_key)
return error('Error loading public key')
Expand All @@ -78,11 +79,11 @@ pub fn pubkey_from_bytes(bytes []u8) !PublicKey {

eckey := C.EVP_PKEY_get1_EC_KEY(pub_key)
if eckey == 0 {
C.EC_KEY_free(eckey)
key_free(eckey)
return error('Failed to get ec key')
}
// check the group for the supported curve(s)
group := C.EC_KEY_get0_group(eckey)
group := voidptr(C.EC_KEY_get0_group(eckey))
if group == 0 {
C.EC_GROUP_free(group)
return error('Failed to load group from key')
Expand All @@ -100,13 +101,13 @@ pub fn pubkey_from_bytes(bytes []u8) !PublicKey {

// bytes gets the bytes of public key parts of this keypair.
pub fn (pbk PublicKey) bytes() ![]u8 {
point := C.EC_KEY_get0_public_key(pbk.key)
point := voidptr(C.EC_KEY_get0_public_key(pbk.key))
if point == 0 {
C.EC_POINT_free(point)
return error('Failed to get public key BIGNUM')
}

group := C.EC_KEY_get0_group(pbk.key)
group := voidptr(C.EC_KEY_get0_group(pbk.key))
num_bits := C.EC_GROUP_get_degree(group)
// 1 byte of conversion format || x || y of EC_POINT
num_bytes := 1 + 2 * ((num_bits + 7) / 8)
Expand Down
11 changes: 11 additions & 0 deletions vlib/crypto/ecdsa/util_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,14 @@ fn test_load_pubkey_from_der_serialized_bytes() ! {
status_with_hashed := pbkey.verify(hashed_msg, expected_signature)!
assert status_with_hashed == true
}

fn test_for_pubkey_bytes() ! {
// material generated with online ecdsa generator https://emn178.github.io/online-tools/ecdsa/key-generator/
pv := '62e998bea8a15f52ff0b76cf3fe281cfcd8042ce4479b6e652ca7b5a36f6fb40'
pb := '0421af184ac64c8a13e66c65d4f1ad31677edeaa97af791aef73b66ea26d1623a411f67b6c4d842ba22fa39d1216bd64acef00a1b924ac11a10af679ac3a7eb2fd'
pvkey := new_key_from_seed(hex.decode(pv)!)!

assert pvkey.seed()!.hex() == pv
pbkey := pvkey.public_key()!
assert pbkey.bytes()!.hex() == pb
}

0 comments on commit d915f15

Please sign in to comment.