File Coverage

inc/CryptX_PK_ECC.xs.inc
Criterion Covered Total %
statement 286 319 89.6
branch 149 220 67.7
condition n/a
subroutine n/a
pod n/a
total 435 539 80.7


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