File Coverage

inc/CryptX_PK_ECC.xs.inc
Criterion Covered Total %
statement 250 277 90.2
branch 141 214 65.8
condition n/a
subroutine n/a
pod n/a
total 391 491 79.6


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