File Coverage

inc/CryptX_PK_ECC.xs.inc
Criterion Covered Total %
statement 285 308 92.5
branch 149 220 67.7
condition n/a
subroutine n/a
pod n/a
total 434 528 82.2


line stmt bran cond sub pod time code
1             MODULE = CryptX PACKAGE = Crypt::PK::ECC
2              
3             PROTOTYPES: DISABLE
4              
5             Crypt::PK::ECC
6             _new(Class)
7             CODE:
8             {
9             int rv;
10 285           Newz(0, RETVAL, 1, struct ecc_struct);
11 285 50         if (!RETVAL) croak("FATAL: Newz failed");
12 285           RETVAL->pindex = find_prng("chacha20");
13 285           RETVAL->last_pid = (IV)PerlProc_getpid();
14 285           RETVAL->key.type = -1;
15 285 50         if (RETVAL->pindex == -1) {
16 0           zeromem(RETVAL, sizeof(*RETVAL));
17 0           Safefree(RETVAL);
18 0           croak("FATAL: find_prng('chacha20') failed");
19             }
20 285           rv = rng_make_prng(320, RETVAL->pindex, &RETVAL->pstate, NULL); /* 320bits = 40bytes */
21 285 50         if (rv != CRYPT_OK) {
22 0           zeromem(RETVAL, sizeof(*RETVAL));
23 0           Safefree(RETVAL);
24 0           croak("FATAL: rng_make_prng failed: %s", error_to_string(rv));
25             }
26             }
27             OUTPUT:
28             RETVAL
29              
30             void
31             generate_key(Crypt::PK::ECC self, SV *curve)
32             PPCODE:
33             {
34             int rv;
35 12           cryptx_internal_pk_prng_reseed(&self->pstate, self->pindex, &self->last_pid);
36             /* setup dp structure */
37 12           rv = cryptx_internal_ecc_set_curve_from_SV(&self->key, curve); /* croaks on error */
38 12 50         if (rv != CRYPT_OK) croak("FATAL: ecc_set_curve failed: %s", error_to_string(rv));
39             /* gen the key */
40 12           rv = ecc_generate_key(&self->pstate, self->pindex, &self->key);
41 12 50         if (rv != CRYPT_OK) croak("FATAL: ecc_generate_key failed: %s", error_to_string(rv));
42 12 50         XPUSHs(ST(0)); /* return self */
43             }
44              
45             void
46             _import(Crypt::PK::ECC self, SV * key_data)
47             PPCODE:
48             {
49             int rv;
50 44           unsigned char *data=NULL;
51 44           STRLEN data_len=0;
52              
53 44           data = (unsigned char *)SvPVbyte(key_data, data_len);
54 44 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
55 44           rv = ecc_import_openssl(data, (unsigned long)data_len, &self->key);
56 44 100         if (rv != CRYPT_OK) croak("FATAL: ecc_import_openssl failed: %s", error_to_string(rv));
57 34 50         XPUSHs(ST(0)); /* return self */
58             }
59              
60             void
61             _import_old(Crypt::PK::ECC self, SV * key_data)
62             PPCODE:
63             {
64             int rv;
65 19           unsigned char *data=NULL;
66 19           STRLEN data_len=0;
67              
68 19           data = (unsigned char *)SvPVbyte(key_data, data_len);
69 19 50         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
70 19           rv = ecc_import(data, (unsigned long)data_len, &self->key);
71 19 100         if (rv != CRYPT_OK) croak("FATAL: ecc_import failed: %s", error_to_string(rv));
72 8 50         XPUSHs(ST(0)); /* return self */
73             }
74              
75             void
76             _import_pkcs8(Crypt::PK::ECC self, SV * key_data, SV * passwd)
77             PPCODE:
78             {
79             int rv;
80 6           unsigned char *data = NULL;
81 6           STRLEN data_len = 0;
82 6           password_ctx pw_ctx = { cryptx_internal_password_cb_getpw, cryptx_internal_password_cb_free, passwd };
83              
84 6           data = (unsigned char *)SvPVbyte(key_data, data_len);
85 6 50         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
86 6 100         if (SvOK(passwd)) {
87 2           rv = ecc_import_pkcs8(data, (unsigned long)data_len, &pw_ctx, &self->key);
88             }
89             else {
90 4           rv = ecc_import_pkcs8(data, (unsigned long)data_len, NULL, &self->key);
91             }
92 6 100         if (rv != CRYPT_OK) croak("FATAL: ecc_import_pkcs8 failed: %s", error_to_string(rv));
93 5 50         XPUSHs(ST(0)); /* return self */
94             }
95              
96             void
97             _import_pem(Crypt::PK::ECC self, SV * key_data, SV * passwd)
98             PPCODE:
99             {
100             int rv;
101 65           unsigned char *data = NULL;
102 65           STRLEN data_len = 0;
103 65           password_ctx pw_ctx = { cryptx_internal_password_cb_getpw, cryptx_internal_password_cb_free, passwd };
104             ltc_pka_key key_from_pem;
105              
106 65           data = (unsigned char *)SvPVbyte(key_data, data_len);
107 65 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
108 65 100         if (SvOK(passwd)) {
109 17           rv = pem_decode_pkcs(data, (unsigned long)data_len, &key_from_pem, &pw_ctx);
110             }
111             else {
112 48           rv = pem_decode_pkcs(data, (unsigned long)data_len, &key_from_pem, NULL);
113             }
114 65 100         if (rv != CRYPT_OK) croak("FATAL: pem_decode_pkcs failed: %s", error_to_string(rv));
115 56 50         if (key_from_pem.id != LTC_PKA_EC) croak("FATAL: pem_decode_pkcs decoded non-ECC key");
116 56           self->key = key_from_pem.u.ecc;
117 56 50         XPUSHs(ST(0)); /* return self */
118             }
119              
120             void
121             _import_openssh(Crypt::PK::ECC self, SV * key_data, SV * passwd)
122             PPCODE:
123             {
124             int rv;
125 9           unsigned char *data = NULL;
126 9           STRLEN data_len = 0;
127 9           password_ctx pw_ctx = { cryptx_internal_password_cb_getpw, cryptx_internal_password_cb_free, passwd };
128             ltc_pka_key key_from_pem;
129              
130 9           data = (unsigned char *)SvPVbyte(key_data, data_len);
131 9 50         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
132 9 100         if (SvOK(passwd)) {
133 3           rv = pem_decode_openssh(data, (unsigned long)data_len, &key_from_pem, &pw_ctx);
134             }
135             else {
136 6           rv = pem_decode_openssh(data, (unsigned long)data_len, &key_from_pem, NULL);
137             }
138 9 50         if (rv != CRYPT_OK) croak("FATAL: pem_decode_openssh failed: %s", error_to_string(rv));
139 9 50         if (key_from_pem.id != LTC_PKA_EC) croak("FATAL: pem_decode_openssh decoded non-ECC key");
140 9           self->key = key_from_pem.u.ecc;
141 9 50         XPUSHs(ST(0)); /* return self */
142             }
143              
144             void
145             _import_x509(Crypt::PK::ECC self, SV * key_data)
146             PPCODE:
147             {
148             int rv;
149 1           unsigned char *data=NULL;
150 1           STRLEN data_len=0;
151              
152 1           data = (unsigned char *)SvPVbyte(key_data, data_len);
153 1 50         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
154 1           rv = ecc_import_x509(data, (unsigned long)data_len, &self->key);
155 1 50         if (rv != CRYPT_OK) croak("FATAL: ecc_import_x509 failed: %s", error_to_string(rv));
156 0 0         XPUSHs(ST(0)); /* return self */
157             }
158              
159             void
160             import_key_raw(Crypt::PK::ECC self, SV * key_data, SV * curve)
161             PPCODE:
162             {
163             int rv, type;
164 187           unsigned char *data=NULL;
165 187           STRLEN data_len=0;
166              
167 187           data = (unsigned char *)SvPVbyte(key_data, data_len);
168 187 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
169             /* setup dp structure */
170 187           rv = cryptx_internal_ecc_set_curve_from_SV(&self->key, curve); /* croaks on error */
171 187 50         if (rv != CRYPT_OK) croak("FATAL: ecc_set_curve failed: %s", error_to_string(rv));
172             /* import key */
173 187           type = (data_len == (STRLEN)ecc_get_size(&self->key)) ? PK_PRIVATE : PK_PUBLIC;
174 187           rv = ecc_set_key(data, (unsigned long)data_len, type, &self->key);
175 187 50         if (rv != CRYPT_OK) croak("FATAL: ecc_set_key failed: %s", error_to_string(rv));
176 187 50         XPUSHs(ST(0)); /* return self */
177             }
178              
179             int
180             is_private(Crypt::PK::ECC self)
181             CODE:
182 80 50         if (self->key.type == -1) XSRETURN_UNDEF;
183 80 100         RETVAL = (self->key.type == PK_PRIVATE) ? 1 : 0;
184             OUTPUT:
185             RETVAL
186              
187             int
188             size(Crypt::PK::ECC self)
189             CODE:
190 5 50         if (self->key.type == -1) XSRETURN_UNDEF;
191 5           RETVAL = ecc_get_size(&self->key);
192             OUTPUT:
193             RETVAL
194              
195             SV*
196             key2hash(Crypt::PK::ECC self)
197             PREINIT:
198             HV *rv_hash;
199             size_t siz;
200             long esize;
201             char buf[20001];
202             SV **not_used;
203             CODE:
204 45 50         if (self->key.type == -1) XSRETURN_UNDEF;
205 45           esize = ecc_get_size(&self->key);
206 45           rv_hash = newHV();
207             /* k */
208 45 50         siz = (self->key.k) ? mp_ubin_size(self->key.k) : 0;
209 45 50         if (siz>10000) {
210 0           croak("FATAL: key2hash failed - 'k' too big number");
211             }
212 45 100         if (siz>0) {
213 32           cryptx_internal_mp2hex_with_leading_zero(self->key.k, buf, 20000, esize*2);
214 32           not_used = hv_store(rv_hash, "k", 1, newSVpv(buf, strlen(buf)), 0);
215             }
216             else{
217 13           not_used = hv_store(rv_hash, "k", 1, newSVpv("", 0), 0);
218             }
219             /* pub_x */
220 45 50         siz = (self->key.pubkey.x) ? mp_ubin_size(self->key.pubkey.x) : 0;
221 45 50         if (siz>10000) {
222 0           croak("FATAL: key2hash failed - 'pub_x' too big number");
223             }
224 45 50         if (siz>0) {
225 45           cryptx_internal_mp2hex_with_leading_zero(self->key.pubkey.x, buf, 20000, esize*2);
226 45           not_used = hv_store(rv_hash, "pub_x", 5, newSVpv(buf, strlen(buf)), 0);
227             }
228             else{
229 0           not_used = hv_store(rv_hash, "pub_x", 5, newSVpv("", 0), 0);
230             }
231             /* pub_y */
232 45 50         siz = (self->key.pubkey.y) ? mp_ubin_size(self->key.pubkey.y) : 0;
233 45 50         if (siz>10000) {
234 0           croak("FATAL: key2hash failed - 'pub_y' too big number");
235             }
236 45 50         if (siz>0) {
237 45           cryptx_internal_mp2hex_with_leading_zero(self->key.pubkey.y, buf, 20000, esize*2);
238 45           not_used = hv_store(rv_hash, "pub_y", 5, newSVpv(buf, strlen(buf)), 0);
239             }
240             else{
241 0           not_used = hv_store(rv_hash, "pub_y", 5, newSVpv("", 0), 0);
242             }
243             /* curve_... */
244             {
245 45           not_used = hv_store(rv_hash, "curve_cofactor", 14, newSViv(self->key.dp.cofactor), 0);
246 45           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.prime, buf, 20000, 0);
247 45           not_used = hv_store(rv_hash, "curve_prime", 11, newSVpv(buf, strlen(buf)), 0);
248 45           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.A, buf, 20000, 0);
249 45           not_used = hv_store(rv_hash, "curve_A", 7, newSVpv(buf, strlen(buf)), 0);
250 45           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.B, buf, 20000, 0);
251 45           not_used = hv_store(rv_hash, "curve_B", 7, newSVpv(buf, strlen(buf)), 0);
252 45           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.order, buf, 20000, 0);
253 45           not_used = hv_store(rv_hash, "curve_order", 11, newSVpv(buf, strlen(buf)), 0);
254 45           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.base.x, buf, 20000, 0);
255 45           not_used = hv_store(rv_hash, "curve_Gx", 8, newSVpv(buf, strlen(buf)), 0);
256 45           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.base.y, buf, 20000, 0);
257 45           not_used = hv_store(rv_hash, "curve_Gy", 8, newSVpv(buf, strlen(buf)), 0);
258 45           not_used = hv_store(rv_hash, "curve_bytes", 11, newSViv(mp_ubin_size(self->key.dp.prime)), 0);
259 45           not_used = hv_store(rv_hash, "curve_bits", 10, newSViv(mp_count_bits(self->key.dp.prime)), 0);
260              
261 45 100         if (self->key.dp.oidlen > 0) {
262             unsigned long i;
263             HV *h;
264             SV **pref, *cname;
265             char *cname_ptr, *oid_ptr;
266             STRLEN cname_len;
267              
268             /* OID -> "curve_oid" */
269 43           SV *oid = newSVpv("", 0);
270 253 100         for(i = 0; i < self->key.dp.oidlen - 1; i++) sv_catpvf(oid, "%lu.", self->key.dp.oid[i]);
271 43           sv_catpvf(oid, "%lu", self->key.dp.oid[i]);
272 43           oid_ptr = SvPVX(oid);
273 43           not_used = hv_store(rv_hash, "curve_oid", 9, oid, 0);
274              
275             /* curve name -> "curve_name" */
276 43 50         if ((h = get_hv("Crypt::PK::ECC::curve_oid2name", 0)) != NULL) {
277 43           pref = hv_fetch(h, oid_ptr, (U32)strlen(oid_ptr), 0);
278 43 50         if (pref) {
279 43           cname_ptr = SvPV(*pref, cname_len);
280 43           cname = newSVpv(cname_ptr, cname_len);
281 43           cname_ptr = SvPVX(cname);
282 43           not_used = hv_store(rv_hash, "curve_name", 10, cname, 0);
283             }
284             }
285             }
286             }
287             /* size */
288 45           not_used = hv_store(rv_hash, "size", 4, newSViv(esize), 0);
289             /* type */
290 45           not_used = hv_store(rv_hash, "type", 4, newSViv(self->key.type), 0);
291             LTC_UNUSED_PARAM(not_used);
292 45           RETVAL = newRV_noinc((SV*)rv_hash);
293             OUTPUT:
294             RETVAL
295              
296             SV *
297             export_key_der(Crypt::PK::ECC self, char * type)
298             CODE:
299             {
300             int rv;
301             unsigned char out[4096];
302 28           unsigned long int out_len = 4096;
303              
304 28 100         if (self->key.type == -1) croak("FATAL: export_key_der no key");
305 27 100         if (strEQ(type, "private_short")) {
306 5           rv = ecc_export_openssl(out, &out_len, PK_PRIVATE|PK_CURVEOID, &self->key);
307 5 100         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PRIVATE|PK_CURVEOID) failed: %s", error_to_string(rv));
308 4           RETVAL = newSVpvn((char*)out, out_len);
309             }
310 22 50         else if (strEQ(type, "private_compressed")) {
311 0           rv = ecc_export_openssl(out, &out_len, PK_PRIVATE|PK_CURVEOID|PK_COMPRESSED, &self->key);
312 0 0         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PRIVATE|PK_CURVEOID|PK_COMPRESSED) failed: %s", error_to_string(rv));
313 0           RETVAL = newSVpvn((char*)out, out_len);
314             }
315 22 100         else if (strEQ(type, "private")) {
316 10           rv = ecc_export_openssl(out, &out_len, PK_PRIVATE, &self->key);
317 10 50         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PRIVATE) failed: %s", error_to_string(rv));
318 10           RETVAL = newSVpvn((char*)out, out_len);
319             }
320 12 50         else if (strEQ(type, "public_compressed")) {
321 0           rv = ecc_export_openssl(out, &out_len, PK_PUBLIC|PK_CURVEOID|PK_COMPRESSED, &self->key);
322 0 0         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PUBLIC|PK_CURVEOID|PK_COMPRESSED) failed: %s", error_to_string(rv));
323 0           RETVAL = newSVpvn((char*)out, out_len);
324             }
325 12 100         else if (strEQ(type, "public_short")) {
326 3           rv = ecc_export_openssl(out, &out_len, PK_PUBLIC|PK_CURVEOID, &self->key);
327 3 50         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PUBLIC|PK_CURVEOID) failed: %s", error_to_string(rv));
328 3           RETVAL = newSVpvn((char*)out, out_len);
329             }
330 9 50         else if (strEQ(type, "public")) {
331 9           rv = ecc_export_openssl(out, &out_len, PK_PUBLIC, &self->key);
332 9 50         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PUBLIC) failed: %s", error_to_string(rv));
333 9           RETVAL = newSVpvn((char*)out, out_len);
334             }
335             else {
336 0           croak("FATAL: export_key_der invalid type '%s'", type);
337             }
338 26           zeromem(out, sizeof(out));
339             }
340             OUTPUT:
341             RETVAL
342              
343             SV *
344             export_key_raw(Crypt::PK::ECC self, char * type)
345             CODE:
346             {
347             int rv;
348             unsigned char out[4096];
349 428           unsigned long int out_len = sizeof(out);
350              
351 428 50         if (self->key.type == -1) croak("FATAL: export_key_raw no key");
352 428 100         if (strEQ(type, "private")) {
353 60           rv = ecc_get_key(out, &out_len, PK_PRIVATE, &self->key);
354 60 50         if (rv != CRYPT_OK) croak("FATAL: ecc_get_key(private) failed: %s", error_to_string(rv));
355 60           RETVAL = newSVpvn((char*)out, out_len);
356             }
357 368 100         else if (strEQ(type, "public_compressed")) {
358 180           rv = ecc_get_key(out, &out_len, PK_PUBLIC|PK_COMPRESSED, &self->key);
359 180 50         if (rv != CRYPT_OK) croak("FATAL: ecc_get_key(public_compressed) failed: %s", error_to_string(rv));
360 180           RETVAL = newSVpvn((char*)out, out_len);
361             }
362 188 50         else if (strEQ(type, "public")) {
363 188           rv = ecc_get_key(out, &out_len, PK_PUBLIC, &self->key);
364 188 50         if (rv != CRYPT_OK) croak("FATAL: ecc_get_key(public) failed: %s", error_to_string(rv));
365 188           RETVAL = newSVpvn((char*)out, out_len);
366             }
367             else {
368 0           croak("FATAL: export_key_raw invalid type '%s'", type);
369             }
370 428           zeromem(out, sizeof(out));
371             }
372             OUTPUT:
373             RETVAL
374              
375             SV *
376             encrypt(Crypt::PK::ECC self, SV * data, const char * hash_name = "SHA1")
377             CODE:
378             {
379             int rv, hash_id;
380 3           unsigned char *data_ptr=NULL;
381 3           STRLEN data_len=0;
382             unsigned char buffer[1024];
383 3           unsigned long buffer_len = 1024;
384              
385 3           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
386 3           cryptx_internal_pk_prng_reseed(&self->pstate, self->pindex, &self->last_pid);
387              
388 3           hash_id = cryptx_internal_find_hash(hash_name);
389 3 50         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
390 3           rv = ecc_encrypt_key(data_ptr, (unsigned long)data_len, buffer, &buffer_len,
391             &self->pstate, self->pindex,
392 3           hash_id, &self->key);
393 3 50         if (rv != CRYPT_OK) croak("FATAL: ecc_encrypt_key failed: %s", error_to_string(rv));
394 3           RETVAL = newSVpvn((char*)buffer, buffer_len);
395 3           zeromem(buffer, sizeof(buffer));
396             }
397             OUTPUT:
398             RETVAL
399              
400             SV *
401             decrypt(Crypt::PK::ECC self, SV * data)
402             CODE:
403             {
404             int rv;
405 2           unsigned char *data_ptr=NULL;
406 2           STRLEN data_len=0;
407             unsigned char buffer[1024];
408 2           unsigned long buffer_len = 1024;
409              
410 2           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
411              
412 2           rv = ecc_decrypt_key(data_ptr, (unsigned long)data_len, buffer, &buffer_len, &self->key);
413 2 50         if (rv != CRYPT_OK) croak("FATAL: ecc_decrypt_key failed: %s", error_to_string(rv));
414 2           RETVAL = newSVpvn((char*)buffer, buffer_len);
415 2           zeromem(buffer, sizeof(buffer));
416             }
417             OUTPUT:
418             RETVAL
419              
420             SV *
421             sign_hash(Crypt::PK::ECC self, SV * data, const char * hash_name = NULL, const char * hash_rfc6979_name = NULL)
422             ALIAS:
423             sign_hash_rfc7518 = 3
424             sign_message = 1
425             sign_message_rfc7518 = 2
426             sign_hash_eth = 4
427             CODE:
428             {
429             int rv, id, hash_rfc6979_id;
430 32           unsigned char buffer[1024], tmp[MAXBLOCKSIZE], *data_ptr = NULL;
431 32           unsigned long tmp_len = MAXBLOCKSIZE, buffer_len = 1024;
432 32           STRLEN data_len = 0;
433             ltc_ecc_sig_opts sig_opts;
434              
435 32           sig_opts.type = LTC_ECCSIG_ANSIX962;
436 32           sig_opts.prng = &self->pstate;
437 32           sig_opts.wprng = self->pindex;
438 32           sig_opts.enable_recovery_id = 0;
439 32           sig_opts.recovery_id = -1;
440 32           sig_opts.rfc6979_hash_alg = NULL;
441              
442             /* Handle dual signature modes for backward compatibility: if only 2 params passed, treat second as RFC6979 hash */
443 32 100         if ((ix == 0 || ix == 3 || ix == 4) && hash_name != NULL && hash_rfc6979_name == NULL) {
    100          
    100          
    100          
    50          
444 12           hash_rfc6979_name = hash_name;
445             }
446              
447 32           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
448 32           cryptx_internal_pk_prng_reseed(&self->pstate, self->pindex, &self->last_pid);
449 32 100         if (ix == 1 || ix == 2) {
    100          
450             /* for backward compatibility, if hash_name is NULL, use SHA1 */
451 14 100         if (hash_name == NULL) {
452 7           hash_name = "SHA1";
453             }
454 14           id = cryptx_internal_find_hash(hash_name);
455 14 50         if (id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
456 14           rv = hash_memory(id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
457 14 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
458 14           data_ptr = tmp;
459 14           data_len = tmp_len;
460             }
461              
462 32 100         if (hash_rfc6979_name != NULL) {
463             /* deterministic signing */
464 21           hash_rfc6979_id = cryptx_internal_find_hash(hash_rfc6979_name);
465 21 50         if (hash_rfc6979_id == -1) croak("FATAL: find_hash failed for rfc6979 hash '%s'", hash_rfc6979_name);
466 21           sig_opts.rfc6979_hash_alg = hash_descriptor[hash_rfc6979_id].name;
467             }
468              
469 32 100         if (ix == 2 || ix == 3) {
    100          
470             /* rfc7518 */
471 10           sig_opts.type = LTC_ECCSIG_RFC7518;
472             }
473 22 100         else if (ix == 4) {
474             /* eth27 */
475 6           sig_opts.type = LTC_ECCSIG_ETH27;
476             }
477             else {
478             /* default */
479 16           sig_opts.type = LTC_ECCSIG_ANSIX962;
480             }
481 32           rv = ecc_sign_hash_v2(data_ptr, (unsigned long)data_len, buffer, &buffer_len, &sig_opts, &self->key);
482 32 50         if (rv != CRYPT_OK) croak("FATAL: ecc_sign_hash_v2 failed: %s", error_to_string(rv));
483 32           RETVAL = newSVpvn((char*)buffer, buffer_len);
484 32           zeromem(buffer, sizeof(buffer));
485 32           zeromem(tmp, sizeof(tmp));
486             }
487             OUTPUT:
488             RETVAL
489              
490             int
491             verify_hash(Crypt::PK::ECC self, SV * sig, SV * data, const char * hash_name = "SHA1")
492             ALIAS:
493             verify_hash_rfc7518 = 3
494             verify_message = 1
495             verify_message_rfc7518 = 2
496             verify_hash_eth = 4
497             CODE:
498             {
499             int rv, stat, id;
500 143           unsigned char tmp[MAXBLOCKSIZE], *data_ptr = NULL, *sig_ptr = NULL;
501 143           unsigned long tmp_len = MAXBLOCKSIZE;
502 143           STRLEN data_len = 0, sig_len = 0;
503             ltc_ecc_sig_opts sig_opts;
504              
505 143           sig_opts.type = LTC_ECCSIG_ANSIX962;
506 143           sig_opts.prng = &self->pstate;
507 143           sig_opts.wprng = self->pindex;
508 143           sig_opts.enable_recovery_id = 0;
509 143           sig_opts.recovery_id = -1;
510 143           sig_opts.rfc6979_hash_alg = NULL;
511              
512 143           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
513 143           sig_ptr = (unsigned char *)SvPVbyte(sig, sig_len);
514 143           cryptx_internal_pk_prng_reseed(&self->pstate, self->pindex, &self->last_pid);
515 143 100         if (ix == 1 || ix == 2) {
    100          
516 131           id = cryptx_internal_find_hash(hash_name);
517 131 50         if (id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
518 131           rv = hash_memory(id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
519 131 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
520 131           data_ptr = tmp;
521 131           data_len = tmp_len;
522             }
523 143           RETVAL = 1;
524 143           stat = 0;
525 143 100         if (ix == 2 || ix == 3) {
    100          
526             /* rfc7518 */
527 6           sig_opts.type = LTC_ECCSIG_RFC7518;
528             }
529 137 100         else if (ix == 4) {
530             /* eth27 */
531 4           sig_opts.type = LTC_ECCSIG_ETH27;
532             }
533             else {
534             /* default */
535 133           sig_opts.type = LTC_ECCSIG_ANSIX962;
536             }
537 143           rv = ecc_verify_hash_v2(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &sig_opts, &stat, &self->key);
538 143 50         if (rv != CRYPT_OK || stat != 1) RETVAL = 0;
    100          
539             }
540             OUTPUT:
541             RETVAL
542              
543             SV *
544             shared_secret(Crypt::PK::ECC self, Crypt::PK::ECC pubkey)
545             CODE:
546             {
547             int rv;
548             unsigned char buffer[1024];
549 9           unsigned long buffer_len = 1024;
550              
551 9           rv = ecc_shared_secret(&self->key, &pubkey->key, buffer, &buffer_len);
552 9 100         if (rv != CRYPT_OK) croak("FATAL: ecc_shared_secret failed: %s", error_to_string(rv));
553 5           RETVAL = newSVpvn((char*)buffer, buffer_len);
554 5           zeromem(buffer, sizeof(buffer));
555             }
556             OUTPUT:
557             RETVAL
558              
559             int
560             recovery_pub(Crypt::PK::ECC self, SV * sig, SV* hash, SV* recid = NULL)
561             ALIAS:
562             recovery_pub_rfc7518 = 1
563             recovery_pub_eth = 2
564             CODE:
565             {
566             int rv;
567 6           unsigned char *sig_ptr = NULL, *hash_ptr = NULL;
568 6           STRLEN hash_len = 0, sig_len = 0;
569             ltc_ecc_sig_opts sig_opts;
570              
571 6           sig_opts.type = LTC_ECCSIG_ANSIX962;
572 6           sig_opts.prng = &self->pstate;
573 6           sig_opts.wprng = self->pindex;
574 6           sig_opts.enable_recovery_id = 0;
575 6           sig_opts.recovery_id = -1;
576 6           sig_opts.rfc6979_hash_alg = NULL;
577              
578 6 100         if (recid != NULL) {
579 5           sig_opts.enable_recovery_id = 1;
580 5           sig_opts.recovery_id = (int) SvIV(recid);
581             }
582 1 50         else if (ix != 2) {
583 0 0         if (ix == 1) {
584 0           croak("FATAL: recovery_pub_rfc7518 requires recid argument");
585             } else {
586 0           croak("FATAL: recovery_pub requires recid argument");
587             }
588             }
589              
590 6           sig_ptr = (unsigned char *)SvPVbyte(sig, sig_len);
591 6           hash_ptr = (unsigned char *)SvPVbyte(hash, hash_len);
592 6           cryptx_internal_pk_prng_reseed(&self->pstate, self->pindex, &self->last_pid);
593 6 100         if (ix == 1) {
594 2           sig_opts.type = LTC_ECCSIG_RFC7518;
595             }
596 4 100         else if (ix == 2) {
597 2           sig_opts.type = LTC_ECCSIG_ETH27;
598             }
599             else {
600 2           sig_opts.type = LTC_ECCSIG_ANSIX962;
601             }
602 6           rv = ecc_recover_key(sig_ptr, (unsigned long)sig_len, hash_ptr, (unsigned long) hash_len, &sig_opts, &self->key);
603 6 50         if (rv != CRYPT_OK) croak("FATAL: ecc_recover_key failed: %s", error_to_string(rv));
604 6 50         RETVAL = 1;
605             }
606             OUTPUT:
607             RETVAL
608              
609             void
610             DESTROY(Crypt::PK::ECC self)
611             CODE:
612 285 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
613 285 50         if (self->pindex >= 0 && prng_is_valid(self->pindex) == CRYPT_OK && prng_descriptor[self->pindex].done) {
    50          
    50          
614 285           prng_descriptor[self->pindex].done(&self->pstate);
615             }
616 285           zeromem(self, sizeof(*self));
617 285           Safefree(self);