File Coverage

inc/CryptX_PK_ECC.xs.inc
Criterion Covered Total %
statement 237 264 89.7
branch 126 198 63.6
condition n/a
subroutine n/a
pod n/a
total 363 462 78.5


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 270           Newz(0, RETVAL, 1, struct ecc_struct);
11 270 50         if (!RETVAL) croak("FATAL: Newz failed");
12 270           RETVAL->pindex = find_prng("chacha20");
13 270           RETVAL->key.type = -1;
14 270 50         if (RETVAL->pindex == -1) {
15 0           Safefree(RETVAL);
16 0           croak("FATAL: find_prng('chacha20') failed");
17             }
18 270           rv = rng_make_prng(320, RETVAL->pindex, &RETVAL->pstate, NULL); /* 320bits = 40bytes */
19 270 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 9           rv = cryptx_internal_ecc_set_curve_from_SV(&self->key, curve); /* croaks on error */
34 9 50         if (rv != CRYPT_OK) croak("FATAL: ecc_set_curve failed: %s", error_to_string(rv));
35             /* gen the key */
36 9           rv = ecc_generate_key(&self->pstate, self->pindex, &self->key);
37 9 50         if (rv != CRYPT_OK) croak("FATAL: ecc_generate_key failed: %s", error_to_string(rv));
38 9 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 = "SHA1")
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             int rv, id;
421 9           unsigned char buffer[1024], tmp[MAXBLOCKSIZE], *data_ptr = NULL;
422 9           unsigned long tmp_len = MAXBLOCKSIZE, buffer_len = 1024;
423 9           STRLEN data_len = 0;
424              
425 9           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
426 9 100         if (ix == 1 || ix == 2) {
    100          
427 3           id = cryptx_internal_find_hash(hash_name);
428 3 50         if (id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
429 3           rv = hash_memory(id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
430 3 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
431 3           data_ptr = tmp;
432 3           data_len = tmp_len;
433             }
434 9 100         if (ix == 2 || ix == 3) {
    100          
435 2           rv = ecc_sign_hash_rfc7518(data_ptr, (unsigned long)data_len, buffer, &buffer_len,
436             &self->pstate, self->pindex,
437 2           &self->key);
438             }
439 7 100         else if (ix == 4) {
440 2           rv = ecc_sign_hash_eth27(data_ptr, (unsigned long)data_len, buffer, &buffer_len,
441             &self->pstate, self->pindex,
442 2           &self->key);
443             }
444             else {
445 5           rv = ecc_sign_hash(data_ptr, (unsigned long)data_len, buffer, &buffer_len,
446             &self->pstate, self->pindex,
447 5           &self->key);
448             }
449 9 50         if (rv != CRYPT_OK) croak("FATAL: ecc_sign_hash_ex failed: %s", error_to_string(rv));
450 9           RETVAL = newSVpvn((char*)buffer, buffer_len);
451             }
452             OUTPUT:
453             RETVAL
454              
455             int
456             verify_hash(Crypt::PK::ECC self, SV * sig, SV * data, const char * hash_name = "SHA1")
457             ALIAS:
458             verify_hash_rfc7518 = 3
459             verify_message = 1
460             verify_message_rfc7518 = 2
461             verify_hash_eth = 4
462             CODE:
463             {
464             int rv, stat, id;
465 126           unsigned char tmp[MAXBLOCKSIZE], *data_ptr = NULL, *sig_ptr = NULL;
466 126           unsigned long tmp_len = MAXBLOCKSIZE;
467 126           STRLEN data_len = 0, sig_len = 0;
468              
469 126           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
470 126           sig_ptr = (unsigned char *)SvPVbyte(sig, sig_len);
471 126 100         if (ix == 1 || ix == 2) {
    100          
472 123           id = cryptx_internal_find_hash(hash_name);
473 123 50         if (id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
474 123           rv = hash_memory(id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
475 123 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
476 123           data_ptr = tmp;
477 123           data_len = tmp_len;
478             }
479 126           RETVAL = 1;
480 126           stat = 0;
481 126 100         if (ix == 2 || ix == 3) {
    50          
482 1           rv = ecc_verify_hash_rfc7518(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key);
483             }
484 125 100         else if (ix == 4) {
485 1           rv = ecc_verify_hash_eth27(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key);
486             }
487             else {
488 124           rv = ecc_verify_hash(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key);
489             }
490 126 50         if (rv != CRYPT_OK || stat != 1) RETVAL = 0;
    50          
491             }
492             OUTPUT:
493             RETVAL
494              
495             SV *
496             shared_secret(Crypt::PK::ECC self, Crypt::PK::ECC pubkey)
497             CODE:
498             {
499             int rv;
500             unsigned char buffer[1024];
501 4           unsigned long buffer_len = 1024;
502              
503 4           rv = ecc_shared_secret(&self->key, &pubkey->key, buffer, &buffer_len);
504 4 50         if (rv != CRYPT_OK) croak("FATAL: ecc_shared_secret failed: %s", error_to_string(rv));
505 4           RETVAL = newSVpvn((char*)buffer, buffer_len);
506             }
507             OUTPUT:
508             RETVAL
509              
510             int
511             recovery_pub(Crypt::PK::ECC self, SV * sig, SV* hash, SV* recid = NULL)
512             ALIAS:
513             recovery_pub_rfc7518 = 1
514             recovery_pub_eth = 2
515             CODE:
516             {
517             int rv;
518 6           unsigned char *sig_ptr = NULL, *hash_ptr = NULL;
519 6           STRLEN hash_len = 0, sig_len = 0;
520 6           int recovery_id = -1;
521              
522 6 100         if (recid != NULL) {
523 5           recovery_id = (int) SvIV(recid);
524 1 50         } else if (ix != 2) {
525 0 0         if (ix == 1) {
526 0           croak("FATAL: recovery_pub_rfc7518 requires recid argument");
527             } else {
528 0           croak("FATAL: recovery_pub requires recid argument");
529             }
530             }
531              
532 6           sig_ptr = (unsigned char *)SvPVbyte(sig, sig_len);
533 6           hash_ptr = (unsigned char *)SvPVbyte(hash, hash_len);
534 6 100         if (ix == 1) {
535 2           rv = ecc_recover_key(sig_ptr, (unsigned long)sig_len, hash_ptr, (unsigned long) hash_len,
536             recovery_id, LTC_ECCSIG_RFC7518, &self->key);
537             }
538 4 100         else if (ix == 2) {
539             /* Ethereum's signature contains the recovery id in the last byte of the signature
540             * don't need to pass it as a separate argument
541             */
542 2           rv = ecc_recover_key(sig_ptr, (unsigned long)sig_len, hash_ptr, (unsigned long) hash_len,
543             recovery_id, LTC_ECCSIG_ETH27, &self->key);
544             }
545             else {
546 2           rv = ecc_recover_key(sig_ptr, (unsigned long)sig_len, hash_ptr, (unsigned long) hash_len,
547             recovery_id, LTC_ECCSIG_ANSIX962, &self->key);
548             }
549 6 50         if (rv != CRYPT_OK) croak("FATAL: ecc_recover_key failed: %s", error_to_string(rv));
550 6 50         RETVAL = 1;
551             }
552             OUTPUT:
553             RETVAL
554              
555             void
556             DESTROY(Crypt::PK::ECC self)
557             CODE:
558 270 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
559 270           Safefree(self);
560