File Coverage

inc/CryptX_PK_ECC.xs.inc
Criterion Covered Total %
statement 190 214 88.7
branch 110 186 59.1
condition n/a
subroutine n/a
pod n/a
total 300 400 75.0


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 253           Newz(0, RETVAL, 1, struct ecc_struct);
11 253 50         if (!RETVAL) croak("FATAL: Newz failed");
12 253           RETVAL->pindex = find_prng("chacha20");
13 253           RETVAL->key.type = -1;
14 253 50         if (RETVAL->pindex == -1) {
15 0           Safefree(RETVAL);
16 0           croak("FATAL: find_prng('chacha20') failed");
17             }
18 253           rv = rng_make_prng(320, RETVAL->pindex, &RETVAL->pstate, NULL); /* 320bits = 40bytes */
19 253 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 3           rv = cryptx_internal_ecc_set_curve_from_SV(&self->key, curve); /* croaks on error */
34 3 50         if (rv != CRYPT_OK) croak("FATAL: ecc_set_curve failed: %s", error_to_string(rv));
35             /* gen the key */
36 3           rv = ecc_generate_key(&self->pstate, self->pindex, &self->key);
37 3 50         if (rv != CRYPT_OK) croak("FATAL: ecc_generate_key failed: %s", error_to_string(rv));
38 3 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 76           unsigned char *data=NULL;
47 76           STRLEN data_len=0;
48              
49 76 50         data = (unsigned char *)SvPVbyte(key_data, data_len);
50 76 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
51 76           rv = ecc_import_openssl(data, (unsigned long)data_len, &self->key);
52 76 100         if (rv != CRYPT_OK) croak("FATAL: ecc_import_openssl failed: %s", error_to_string(rv));
53 63 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 13           unsigned char *data=NULL;
62 13           STRLEN data_len=0;
63              
64 13 50         data = (unsigned char *)SvPVbyte(key_data, data_len);
65 13 50         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
66 13           rv = ecc_import(data, (unsigned long)data_len, &self->key);
67 13 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 9           unsigned char *data=NULL, *pwd=NULL;
77 9           STRLEN data_len=0, pwd_len=0;
78              
79 9 50         data = (unsigned char *)SvPVbyte(key_data, data_len);
80 9 100         if (SvOK(passwd)) {
    50          
    50          
81 4 50         pwd = (unsigned char *)SvPVbyte(passwd, pwd_len);
82             }
83 9 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
84 9           rv = ecc_import_pkcs8(data, (unsigned long)data_len, pwd, (unsigned long)pwd_len, &self->key);
85 9 50         if (rv != CRYPT_OK) croak("FATAL: ecc_import_pkcs8 failed: %s", error_to_string(rv));
86 9 50         XPUSHs(ST(0)); /* return self */
87             }
88              
89             void
90             _import_x509(Crypt::PK::ECC self, SV * key_data)
91             PPCODE:
92             {
93             int rv;
94 0           unsigned char *data=NULL;
95 0           STRLEN data_len=0;
96              
97 0 0         data = (unsigned char *)SvPVbyte(key_data, data_len);
98 0 0         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
99 0           rv = ecc_import_x509(data, (unsigned long)data_len, &self->key);
100 0 0         if (rv != CRYPT_OK) croak("FATAL: ecc_import_x509 failed: %s", error_to_string(rv));
101 0 0         XPUSHs(ST(0)); /* return self */
102             }
103              
104             void
105             import_key_raw(Crypt::PK::ECC self, SV * key_data, SV * curve)
106             PPCODE:
107             {
108             int rv, type;
109 187           unsigned char *data=NULL;
110 187           STRLEN data_len=0;
111              
112 187 50         data = (unsigned char *)SvPVbyte(key_data, data_len);
113 187 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
114             /* setup dp structure */
115 187           rv = cryptx_internal_ecc_set_curve_from_SV(&self->key, curve); /* croaks on error */
116 187 50         if (rv != CRYPT_OK) croak("FATAL: ecc_set_curve failed: %s", error_to_string(rv));
117             /* import key */
118 187           type = (data_len == (STRLEN)ecc_get_size(&self->key)) ? PK_PRIVATE : PK_PUBLIC;
119 187           rv = ecc_set_key(data, (unsigned long)data_len, type, &self->key);
120 187 50         if (rv != CRYPT_OK) croak("FATAL: ecc_set_key failed: %s", error_to_string(rv));
121 187 50         XPUSHs(ST(0)); /* return self */
122             }
123              
124             int
125             is_private(Crypt::PK::ECC self)
126             CODE:
127 64 50         if (self->key.type == -1) XSRETURN_UNDEF;
128 64           RETVAL = (self->key.type == PK_PRIVATE) ? 1 : 0;
129             OUTPUT:
130             RETVAL
131              
132             int
133             size(Crypt::PK::ECC self)
134             CODE:
135 5 50         if (self->key.type == -1) XSRETURN_UNDEF;
136 5           RETVAL = ecc_get_size(&self->key);
137             OUTPUT:
138             RETVAL
139              
140             SV*
141             key2hash(Crypt::PK::ECC self)
142             PREINIT:
143             HV *rv_hash;
144             long siz, esize;
145             char buf[20001];
146             SV **not_used;
147             CODE:
148 29 50         if (self->key.type == -1) XSRETURN_UNDEF;
149 29           esize = ecc_get_size(&self->key);
150 29           rv_hash = newHV();
151             /* k */
152 29 50         siz = (self->key.k) ? mp_unsigned_bin_size(self->key.k) : 0;
153 29 50         if (siz>10000) {
154 0           croak("FATAL: key2hash failed - 'k' too big number");
155             }
156 29 100         if (siz>0) {
157 16           cryptx_internal_mp2hex_with_leading_zero(self->key.k, buf, 20000, esize*2);
158 16           not_used = hv_store(rv_hash, "k", 1, newSVpv(buf, strlen(buf)), 0);
159             }
160             else{
161 13           not_used = hv_store(rv_hash, "k", 1, newSVpv("", 0), 0);
162             }
163             /* pub_x */
164 29 50         siz = (self->key.pubkey.x) ? mp_unsigned_bin_size(self->key.pubkey.x) : 0;
165 29 50         if (siz>10000) {
166 0           croak("FATAL: key2hash failed - 'pub_x' too big number");
167             }
168 29 50         if (siz>0) {
169 29           cryptx_internal_mp2hex_with_leading_zero(self->key.pubkey.x, buf, 20000, esize*2);
170 29           not_used = hv_store(rv_hash, "pub_x", 5, newSVpv(buf, strlen(buf)), 0);
171             }
172             else{
173 0           not_used = hv_store(rv_hash, "pub_x", 5, newSVpv("", 0), 0);
174             }
175             /* pub_y */
176 29 50         siz = (self->key.pubkey.y) ? mp_unsigned_bin_size(self->key.pubkey.y) : 0;
177 29 50         if (siz>10000) {
178 0           croak("FATAL: key2hash failed - 'pub_y' too big number");
179             }
180 29 50         if (siz>0) {
181 29           cryptx_internal_mp2hex_with_leading_zero(self->key.pubkey.y, buf, 20000, esize*2);
182 29           not_used = hv_store(rv_hash, "pub_y", 5, newSVpv(buf, strlen(buf)), 0);
183             }
184             else{
185 0           not_used = hv_store(rv_hash, "pub_y", 5, newSVpv("", 0), 0);
186             }
187             /* curve_... */
188             {
189 29           not_used = hv_store(rv_hash, "curve_cofactor", 14, newSViv(self->key.dp.cofactor), 0);
190 29           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.prime, buf, 20000, 0);
191 29           not_used = hv_store(rv_hash, "curve_prime", 11, newSVpv(buf, strlen(buf)), 0);
192 29           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.A, buf, 20000, 0);
193 29           not_used = hv_store(rv_hash, "curve_A", 7, newSVpv(buf, strlen(buf)), 0);
194 29           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.B, buf, 20000, 0);
195 29           not_used = hv_store(rv_hash, "curve_B", 7, newSVpv(buf, strlen(buf)), 0);
196 29           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.order, buf, 20000, 0);
197 29           not_used = hv_store(rv_hash, "curve_order", 11, newSVpv(buf, strlen(buf)), 0);
198 29           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.base.x, buf, 20000, 0);
199 29           not_used = hv_store(rv_hash, "curve_Gx", 8, newSVpv(buf, strlen(buf)), 0);
200 29           cryptx_internal_mp2hex_with_leading_zero(self->key.dp.base.y, buf, 20000, 0);
201 29           not_used = hv_store(rv_hash, "curve_Gy", 8, newSVpv(buf, strlen(buf)), 0);
202 29           not_used = hv_store(rv_hash, "curve_bytes", 11, newSViv(mp_unsigned_bin_size(self->key.dp.prime)), 0);
203 29           not_used = hv_store(rv_hash, "curve_bits", 10, newSViv(mp_count_bits(self->key.dp.prime)), 0);
204              
205 29 100         if (self->key.dp.oidlen > 0) {
206             unsigned long i;
207             HV *h;
208             SV **pref, *cname;
209             char *cname_ptr, *oid_ptr;
210             STRLEN cname_len;
211              
212             /* OID -> "curve_oid" */
213 27           SV *oid = newSVpv("", 0);
214 163 100         for(i = 0; i < self->key.dp.oidlen - 1; i++) sv_catpvf(oid, "%lu.", self->key.dp.oid[i]);
215 27           sv_catpvf(oid, "%lu", self->key.dp.oid[i]);
216 27           oid_ptr = SvPVX(oid);
217 27           not_used = hv_store(rv_hash, "curve_oid", 9, oid, 0);
218              
219             /* curve name -> "curve_name" */
220 27 50         if ((h = get_hv("Crypt::PK::ECC::curve_oid2name", 0)) != NULL) {
221 27           pref = hv_fetch(h, oid_ptr, (U32)strlen(oid_ptr), 0);
222 27 50         if (pref) {
223 27 50         cname_ptr = SvPV(*pref, cname_len);
224 27           cname = newSVpv(cname_ptr, cname_len);
225 27           cname_ptr = SvPVX(cname);
226 27           not_used = hv_store(rv_hash, "curve_name", 10, cname, 0);
227             }
228             }
229             }
230             }
231             /* size */
232 29           not_used = hv_store(rv_hash, "size", 4, newSViv(esize), 0);
233             /* type */
234 29           not_used = hv_store(rv_hash, "type", 4, newSViv(self->key.type), 0);
235             LTC_UNUSED_PARAM(not_used);
236 29           RETVAL = newRV_noinc((SV*)rv_hash);
237             OUTPUT:
238             RETVAL
239              
240             SV *
241             export_key_der(Crypt::PK::ECC self, char * type)
242             CODE:
243             {
244             int rv;
245             unsigned char out[4096];
246 27           unsigned long int out_len = 4096;
247              
248 27 100         if (self->key.type == -1) croak("FATAL: export_key_der no key");
249 26 100         if (strnEQ(type, "private_short", 16)) {
250 5           rv = ecc_export_openssl(out, &out_len, PK_PRIVATE|PK_CURVEOID, &self->key);
251 5 100         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PRIVATE|PK_CURVEOID) failed: %s", error_to_string(rv));
252 4           RETVAL = newSVpvn((char*)out, out_len);
253             }
254 21 50         else if (strnEQ(type, "private_compressed", 16)) {
255 0           rv = ecc_export_openssl(out, &out_len, PK_PRIVATE|PK_CURVEOID|PK_COMPRESSED, &self->key);
256 0 0         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PRIVATE|PK_CURVEOID|PK_COMPRESSED) failed: %s", error_to_string(rv));
257 0           RETVAL = newSVpvn((char*)out, out_len);
258             }
259 21 100         else if (strnEQ(type, "private", 7)) {
260 10           rv = ecc_export_openssl(out, &out_len, PK_PRIVATE, &self->key);
261 10 50         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PRIVATE) failed: %s", error_to_string(rv));
262 10           RETVAL = newSVpvn((char*)out, out_len);
263             }
264 11 50         else if (strnEQ(type, "public_compressed", 15)) {
265 0           rv = ecc_export_openssl(out, &out_len, PK_PUBLIC|PK_CURVEOID|PK_COMPRESSED, &self->key);
266 0 0         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PUBLIC|PK_CURVEOID|PK_COMPRESSED) failed: %s", error_to_string(rv));
267 0           RETVAL = newSVpvn((char*)out, out_len);
268             }
269 11 100         else if (strnEQ(type, "public_short", 15)) {
270 3           rv = ecc_export_openssl(out, &out_len, PK_PUBLIC|PK_CURVEOID, &self->key);
271 3 50         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PUBLIC|PK_CURVEOID) failed: %s", error_to_string(rv));
272 3           RETVAL = newSVpvn((char*)out, out_len);
273             }
274 8 50         else if (strnEQ(type, "public", 6)) {
275 8           rv = ecc_export_openssl(out, &out_len, PK_PUBLIC, &self->key);
276 8 50         if (rv != CRYPT_OK) croak("FATAL: ecc_export_openssl(PK_PUBLIC) failed: %s", error_to_string(rv));
277 8           RETVAL = newSVpvn((char*)out, out_len);
278             }
279             else {
280 0           croak("FATAL: export_key_der invalid type '%s'", type);
281             }
282             }
283             OUTPUT:
284             RETVAL
285              
286             SV *
287             export_key_raw(Crypt::PK::ECC self, char * type)
288             CODE:
289             {
290             int rv;
291             unsigned char out[4096];
292 420           unsigned long int out_len = sizeof(out);
293              
294 420 50         if (self->key.type == -1) croak("FATAL: export_key_der no key");
295 420 100         if (strnEQ(type, "private", 7)) {
296 60           rv = ecc_get_key(out, &out_len, PK_PRIVATE, &self->key);
297 60 50         if (rv != CRYPT_OK) croak("FATAL: ecc_get_key(private) failed: %s", error_to_string(rv));
298 60           RETVAL = newSVpvn((char*)out, out_len);
299             }
300 360 100         else if (strnEQ(type, "public_compressed", 17)) {
301 180           rv = ecc_get_key(out, &out_len, PK_PUBLIC|PK_COMPRESSED, &self->key);
302 180 50         if (rv != CRYPT_OK) croak("FATAL: ecc_get_key(public_compressed) failed: %s", error_to_string(rv));
303 180           RETVAL = newSVpvn((char*)out, out_len);
304             }
305 180 50         else if (strnEQ(type, "public", 6)) {
306 180           rv = ecc_get_key(out, &out_len, PK_PUBLIC, &self->key);
307 180 50         if (rv != CRYPT_OK) croak("FATAL: ecc_get_key(public) failed: %s", error_to_string(rv));
308 180           RETVAL = newSVpvn((char*)out, out_len);
309             }
310             else {
311 0           croak("FATAL: export_key_raw invalid type '%s'", type);
312             }
313             }
314             OUTPUT:
315             RETVAL
316              
317             SV *
318             encrypt(Crypt::PK::ECC self, SV * data, const char * hash_name = "SHA1")
319             CODE:
320             {
321             int rv, hash_id;
322 2           unsigned char *data_ptr=NULL;
323 2           STRLEN data_len=0;
324             unsigned char buffer[1024];
325 2           unsigned long buffer_len = 1024;
326              
327 2 50         data_ptr = (unsigned char *)SvPVbyte(data, data_len);
328              
329 2           hash_id = cryptx_internal_find_hash(hash_name);
330 2 50         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
331 2           rv = ecc_encrypt_key(data_ptr, (unsigned long)data_len, buffer, &buffer_len,
332             &self->pstate, self->pindex,
333 2           hash_id, &self->key);
334 2 50         if (rv != CRYPT_OK) croak("FATAL: ecc_encrypt_key failed: %s", error_to_string(rv));
335 2           RETVAL = newSVpvn((char*)buffer, buffer_len);
336             }
337             OUTPUT:
338             RETVAL
339              
340             SV *
341             decrypt(Crypt::PK::ECC self, SV * data)
342             CODE:
343             {
344             int rv;
345 2           unsigned char *data_ptr=NULL;
346 2           STRLEN data_len=0;
347             unsigned char buffer[1024];
348 2           unsigned long buffer_len = 1024;
349              
350 2 50         data_ptr = (unsigned char *)SvPVbyte(data, data_len);
351              
352 2           rv = ecc_decrypt_key(data_ptr, (unsigned long)data_len, buffer, &buffer_len, &self->key);
353 2 50         if (rv != CRYPT_OK) croak("FATAL: ecc_decrypt_key_ex failed: %s", error_to_string(rv));
354 2           RETVAL = newSVpvn((char*)buffer, buffer_len);
355             }
356             OUTPUT:
357             RETVAL
358              
359             SV *
360             sign_hash(Crypt::PK::ECC self, SV * data, const char * hash_name = "SHA1")
361             ALIAS:
362             sign_hash_rfc7518 = 3
363             sign_message = 1
364             sign_message_rfc7518 = 2
365             CODE:
366             {
367             int rv, id;
368 5           unsigned char buffer[1024], tmp[MAXBLOCKSIZE], *data_ptr = NULL;
369 5           unsigned long tmp_len = MAXBLOCKSIZE, buffer_len = 1024;
370 5           STRLEN data_len = 0;
371              
372 5 50         data_ptr = (unsigned char *)SvPVbyte(data, data_len);
373 5 100         if (ix == 1 || ix == 2) {
    100          
374 3           id = cryptx_internal_find_hash(hash_name);
375 3 50         if (id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
376 3           rv = hash_memory(id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
377 3 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
378 3           data_ptr = tmp;
379 3           data_len = tmp_len;
380             }
381 5 100         if (ix == 2 || ix == 3) {
    50          
382 1           rv = ecc_sign_hash_rfc7518(data_ptr, (unsigned long)data_len, buffer, &buffer_len,
383             &self->pstate, self->pindex,
384             &self->key);
385             }
386             else {
387 4           rv = ecc_sign_hash(data_ptr, (unsigned long)data_len, buffer, &buffer_len,
388             &self->pstate, self->pindex,
389             &self->key);
390             }
391 5 50         if (rv != CRYPT_OK) croak("FATAL: ecc_sign_hash_ex failed: %s", error_to_string(rv));
392 5           RETVAL = newSVpvn((char*)buffer, buffer_len);
393             }
394             OUTPUT:
395             RETVAL
396              
397             int
398             verify_hash(Crypt::PK::ECC self, SV * sig, SV * data, const char * hash_name = "SHA1")
399             ALIAS:
400             verify_hash_rfc7518 = 3
401             verify_message = 1
402             verify_message_rfc7518 = 2
403             CODE:
404             {
405             int rv, stat, id;
406 125           unsigned char tmp[MAXBLOCKSIZE], *data_ptr = NULL, *sig_ptr = NULL;
407 125           unsigned long tmp_len = MAXBLOCKSIZE;
408 125           STRLEN data_len = 0, sig_len = 0;
409              
410 125 50         data_ptr = (unsigned char *)SvPVbyte(data, data_len);
411 125 50         sig_ptr = (unsigned char *)SvPVbyte(sig, sig_len);
412 125 100         if (ix == 1 || ix == 2) {
    100          
413 123           id = cryptx_internal_find_hash(hash_name);
414 123 50         if (id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
415 123           rv = hash_memory(id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
416 123 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
417 123           data_ptr = tmp;
418 123           data_len = tmp_len;
419             }
420 125           RETVAL = 1;
421 125           stat = 0;
422 125 100         if (ix == 2 || ix == 3) {
    50          
423 1           rv = ecc_verify_hash_rfc7518(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key);
424             }
425             else {
426 124           rv = ecc_verify_hash(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, &stat, &self->key);
427             }
428 125 50         if (rv != CRYPT_OK || stat != 1) RETVAL = 0;
    50          
429             }
430             OUTPUT:
431             RETVAL
432              
433             SV *
434             shared_secret(Crypt::PK::ECC self, Crypt::PK::ECC pubkey)
435             CODE:
436             {
437             int rv;
438             unsigned char buffer[1024];
439 4           unsigned long buffer_len = 1024;
440              
441 4           rv = ecc_shared_secret(&self->key, &pubkey->key, buffer, &buffer_len);
442 4 50         if (rv != CRYPT_OK) croak("FATAL: ecc_shared_secret failed: %s", error_to_string(rv));
443 4           RETVAL = newSVpvn((char*)buffer, buffer_len);
444             }
445             OUTPUT:
446             RETVAL
447              
448             void
449             DESTROY(Crypt::PK::ECC self)
450             CODE:
451 253 100         if (self->key.type != -1) { ecc_free(&self->key); self->key.type = -1; }
452 253           Safefree(self);
453