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