ECC added: verify_message_rfc7518, sign_message_rfc7518, curve2hash
Karel Miko
8 years ago
447 | 447 | $curve = 'P-256' if $curve =~ /(secp256r1|nistp256|prime256v1)/; |
448 | 448 | $curve = 'P-384' if $curve =~ /(secp384r1|nistp384)/; |
449 | 449 | $curve = 'P-521' if $curve =~ /(secp521r1|nistp521)/; |
450 | if ($type eq 'private') { | |
450 | if ($type && $type eq 'private') { | |
451 | 451 | return unless $kh->{pub_x} && $kh->{pub_y} && $kh->{k}; |
452 | 452 | for (qw/pub_x pub_y k/) { |
453 | 453 | $kh->{$_} = "0$kh->{$_}" if length($kh->{$_}) % 2; |
460 | 460 | encode_base64url(pack("H*", $kh->{pub_y})), |
461 | 461 | encode_base64url(pack("H*", $kh->{k})); |
462 | 462 | } |
463 | elsif ($type eq 'public') { | |
463 | elsif ($type && $type eq 'public') { | |
464 | 464 | return unless $kh->{pub_x} && $kh->{pub_y}; |
465 | 465 | for (qw/pub_x pub_y/) { |
466 | 466 | $kh->{$_} = "0$kh->{$_}" if length($kh->{$_}) % 2; |
486 | 486 | } |
487 | 487 | if ($key->{crv} && $key->{kty} && $key->{kty} eq "EC" && ($key->{d} || ($key->{x} && $key->{y}))) { |
488 | 488 | # hash with items corresponding to JSON Web Key (JWK) |
489 | $key = {%$key}; # make a copy as we will modify it | |
489 | 490 | for (qw/x y d/) { |
490 | 491 | $key->{$_} = eval { unpack("H*", decode_base64url($key->{$_})) } if exists $key->{$_}; |
491 | 492 | } |
493 | 494 | return $self->_import_hex($key->{x}, $key->{y}, $key->{d}, $curve); |
494 | 495 | } |
495 | 496 | } |
497 | croak "FATAL: unexpected key hash"; | |
496 | 498 | } |
497 | 499 | |
498 | 500 | my $data; |
567 | 569 | return $self->_sign($data_hash); |
568 | 570 | } |
569 | 571 | |
572 | sub sign_message_rfc7518 { | |
573 | my ($self, $data, $hash_name) = @_; | |
574 | $hash_name ||= 'SHA1'; | |
575 | my $data_hash = digest_data($hash_name, $data); | |
576 | return $self->_sign_rfc7518($data_hash); | |
577 | } | |
578 | ||
570 | 579 | sub verify_message { |
571 | 580 | my ($self, $sig, $data, $hash_name) = @_; |
572 | 581 | $hash_name ||= 'SHA1'; |
574 | 583 | return $self->_verify($sig, $data_hash); |
575 | 584 | } |
576 | 585 | |
586 | sub verify_message_rfc7518 { | |
587 | my ($self, $sig, $data, $hash_name) = @_; | |
588 | $hash_name ||= 'SHA1'; | |
589 | my $data_hash = digest_data($hash_name, $data); | |
590 | return $self->_verify_rfc7518($sig, $data_hash); | |
591 | } | |
592 | ||
577 | 593 | sub sign_hash { |
578 | 594 | my ($self, $data_hash) = @_; |
579 | 595 | return $self->_sign($data_hash); |
582 | 598 | sub verify_hash { |
583 | 599 | my ($self, $sig, $data_hash) = @_; |
584 | 600 | return $self->_verify($sig, $data_hash); |
601 | } | |
602 | ||
603 | sub curve2hash { | |
604 | my $self = shift; | |
605 | my $kh = $self->key2hash; | |
606 | return { | |
607 | prime => $kh->{curve_prime}, | |
608 | A => $kh->{curve_A}, | |
609 | B => $kh->{curve_B}, | |
610 | Gx => $kh->{curve_Gx}, | |
611 | Gy => $kh->{curve_Gy}, | |
612 | cofactor => $kh->{curve_cofactor}, | |
613 | order => $kh->{curve_order} | |
614 | }; | |
585 | 615 | } |
586 | 616 | |
587 | 617 | ### FUNCTIONS |
1035 | 1065 | |
1036 | 1066 | #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest |
1037 | 1067 | |
1068 | =head2 sign_message_rfc7518 | |
1069 | ||
1070 | Same as L<sign_message|/sign_message> only the signature format is as defined by L<https://tools.ietf.org/html/rfc7518> | |
1071 | (JWA - JSON Web Algorithms). | |
1072 | ||
1038 | 1073 | =head2 verify_message |
1039 | 1074 | |
1040 | 1075 | my $pk = Crypt::PK::ECC->new($pub_key_filename); |
1043 | 1078 | my $valid = $pub->verify_message($signature, $message, $hash_name); |
1044 | 1079 | |
1045 | 1080 | #NOTE: $hash_name can be 'SHA1' (DEFAULT), 'SHA256' or any other hash supported by Crypt::Digest |
1081 | ||
1082 | =head2 verify_message_rfc7518 | |
1083 | ||
1084 | Same as L<verify_message|/verify_message> only the signature format is as defined by L<https://tools.ietf.org/html/rfc7518> | |
1085 | (JWA - JSON Web Algorithms). | |
1046 | 1086 | |
1047 | 1087 | =head2 sign_hash |
1048 | 1088 | |
1104 | 1144 | pub_y => "895D57E992D0A15F88D6680B27B701F615FCDC0F", |
1105 | 1145 | } |
1106 | 1146 | |
1147 | =head2 curve2hash | |
1148 | ||
1149 | my $crv = $pk->curve2hash; | |
1150 | ||
1151 | # returns a hash that can be passed to: $pk->generate_key($crv) | |
1152 | { | |
1153 | A => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", | |
1154 | B => "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", | |
1155 | cofactor => 1, | |
1156 | Gx => "4A96B5688EF573284664698968C38BB913CBFC82", | |
1157 | Gy => "23A628553168947D59DCC912042351377AC5FB32", | |
1158 | order => "0100000000000000000001F4C8F927AED3CA752257", | |
1159 | prime => "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", | |
1160 | } | |
1161 | ||
1107 | 1162 | =head1 FUNCTIONS |
1108 | 1163 | |
1109 | 1164 | =head2 ecc_encrypt |
2 | 2 | use strict; |
3 | 3 | use warnings ; |
4 | 4 | |
5 | our $VERSION = '0.023_2'; | |
5 | our $VERSION = '0.024'; | |
6 | 6 | |
7 | 7 | require XSLoader; |
8 | 8 | XSLoader::load('CryptX', $VERSION); |
271 | 271 | |
272 | 272 | SV * |
273 | 273 | _sign(Crypt::PK::ECC self, SV * data) |
274 | ALIAS: | |
275 | _sign_rfc7518 = 1 | |
274 | 276 | CODE: |
275 | 277 | { |
276 | 278 | int rv; |
281 | 283 | |
282 | 284 | data_ptr = (unsigned char *)SvPVbyte(data, data_len); |
283 | 285 | |
284 | rv = ecc_sign_hash(data_ptr, (unsigned long)data_len, buffer, &buffer_len, | |
285 | &self->yarrow_prng_state, self->yarrow_prng_index, | |
286 | &self->key); | |
286 | if (ix == 1) { | |
287 | rv = ecc_sign_hash_rfc7518(data_ptr, (unsigned long)data_len, buffer, &buffer_len, | |
288 | &self->yarrow_prng_state, self->yarrow_prng_index, | |
289 | &self->key); | |
290 | } | |
291 | else { | |
292 | rv = ecc_sign_hash(data_ptr, (unsigned long)data_len, buffer, &buffer_len, | |
293 | &self->yarrow_prng_state, self->yarrow_prng_index, | |
294 | &self->key); | |
295 | } | |
287 | 296 | if (rv != CRYPT_OK) croak("FATAL: ecc_sign_hash_ex failed: %s", error_to_string(rv)); |
288 | 297 | RETVAL = newSVpvn((char*)buffer, buffer_len); |
289 | 298 | } |
292 | 301 | |
293 | 302 | int |
294 | 303 | _verify(Crypt::PK::ECC self, SV * sig, SV * data) |
304 | ALIAS: | |
305 | _verify_rfc7518 = 1 | |
295 | 306 | CODE: |
296 | 307 | { |
297 | 308 | int rv, stat; |
304 | 315 | sig_ptr = (unsigned char *)SvPVbyte(sig, sig_len); |
305 | 316 | |
306 | 317 | RETVAL = 1; |
307 | rv = ecc_verify_hash(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key); | |
318 | if (ix == 1) { | |
319 | rv = ecc_verify_hash_rfc7518(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key); | |
320 | } | |
321 | else { | |
322 | rv = ecc_verify_hash(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key); | |
323 | } | |
308 | 324 | if (rv != CRYPT_OK || stat != 1) RETVAL = 0; |
309 | 325 | } |
310 | 326 | OUTPUT: |
50 | 50 | return CRYPT_INVALID_ARG; |
51 | 51 | } |
52 | 52 | |
53 | /* XXX FIXME names can be different in some situations | |
53 | 54 | if (XSTRCMP(private_key->dp->name, public_key->dp->name) != 0) { |
54 | 55 | return CRYPT_PK_TYPE_MISMATCH; |
55 | 56 | } |
56 | ||
57 | */ | |
57 | 58 | /* make new point */ |
58 | 59 | result = ltc_ecc_new_point(); |
59 | 60 | if (result == NULL) { |
20 | 20 | |
21 | 21 | #ifdef LTC_MECC |
22 | 22 | |
23 | /** | |
24 | Sign a message digest | |
25 | @param in The message digest to sign | |
26 | @param inlen The length of the digest | |
27 | @param out [out] The destination for the signature | |
28 | @param outlen [in/out] The max size and resulting size of the signature | |
29 | @param prng An active PRNG state | |
30 | @param wprng The index of the PRNG you wish to use | |
31 | @param key A private ECC key | |
32 | @return CRYPT_OK if successful | |
33 | */ | |
34 | int ecc_sign_hash(const unsigned char *in, unsigned long inlen, | |
35 | unsigned char *out, unsigned long *outlen, | |
36 | prng_state *prng, int wprng, ecc_key *key) | |
23 | int ecc_sign_hash_ex(const unsigned char *in, unsigned long inlen, | |
24 | unsigned char *out, unsigned long *outlen, | |
25 | prng_state *prng, int wprng, ecc_key *key, int sigformat) | |
37 | 26 | { |
38 | 27 | ecc_key pubkey; |
39 | 28 | void *r, *s, *e, *p; |
110 | 99 | } |
111 | 100 | } |
112 | 101 | |
113 | /* store as SEQUENCE { r, s -- integer } */ | |
114 | err = der_encode_sequence_multi(out, outlen, | |
115 | LTC_ASN1_INTEGER, 1UL, r, | |
116 | LTC_ASN1_INTEGER, 1UL, s, | |
117 | LTC_ASN1_EOL, 0UL, NULL); | |
102 | if (sigformat == 1) { | |
103 | /* RFC7518 format */ | |
104 | if (*outlen < 2*pbytes) { err = CRYPT_MEM; goto errnokey; } | |
105 | zeromem(out, 2*pbytes); | |
106 | i = mp_unsigned_bin_size(r); | |
107 | if ((err = mp_to_unsigned_bin(r, out + (pbytes - i))) != CRYPT_OK) goto errnokey; | |
108 | i = mp_unsigned_bin_size(s); | |
109 | if ((err = mp_to_unsigned_bin(s, out + (2*pbytes - i))) != CRYPT_OK) goto errnokey; | |
110 | *outlen = 2*pbytes; | |
111 | err = CRYPT_OK; | |
112 | } | |
113 | else { | |
114 | /* store as ASN.1 SEQUENCE { r, s -- integer } */ | |
115 | err = der_encode_sequence_multi(out, outlen, | |
116 | LTC_ASN1_INTEGER, 1UL, r, | |
117 | LTC_ASN1_INTEGER, 1UL, s, | |
118 | LTC_ASN1_EOL, 0UL, NULL); | |
119 | } | |
118 | 120 | goto errnokey; |
119 | 121 | error: |
120 | 122 | ecc_free(&pubkey); |
123 | 125 | return err; |
124 | 126 | } |
125 | 127 | |
128 | /** | |
129 | Sign a message digest | |
130 | @param in The message digest to sign | |
131 | @param inlen The length of the digest | |
132 | @param out [out] The destination for the signature | |
133 | @param outlen [in/out] The max size and resulting size of the signature | |
134 | @param prng An active PRNG state | |
135 | @param wprng The index of the PRNG you wish to use | |
136 | @param key A private ECC key | |
137 | @return CRYPT_OK if successful | |
138 | */ | |
139 | int ecc_sign_hash(const unsigned char *in, unsigned long inlen, | |
140 | unsigned char *out, unsigned long *outlen, | |
141 | prng_state *prng, int wprng, ecc_key *key) | |
142 | { | |
143 | return ecc_sign_hash_ex(in, inlen, out, outlen, prng, wprng, key, 0); | |
144 | } | |
145 | ||
146 | /** | |
147 | Sign a message digest in RFC7518 format | |
148 | @param in The message digest to sign | |
149 | @param inlen The length of the digest | |
150 | @param out [out] The destination for the signature | |
151 | @param outlen [in/out] The max size and resulting size of the signature | |
152 | @param prng An active PRNG state | |
153 | @param wprng The index of the PRNG you wish to use | |
154 | @param key A private ECC key | |
155 | @return CRYPT_OK if successful | |
156 | */ | |
157 | int ecc_sign_hash_rfc7518(const unsigned char *in, unsigned long inlen, | |
158 | unsigned char *out, unsigned long *outlen, | |
159 | prng_state *prng, int wprng, ecc_key *key) | |
160 | { | |
161 | return ecc_sign_hash_ex(in, inlen, out, outlen, prng, wprng, key, 1); | |
162 | } | |
163 | ||
126 | 164 | #endif |
127 | 165 | /* $Source$ */ |
128 | 166 | /* $Revision$ */ |
29 | 29 | * v = X_x1 mod n |
30 | 30 | * accept if v == r |
31 | 31 | */ |
32 | ||
33 | int ecc_verify_hash_ex(const unsigned char *sig, unsigned long siglen, | |
34 | const unsigned char *hash, unsigned long hashlen, | |
35 | int *stat, ecc_key *key, int sigformat) | |
36 | { | |
37 | ecc_point *mG, *mQ; | |
38 | void *r, *s, *v, *w, *u1, *u2, *e, *p, *m, *a; | |
39 | void *mp; | |
40 | int err; | |
41 | unsigned long pbits, pbytes, i, shift_right; | |
42 | unsigned char ch, buf[MAXBLOCKSIZE]; | |
43 | ||
44 | LTC_ARGCHK(sig != NULL); | |
45 | LTC_ARGCHK(hash != NULL); | |
46 | LTC_ARGCHK(stat != NULL); | |
47 | LTC_ARGCHK(key != NULL); | |
48 | ||
49 | /* default to invalid signature */ | |
50 | *stat = 0; | |
51 | mp = NULL; | |
52 | ||
53 | /* is the IDX valid ? */ | |
54 | if (ltc_ecc_is_valid_idx(key->idx) != 1) { | |
55 | return CRYPT_PK_INVALID_TYPE; | |
56 | } | |
57 | ||
58 | /* allocate ints */ | |
59 | if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, &a, NULL)) != CRYPT_OK) { | |
60 | return CRYPT_MEM; | |
61 | } | |
62 | ||
63 | /* allocate points */ | |
64 | mG = ltc_ecc_new_point(); | |
65 | mQ = ltc_ecc_new_point(); | |
66 | if (mQ == NULL || mG == NULL) { | |
67 | err = CRYPT_MEM; | |
68 | goto error; | |
69 | } | |
70 | ||
71 | if (sigformat == 1) { | |
72 | /* RFC7518 format */ | |
73 | if ((siglen % 2) == 1) { | |
74 | err = CRYPT_INVALID_PACKET; | |
75 | goto error; | |
76 | } | |
77 | i = siglen / 2; | |
78 | if ((err = mp_read_unsigned_bin(r, (unsigned char *)sig, i)) != CRYPT_OK) goto error; | |
79 | if ((err = mp_read_unsigned_bin(s, (unsigned char *)sig+i, i)) != CRYPT_OK) goto error; | |
80 | } | |
81 | else { | |
82 | /* ASN.1 format */ | |
83 | if ((err = der_decode_sequence_multi(sig, siglen, | |
84 | LTC_ASN1_INTEGER, 1UL, r, | |
85 | LTC_ASN1_INTEGER, 1UL, s, | |
86 | LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { | |
87 | goto error; | |
88 | } | |
89 | } | |
90 | ||
91 | /* get the order */ | |
92 | if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto error; } | |
93 | ||
94 | /* get the modulus */ | |
95 | if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto error; } | |
96 | ||
97 | /* get the a */ | |
98 | if ((err = mp_read_radix(a, (char *)key->dp->A, 16)) != CRYPT_OK) { goto error; } | |
99 | ||
100 | /* check for zero */ | |
101 | if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) { | |
102 | err = CRYPT_INVALID_PACKET; | |
103 | goto error; | |
104 | } | |
105 | ||
106 | /* read hash - truncate if needed */ | |
107 | pbits = mp_count_bits(p); | |
108 | pbytes = (pbits+7) >> 3; | |
109 | if (pbits > hashlen*8) { | |
110 | if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error; } | |
111 | } | |
112 | else if (pbits % 8 == 0) { | |
113 | if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK) { goto error; } | |
114 | } | |
115 | else { | |
116 | shift_right = 8 - pbits % 8; | |
117 | for (i=0, ch=0; i<pbytes; i++) { | |
118 | buf[i] = ch; | |
119 | ch = (hash[i] << (8-shift_right)); | |
120 | buf[i] = buf[i] ^ (hash[i] >> shift_right); | |
121 | } | |
122 | if ((err = mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK) { goto error; } | |
123 | } | |
124 | ||
125 | /* w = s^-1 mod n */ | |
126 | if ((err = mp_invmod(s, p, w)) != CRYPT_OK) { goto error; } | |
127 | ||
128 | /* u1 = ew */ | |
129 | if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; } | |
130 | ||
131 | /* u2 = rw */ | |
132 | if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; } | |
133 | ||
134 | /* find mG and mQ */ | |
135 | if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto error; } | |
136 | if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto error; } | |
137 | if ((err = mp_set(mG->z, 1)) != CRYPT_OK) { goto error; } | |
138 | ||
139 | if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK) { goto error; } | |
140 | if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK) { goto error; } | |
141 | if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK) { goto error; } | |
142 | ||
143 | /* compute u1*mG + u2*mQ = mG */ | |
144 | if (ltc_mp.ecc_mul2add == NULL) { | |
145 | if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK) { goto error; } | |
146 | if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK) { goto error; } | |
147 | ||
148 | /* find the montgomery mp */ | |
149 | if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } | |
150 | ||
151 | /* add them */ | |
152 | if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, a, m, mp)) != CRYPT_OK) { goto error; } | |
153 | ||
154 | /* reduce */ | |
155 | if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; } | |
156 | } else { | |
157 | /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ | |
158 | if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, a, m)) != CRYPT_OK) { goto error; } | |
159 | } | |
160 | ||
161 | /* v = X_x1 mod n */ | |
162 | if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; } | |
163 | ||
164 | /* does v == r */ | |
165 | if (mp_cmp(v, r) == LTC_MP_EQ) { | |
166 | *stat = 1; | |
167 | } | |
168 | ||
169 | /* clear up and return */ | |
170 | err = CRYPT_OK; | |
171 | error: | |
172 | ltc_ecc_del_point(mG); | |
173 | ltc_ecc_del_point(mQ); | |
174 | mp_clear_multi(r, s, v, w, u1, u2, p, e, m, a, NULL); | |
175 | if (mp != NULL) { | |
176 | mp_montgomery_free(mp); | |
177 | } | |
178 | return err; | |
179 | } | |
32 | 180 | |
33 | 181 | /** |
34 | 182 | Verify an ECC signature |
44 | 192 | const unsigned char *hash, unsigned long hashlen, |
45 | 193 | int *stat, ecc_key *key) |
46 | 194 | { |
47 | ecc_point *mG, *mQ; | |
48 | void *r, *s, *v, *w, *u1, *u2, *e, *p, *m, *a; | |
49 | void *mp; | |
50 | int err; | |
51 | unsigned long pbits, pbytes, i, shift_right; | |
52 | unsigned char ch, buf[MAXBLOCKSIZE]; | |
53 | ||
54 | LTC_ARGCHK(sig != NULL); | |
55 | LTC_ARGCHK(hash != NULL); | |
56 | LTC_ARGCHK(stat != NULL); | |
57 | LTC_ARGCHK(key != NULL); | |
58 | ||
59 | /* default to invalid signature */ | |
60 | *stat = 0; | |
61 | mp = NULL; | |
62 | ||
63 | /* is the IDX valid ? */ | |
64 | if (ltc_ecc_is_valid_idx(key->idx) != 1) { | |
65 | return CRYPT_PK_INVALID_TYPE; | |
66 | } | |
67 | ||
68 | /* allocate ints */ | |
69 | if ((err = mp_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, &a, NULL)) != CRYPT_OK) { | |
70 | return CRYPT_MEM; | |
71 | } | |
72 | ||
73 | /* allocate points */ | |
74 | mG = ltc_ecc_new_point(); | |
75 | mQ = ltc_ecc_new_point(); | |
76 | if (mQ == NULL || mG == NULL) { | |
77 | err = CRYPT_MEM; | |
78 | goto error; | |
79 | } | |
80 | ||
81 | /* parse header */ | |
82 | if ((err = der_decode_sequence_multi(sig, siglen, | |
83 | LTC_ASN1_INTEGER, 1UL, r, | |
84 | LTC_ASN1_INTEGER, 1UL, s, | |
85 | LTC_ASN1_EOL, 0UL, NULL)) != CRYPT_OK) { | |
86 | goto error; | |
87 | } | |
88 | ||
89 | /* get the order */ | |
90 | if ((err = mp_read_radix(p, (char *)key->dp->order, 16)) != CRYPT_OK) { goto error; } | |
91 | ||
92 | /* get the modulus */ | |
93 | if ((err = mp_read_radix(m, (char *)key->dp->prime, 16)) != CRYPT_OK) { goto error; } | |
94 | ||
95 | /* get the a */ | |
96 | if ((err = mp_read_radix(a, (char *)key->dp->A, 16)) != CRYPT_OK) { goto error; } | |
97 | ||
98 | /* check for zero */ | |
99 | if (mp_iszero(r) || mp_iszero(s) || mp_cmp(r, p) != LTC_MP_LT || mp_cmp(s, p) != LTC_MP_LT) { | |
100 | err = CRYPT_INVALID_PACKET; | |
101 | goto error; | |
102 | } | |
103 | ||
104 | /* read hash - truncate if needed */ | |
105 | pbits = mp_count_bits(p); | |
106 | pbytes = (pbits+7) >> 3; | |
107 | if (pbits > hashlen*8) { | |
108 | if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, hashlen)) != CRYPT_OK) { goto error; } | |
109 | } | |
110 | else if (pbits % 8 == 0) { | |
111 | if ((err = mp_read_unsigned_bin(e, (unsigned char *)hash, pbytes)) != CRYPT_OK) { goto error; } | |
112 | } | |
113 | else { | |
114 | shift_right = 8 - pbits % 8; | |
115 | for (i=0, ch=0; i<pbytes; i++) { | |
116 | buf[i] = ch; | |
117 | ch = (hash[i] << (8-shift_right)); | |
118 | buf[i] = buf[i] ^ (hash[i] >> shift_right); | |
119 | } | |
120 | if ((err = mp_read_unsigned_bin(e, (unsigned char *)buf, pbytes)) != CRYPT_OK) { goto error; } | |
121 | } | |
122 | ||
123 | /* w = s^-1 mod n */ | |
124 | if ((err = mp_invmod(s, p, w)) != CRYPT_OK) { goto error; } | |
125 | ||
126 | /* u1 = ew */ | |
127 | if ((err = mp_mulmod(e, w, p, u1)) != CRYPT_OK) { goto error; } | |
128 | ||
129 | /* u2 = rw */ | |
130 | if ((err = mp_mulmod(r, w, p, u2)) != CRYPT_OK) { goto error; } | |
131 | ||
132 | /* find mG and mQ */ | |
133 | if ((err = mp_read_radix(mG->x, (char *)key->dp->Gx, 16)) != CRYPT_OK) { goto error; } | |
134 | if ((err = mp_read_radix(mG->y, (char *)key->dp->Gy, 16)) != CRYPT_OK) { goto error; } | |
135 | if ((err = mp_set(mG->z, 1)) != CRYPT_OK) { goto error; } | |
136 | ||
137 | if ((err = mp_copy(key->pubkey.x, mQ->x)) != CRYPT_OK) { goto error; } | |
138 | if ((err = mp_copy(key->pubkey.y, mQ->y)) != CRYPT_OK) { goto error; } | |
139 | if ((err = mp_copy(key->pubkey.z, mQ->z)) != CRYPT_OK) { goto error; } | |
140 | ||
141 | /* compute u1*mG + u2*mQ = mG */ | |
142 | if (ltc_mp.ecc_mul2add == NULL) { | |
143 | if ((err = ltc_mp.ecc_ptmul(u1, mG, mG, a, m, 0)) != CRYPT_OK) { goto error; } | |
144 | if ((err = ltc_mp.ecc_ptmul(u2, mQ, mQ, a, m, 0)) != CRYPT_OK) { goto error; } | |
145 | ||
146 | /* find the montgomery mp */ | |
147 | if ((err = mp_montgomery_setup(m, &mp)) != CRYPT_OK) { goto error; } | |
148 | ||
149 | /* add them */ | |
150 | if ((err = ltc_mp.ecc_ptadd(mQ, mG, mG, a, m, mp)) != CRYPT_OK) { goto error; } | |
151 | ||
152 | /* reduce */ | |
153 | if ((err = ltc_mp.ecc_map(mG, m, mp)) != CRYPT_OK) { goto error; } | |
154 | } else { | |
155 | /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ | |
156 | if ((err = ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, a, m)) != CRYPT_OK) { goto error; } | |
157 | } | |
158 | ||
159 | /* v = X_x1 mod n */ | |
160 | if ((err = mp_mod(mG->x, p, v)) != CRYPT_OK) { goto error; } | |
161 | ||
162 | /* does v == r */ | |
163 | if (mp_cmp(v, r) == LTC_MP_EQ) { | |
164 | *stat = 1; | |
165 | } | |
166 | ||
167 | /* clear up and return */ | |
168 | err = CRYPT_OK; | |
169 | error: | |
170 | ltc_ecc_del_point(mG); | |
171 | ltc_ecc_del_point(mQ); | |
172 | mp_clear_multi(r, s, v, w, u1, u2, p, e, m, a, NULL); | |
173 | if (mp != NULL) { | |
174 | mp_montgomery_free(mp); | |
175 | } | |
176 | return err; | |
195 | return ecc_verify_hash_ex(sig, siglen, hash, hashlen, stat, key, 0); | |
196 | } | |
197 | ||
198 | /** | |
199 | Verify an ECC signature in RFC7518 format | |
200 | @param sig The signature to verify | |
201 | @param siglen The length of the signature (octets) | |
202 | @param hash The hash (message digest) that was signed | |
203 | @param hashlen The length of the hash (octets) | |
204 | @param stat Result of signature, 1==valid, 0==invalid | |
205 | @param key The corresponding public ECC key | |
206 | @return CRYPT_OK if successful (even if the signature is not valid) | |
207 | */ | |
208 | int ecc_verify_hash_rfc7518(const unsigned char *sig, unsigned long siglen, | |
209 | const unsigned char *hash, unsigned long hashlen, | |
210 | int *stat, ecc_key *key) | |
211 | { | |
212 | return ecc_verify_hash_ex(sig, siglen, hash, hashlen, stat, key, 1); | |
177 | 213 | } |
178 | 214 | |
179 | 215 | #endif |
11 | 11 | ok($k->is_private, 'is_private cryptx_priv_ecc1.der'); |
12 | 12 | is($k->size, 32, 'size'); |
13 | 13 | is(uc($k->key2hash->{pub_x}), 'C068B754877A4AB328A569BAC6D464A81B17E527D2D652572ABB11BDA3572D50', 'key2hash'); |
14 | is(uc($k->curve2hash->{prime}), 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F', 'curve2hash'); | |
14 | 15 | |
15 | 16 | $k = Crypt::PK::ECC->new('t/data/cryptx_priv_ecc2.der'); |
16 | 17 | ok($k, 'load cryptx_priv_ecc2.der'); |
71 | 72 | ok(length $sig > 60, 'sign_message ' . length($sig)); |
72 | 73 | ok($pu1->verify_message($sig, "message"), 'verify_message'); |
73 | 74 | |
75 | my $sig_rfc7518 = $pr1->sign_message_rfc7518("message"); | |
76 | ok(length $sig_rfc7518 > 60, 'sign_message_rfc7518 ' . length($sig_rfc7518)); | |
77 | ok($pu1->verify_message_rfc7518($sig_rfc7518, "message"), 'verify_message_rfc7518'); | |
78 | ||
74 | 79 | my $hash = pack("H*","04624fae618e9ad0c5e479f62e1420c71fff34dd"); |
75 | 80 | $sig = $pr1->sign_hash($hash, 'SHA1'); |
76 | 81 | ok(length $sig > 60, 'sign_hash ' . length($sig)); |
121 | 126 | ok($k->is_private, "is_private $priv"); |
122 | 127 | is($k->size, 32, "size $priv"); |
123 | 128 | is(uc($k->key2hash->{pub_x}), 'A01532A3C0900053DE60FBEFEFCCA58793301598D308B41E6F4E364E388C2711', "key2hash $priv"); |
129 | is(uc($k->curve2hash->{prime}), 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF', "curve2hash $priv"); | |
124 | 130 | } |
125 | 131 | |
126 | 132 | for my $pub (qw/openssl_ec-short.pub.pem openssl_ec-short.pub.der/) { |