File Coverage

inc/CryptX_PK_ECC.xs.inc
Criterion Covered Total %
statement 256 283 90.4
branch 141 214 65.8
condition n/a
subroutine n/a
pod n/a
total 397 497 79.8


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