File Coverage

inc/CryptX_PK_RSA.xs.inc
Criterion Covered Total %
statement 232 296 78.3
branch 126 276 45.6
condition n/a
subroutine n/a
pod n/a
total 358 572 62.5


line stmt bran cond sub pod time code
1             MODULE = CryptX PACKAGE = Crypt::PK::RSA
2              
3             PROTOTYPES: DISABLE
4              
5             Crypt::PK::RSA
6             _new(Class)
7             CODE:
8             {
9             int rv;
10 107           Newz(0, RETVAL, 1, struct rsa_struct);
11 107 50         if (!RETVAL) croak("FATAL: Newz failed");
12 107           RETVAL->key.type = -1;
13 107           RETVAL->pindex = find_prng("chacha20");
14 107 50         if (RETVAL->pindex == -1) {
15 0           Safefree(RETVAL);
16 0           croak("FATAL: find_prng('chacha20') failed");
17             }
18 107           rv = rng_make_prng(320, RETVAL->pindex, &RETVAL->pstate, NULL); /* 320bits = 40bytes */
19 107 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::RSA self, int key_size=256, long key_e=65537)
29             PPCODE:
30             {
31             /* key_size is in octets */
32             int rv;
33             /* gen the key */
34 1           rv = rsa_make_key(&self->pstate, self->pindex, key_size, key_e, &self->key);
35 1 50         if (rv != CRYPT_OK) croak("FATAL: rsa_make_key failed: %s", error_to_string(rv));
36 1 50         XPUSHs(ST(0)); /* return self */
37             }
38              
39             void
40             _import(Crypt::PK::RSA self, SV * key_data)
41             PPCODE:
42             {
43             int rv;
44 89           unsigned char *data=NULL;
45 89           STRLEN data_len=0;
46              
47 89           data = (unsigned char *)SvPVbyte(key_data, data_len);
48 89 100         if (self->key.type != -1) { rsa_free(&self->key); self->key.type = -1; }
49 89           rv = rsa_import(data, (unsigned long)data_len, &self->key);
50 89 100         if (rv != CRYPT_OK) croak("FATAL: rsa_import failed: %s", error_to_string(rv));
51 86 50         XPUSHs(ST(0)); /* return self */
52             }
53              
54             void
55             _import_pkcs8(Crypt::PK::RSA self, SV * key_data, SV * passwd)
56             PPCODE:
57             {
58             int rv;
59 3           unsigned char *data = NULL;
60 3           STRLEN data_len = 0;
61 3           password_ctx pw_ctx = { cryptx_internal_password_cb_getpw, cryptx_internal_password_cb_free, passwd };
62              
63 3           data = (unsigned char *)SvPVbyte(key_data, data_len);
64 3 50         if (self->key.type != -1) { rsa_free(&self->key); self->key.type = -1; }
65 3 100         if (SvOK(passwd)) {
66 1           rv = rsa_import_pkcs8(data, (unsigned long)data_len, &pw_ctx, &self->key);
67             }
68             else {
69 2           rv = rsa_import_pkcs8(data, (unsigned long)data_len, NULL, &self->key);
70             }
71 3 100         if (rv != CRYPT_OK) croak("FATAL: rsa_import_pkcs8 failed: %s", error_to_string(rv));
72 2 50         XPUSHs(ST(0)); /* return self */
73             }
74              
75             void
76             _import_pem(Crypt::PK::RSA self, SV * key_data, SV * passwd)
77             PPCODE:
78             {
79             int rv;
80 54           unsigned char *data = NULL;
81 54           STRLEN data_len = 0;
82 54           password_ctx pw_ctx = { cryptx_internal_password_cb_getpw, cryptx_internal_password_cb_free, passwd };
83             ltc_pka_key key_from_pem;
84              
85 54           data = (unsigned char *)SvPVbyte(key_data, data_len);
86 54 100         if (self->key.type != -1) { rsa_free(&self->key); self->key.type = -1; }
87 54 100         if (SvOK(passwd)) {
88 22           rv = pem_decode_pkcs(data, (unsigned long)data_len, &key_from_pem, &pw_ctx);
89             }
90             else {
91 32           rv = pem_decode_pkcs(data, (unsigned long)data_len, &key_from_pem, NULL);
92             }
93 54 50         if (rv != CRYPT_OK) croak("FATAL: pem_decode_pkcs failed: %s", error_to_string(rv));
94 54 50         if (key_from_pem.id != LTC_PKA_RSA) croak("FATAL: pem_decode_pkcs decoded non-RSA key");
95 54           self->key = key_from_pem.u.rsa;
96 54 50         XPUSHs(ST(0)); /* return self */
97             }
98              
99              
100             void
101             _import_openssh(Crypt::PK::RSA self, SV * key_data, SV * passwd)
102             PPCODE:
103             {
104             int rv;
105 18           unsigned char *data = NULL;
106 18           STRLEN data_len = 0;
107 18           password_ctx pw_ctx = { cryptx_internal_password_cb_getpw, cryptx_internal_password_cb_free, passwd };
108             ltc_pka_key key_from_pem;
109              
110 18           data = (unsigned char *)SvPVbyte(key_data, data_len);
111 18 50         if (self->key.type != -1) { rsa_free(&self->key); self->key.type = -1; }
112 18 100         if (SvOK(passwd)) {
113 6           rv = pem_decode_openssh(data, (unsigned long)data_len, &key_from_pem, &pw_ctx);
114             }
115             else {
116 12           rv = pem_decode_openssh(data, (unsigned long)data_len, &key_from_pem, NULL);
117             }
118 18 50         if (rv != CRYPT_OK) croak("FATAL: pem_decode_openssh failed: %s", error_to_string(rv));
119 18 50         if (key_from_pem.id != LTC_PKA_RSA) croak("FATAL: pem_decode_openssh decoded non-RSA key");
120 18           self->key = key_from_pem.u.rsa;
121 18 50         XPUSHs(ST(0)); /* return self */
122             }
123              
124             void
125             _import_x509(Crypt::PK::RSA self, SV * key_data)
126             PPCODE:
127             {
128             int rv;
129 1           unsigned char *data=NULL;
130 1           STRLEN data_len=0;
131              
132 1           data = (unsigned char *)SvPVbyte(key_data, data_len);
133 1 50         if (self->key.type != -1) { rsa_free(&self->key); self->key.type = -1; }
134 1           rv = rsa_import_x509(data, (unsigned long)data_len, &self->key);
135 1 50         if (rv != CRYPT_OK) croak("FATAL: rsa_import_x509 failed: %s", error_to_string(rv));
136 1 50         XPUSHs(ST(0)); /* return self */
137             }
138              
139             void
140             _import_hex(Crypt::PK::RSA self, char *N, char *e, char *d=NULL, char *p=NULL, char *q=NULL, char *dP=NULL, char *dQ=NULL, char *qP=NULL)
141             PPCODE:
142             {
143             int rv;
144             unsigned char Nbin[1024], ebin[128], dbin[1024], pbin[512], qbin[512], dPbin[512], dQbin[512], qPbin[512];
145 7           unsigned long Nlen=sizeof(Nbin), elen=sizeof(ebin), dlen=sizeof(dbin), plen=sizeof(pbin),
146 7           qlen=sizeof(qbin), dPlen=sizeof(dPbin), dQlen=sizeof(dQbin), qPlen=sizeof(qPbin);
147              
148 7           rv = radix_to_bin(N, 16, Nbin, &Nlen);
149 7 50         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(N) failed: %s", error_to_string(rv));
150 7           rv = radix_to_bin(e, 16, ebin, &elen);
151 7 50         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(e) failed: %s", error_to_string(rv));
152              
153 7 50         if (d && strlen(d) > 0) {
    0          
154             /* private */
155 0           rv = radix_to_bin(d, 16, dbin, &dlen);
156 0 0         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(d) failed: %s", error_to_string(rv));
157 0           rv = rsa_set_key(Nbin, Nlen, ebin, elen, dbin, dlen, &self->key);
158 0 0         if (rv != CRYPT_OK) croak("FATAL: rsa_set_key failed: %s", error_to_string(rv));
159             }
160             else {
161             /* public */
162 7           rv = rsa_set_key(Nbin, Nlen, ebin, elen, NULL, 0, &self->key);
163 7 50         if (rv != CRYPT_OK) croak("FATAL: rsa_set_key failed: %s", error_to_string(rv));
164             }
165              
166 7 50         if (p && strlen(p) > 0 && q && strlen(q) > 0) {
    0          
    0          
    0          
167             /* private only */
168 0           rv = radix_to_bin(p, 16, pbin, &plen);
169 0 0         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(p) failed: %s", error_to_string(rv));
170 0           rv = radix_to_bin(q, 16, qbin, &qlen);
171 0 0         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(q) failed: %s", error_to_string(rv));
172 0           rv = rsa_set_factors(pbin, plen, qbin, qlen, &self->key);
173 0 0         if (rv != CRYPT_OK) croak("FATAL: rsa_set_factors failed: %s", error_to_string(rv));
174             }
175              
176 7 50         if (dP && strlen(dP) > 0 && dQ && strlen(dQ) > 0 && qP && strlen(qP) > 0) {
    0          
    0          
    0          
    0          
    0          
177             /* private only */
178 0           rv = radix_to_bin(dP, 16, dPbin, &dPlen);
179 0 0         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(dP) failed: %s", error_to_string(rv));
180 0           rv = radix_to_bin(dQ, 16, dQbin, &dQlen);
181 0 0         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(dQ) failed: %s", error_to_string(rv));
182 0           rv = radix_to_bin(qP, 16, qPbin, &qPlen);
183 0 0         if (rv != CRYPT_OK) croak("FATAL: radix_to_bin(qP) failed: %s", error_to_string(rv));
184 0           rv = rsa_set_crt_params(dPbin, dPlen, dQbin, dQlen, qPbin, qPlen, &self->key);
185 0 0         if (rv != CRYPT_OK) croak("FATAL: rsa_set_crt_params failed: %s", error_to_string(rv));
186             }
187              
188 7 50         XPUSHs(ST(0)); /* return self */
189             }
190              
191             int
192             is_private(Crypt::PK::RSA self)
193             CODE:
194 88 50         if (self->key.type == -1 || self->key.N == NULL) XSRETURN_UNDEF;
    50          
195 88 100         RETVAL = (self->key.type == PK_PRIVATE) ? 1 : 0;
196             OUTPUT:
197             RETVAL
198              
199             size_t
200             size(Crypt::PK::RSA self)
201             CODE:
202 1 50         if (self->key.type == -1 || self->key.N == NULL) XSRETURN_UNDEF;
    50          
203 1           RETVAL = mp_ubin_size(self->key.N);
204             OUTPUT:
205             RETVAL
206              
207             SV*
208             key2hash(Crypt::PK::RSA self)
209             PREINIT:
210             HV *rv_hash;
211             size_t siz, nsize;
212             char buf[20001];
213             SV **not_used;
214             CODE:
215 133 50         if (self->key.type == -1 || self->key.N == NULL) XSRETURN_UNDEF;
    50          
216 133           nsize = mp_ubin_size(self->key.N);
217 133           rv_hash = newHV();
218             /* e */
219 133 50         siz = (self->key.e) ? mp_ubin_size(self->key.e) : 0;
220 133 50         if (siz>10000) {
221 0           croak("FATAL: key2hash failed - 'e' too big number");
222             }
223 133 50         if (siz>0) {
224 133           cryptx_internal_mp2hex_with_leading_zero(self->key.e, buf, 20000, 0);
225 133           not_used = hv_store(rv_hash, "e", 1, newSVpv(buf, strlen(buf)), 0);
226             }
227             else{
228 0           not_used = hv_store(rv_hash, "e", 1, newSVpv("", 0), 0);
229             }
230             /* d */
231 133 50         siz = (self->key.d) ? mp_ubin_size(self->key.d) : 0;
232 133 50         if (siz>10000) {
233 0           croak("FATAL: key2hash failed - 'd' too big number");
234             }
235 133 100         if (siz>0) {
236 73           cryptx_internal_mp2hex_with_leading_zero(self->key.d, buf, 20000, 0);
237 73           not_used = hv_store(rv_hash, "d", 1, newSVpv(buf, strlen(buf)), 0);
238             }
239             else{
240 60           not_used = hv_store(rv_hash, "d", 1, newSVpv("", 0), 0);
241             }
242             /* N */
243 133 50         siz = (self->key.N) ? nsize : 0;
244 133 50         if (siz>10000) {
245 0           croak("FATAL: key2hash failed - 'N' too big number");
246             }
247 133 50         if (siz>0) {
248 133           cryptx_internal_mp2hex_with_leading_zero(self->key.N, buf, 20000, 0);
249 133           not_used = hv_store(rv_hash, "N", 1, newSVpv(buf, strlen(buf)), 0);
250             }
251             else{
252 0           not_used = hv_store(rv_hash, "N", 1, newSVpv("", 0), 0);
253             }
254             /* q */
255 133 50         siz = (self->key.q) ? mp_ubin_size(self->key.q) : 0;
256 133 50         if (siz>10000) {
257 0           croak("FATAL: key2hash failed - 'q' too big number");
258             }
259 133 100         if (siz>0) {
260 73           cryptx_internal_mp2hex_with_leading_zero(self->key.q, buf, 20000, 0);
261 73           not_used = hv_store(rv_hash, "q", 1, newSVpv(buf, strlen(buf)), 0);
262             }
263             else{
264 60           not_used = hv_store(rv_hash, "q", 1, newSVpv("", 0), 0);
265             }
266             /* p */
267 133 50         siz = (self->key.p) ? mp_ubin_size(self->key.p) : 0;
268 133 50         if (siz>10000) {
269 0           croak("FATAL: key2hash failed - 'p' too big number");
270             }
271 133 100         if (siz>0) {
272 73           cryptx_internal_mp2hex_with_leading_zero(self->key.p, buf, 20000, 0);
273 73           not_used = hv_store(rv_hash, "p", 1, newSVpv(buf, strlen(buf)), 0);
274             }
275             else{
276 60           not_used = hv_store(rv_hash, "p", 1, newSVpv("", 0), 0);
277             }
278             /* qP */
279 133 50         siz = (self->key.qP) ? mp_ubin_size(self->key.qP) : 0;
280 133 50         if (siz>10000) {
281 0           croak("FATAL: key2hash failed - 'qP' too big number");
282             }
283 133 100         if (siz>0) {
284 73           cryptx_internal_mp2hex_with_leading_zero(self->key.qP, buf, 20000, 0);
285 73           not_used = hv_store(rv_hash, "qP", 2, newSVpv(buf, strlen(buf)), 0);
286             }
287             else{
288 60           not_used = hv_store(rv_hash, "qP", 2, newSVpv("", 0), 0);
289             }
290             /* dP */
291 133 50         siz = (self->key.dP) ? mp_ubin_size(self->key.dP) : 0;
292 133 50         if (siz>10000) {
293 0           croak("FATAL: key2hash failed - 'dP' too big number");
294             }
295 133 100         if (siz>0) {
296 73           cryptx_internal_mp2hex_with_leading_zero(self->key.dP, buf, 20000, 0);
297 73           not_used = hv_store(rv_hash, "dP", 2, newSVpv(buf, strlen(buf)), 0);
298             }
299             else{
300 60           not_used = hv_store(rv_hash, "dP", 2, newSVpv("", 0), 0);
301             }
302             /* dQ */
303 133 50         siz = (self->key.dQ) ? mp_ubin_size(self->key.dQ) : 0;
304 133 50         if (siz>10000) {
305 0           croak("FATAL: key2hash failed - 'dQ' too big number");
306             }
307 133 100         if (siz>0) {
308 73           cryptx_internal_mp2hex_with_leading_zero(self->key.dQ, buf, 20000, 0);
309 73           not_used = hv_store(rv_hash, "dQ", 2, newSVpv(buf, strlen(buf)), 0);
310             }
311             else{
312 60           not_used = hv_store(rv_hash, "dQ", 2, newSVpv("", 0), 0);
313             }
314             /* size */
315 133           not_used = hv_store(rv_hash, "size", 4, newSViv(nsize), 0);
316             /* type */
317 133           not_used = hv_store(rv_hash, "type", 4, newSViv(self->key.type), 0);
318             LTC_UNUSED_PARAM(not_used);
319 133           RETVAL = newRV_noinc((SV*)rv_hash);
320             OUTPUT:
321             RETVAL
322              
323             SV*
324             export_key_der(Crypt::PK::RSA self, char * type)
325             CODE:
326             {
327             int rv;
328             unsigned char out[4096];
329 5           unsigned long out_len = 4096;
330              
331 5           RETVAL = newSVpvn(NULL, 0); /* undef */
332 5 100         if (strnEQ(type, "private", 7)) {
333 2           rv = rsa_export(out, &out_len, PK_PRIVATE, &self->key);
334 2 50         if (rv != CRYPT_OK) croak("FATAL: rsa_export(PK_PRIVATE) failed: %s", error_to_string(rv));
335 2           RETVAL = newSVpvn((char*)out, out_len);
336             }
337 3 50         else if (strnEQ(type, "public", 6)) {
338 3           rv = rsa_export(out, &out_len, PK_PUBLIC|PK_STD, &self->key);
339 3 50         if (rv != CRYPT_OK) croak("FATAL: rsa_export(PK_PUBLIC|PK_STD) failed: %s", error_to_string(rv));
340 3           RETVAL = newSVpvn((char*)out, out_len);
341             }
342             else {
343 0           croak("FATAL: export_key_der invalid type '%s'", type);
344             }
345             }
346             OUTPUT:
347             RETVAL
348              
349             SV *
350             encrypt(Crypt::PK::RSA self, SV * data, const char * padding = "oaep", const char * mgf_hash = "SHA1", SV * oaep_lparam = NULL, const char * lparam_hash = NULL)
351             CODE:
352             {
353             int rv, mgf_hash_id, lparam_hash_id;
354 2           unsigned char *lparam_ptr=NULL;
355 2           STRLEN lparam_len=0;
356 2           unsigned char *data_ptr=NULL;
357 2           STRLEN data_len=0;
358             unsigned char buffer[1024];
359 2           unsigned long buffer_len = 1024;
360              
361 2           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
362              
363 2           RETVAL = newSVpvn(NULL, 0); /* undef */
364 2 100         if (strnEQ(padding, "oaep", 4)) {
365 1           mgf_hash_id = cryptx_internal_find_hash(mgf_hash);
366 1 50         if (mgf_hash_id == -1) croak("FATAL: find_hash failed for '%s'", mgf_hash);
367 1 50         if (lparam_hash) {
368 0           lparam_hash_id = cryptx_internal_find_hash(lparam_hash);
369 0 0         if (lparam_hash_id == -1) croak("FATAL: find_hash failed for '%s'", lparam_hash);
370             }
371             else {
372 1           lparam_hash_id = mgf_hash_id;
373             }
374 1 50         if (oaep_lparam) lparam_ptr = (unsigned char *)SvPVbyte(oaep_lparam, lparam_len);
375 1           rv = rsa_encrypt_key_ex(data_ptr, (unsigned long)data_len, buffer, &buffer_len, lparam_ptr, (unsigned long)lparam_len,
376             &self->pstate, self->pindex,
377 1           mgf_hash_id, lparam_hash_id, LTC_PKCS_1_OAEP, &self->key);
378 1 50         if (rv != CRYPT_OK) croak("FATAL: rsa_encrypt_key_ex failed: %s", error_to_string(rv));
379 1           RETVAL = newSVpvn((char*)buffer, buffer_len);
380             }
381 1 50         else if (strnEQ(padding, "v1.5", 4)) {
382 0           rv = rsa_encrypt_key_ex(data_ptr, (unsigned long)data_len, buffer, &buffer_len, NULL, 0,
383             &self->pstate, self->pindex,
384 0           0, -1, LTC_PKCS_1_V1_5, &self->key);
385 0 0         if (rv != CRYPT_OK) croak("FATAL: rsa_encrypt_key_ex failed: %s", error_to_string(rv));
386 0           RETVAL = newSVpvn((char*)buffer, buffer_len);
387             }
388 1 50         else if (strnEQ(padding, "none", 4)) {
389             /* raw RSA */
390 1           rv = ltc_mp.rsa_me(data_ptr, (unsigned long)data_len, buffer, &buffer_len, PK_PUBLIC, &self->key);
391 1 50         if (rv != CRYPT_OK) croak("FATAL: rsa_me failed: %s", error_to_string(rv));
392 1           RETVAL = newSVpvn((char*)buffer, buffer_len);
393             }
394             else {
395 0           croak("FATAL: rsa_encrypt invalid padding '%s'", padding);
396             }
397             }
398             OUTPUT:
399             RETVAL
400              
401             SV *
402             decrypt(Crypt::PK::RSA self, SV * data, const char * padding = "oaep", const char * mgf_hash = "SHA1", SV * oaep_lparam = NULL, const char * lparam_hash = NULL)
403             CODE:
404             {
405             int rv, lparam_hash_id, mgf_hash_id, stat;
406 38           unsigned char *lparam_ptr=NULL;
407 38           STRLEN lparam_len=0;
408 38           unsigned char *data_ptr=NULL;
409 38           STRLEN data_len=0;
410             unsigned char buffer[1024];
411 38           unsigned long buffer_len = 1024;
412              
413 38           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
414              
415 38           RETVAL = newSVpvn(NULL, 0); /* undef */
416 38 100         if (strnEQ(padding, "oaep", 4)) {
417 1           mgf_hash_id = cryptx_internal_find_hash(mgf_hash);
418 1 50         if (mgf_hash_id == -1) croak("FATAL: find_hash failed for '%s'", mgf_hash);
419 1 50         if (lparam_hash) {
420 0           lparam_hash_id = cryptx_internal_find_hash(lparam_hash);
421 0 0         if (lparam_hash_id == -1) croak("FATAL: find_hash failed for '%s'", lparam_hash);
422             }
423             else {
424 1           lparam_hash_id = mgf_hash_id;
425             }
426 1 50         if (oaep_lparam) lparam_ptr = (unsigned char *)SvPVbyte(oaep_lparam, lparam_len);
427 1           rv = rsa_decrypt_key_ex(data_ptr, (unsigned long)data_len, buffer, &buffer_len, lparam_ptr, (unsigned long)lparam_len,
428 1           mgf_hash_id, lparam_hash_id, LTC_PKCS_1_OAEP, &stat, &self->key);
429 1 50         if (rv != CRYPT_OK) croak("FATAL: rsa_decrypt_key_ex failed: %s", error_to_string(rv));
430 1 50         if (stat != 1) croak("FATAL: rsa_decrypt - not valid OAEP packet");
431 1           RETVAL = newSVpvn((char*)buffer, buffer_len);
432             }
433 37 100         else if (strnEQ(padding, "v1.5", 4)) {
434 36           rv = rsa_decrypt_key_ex(data_ptr, (unsigned long)data_len, buffer, &buffer_len, NULL, 0,
435 36           0, -1, LTC_PKCS_1_V1_5, &stat, &self->key);
436 36 50         if (rv != CRYPT_OK) croak("FATAL: rsa_decrypt_key_ex failed: %s", error_to_string(rv));
437 36 50         if (stat != 1) croak("FATAL: rsa_decrypt - invalid");
438 36           RETVAL = newSVpvn((char*)buffer, buffer_len);
439             }
440 1 50         else if (strnEQ(padding, "none", 4)) {
441             /* raw RSA */
442 1           rv = ltc_mp.rsa_me(data_ptr, (unsigned long)data_len, buffer, &buffer_len, PK_PRIVATE, &self->key);
443 1 50         if (rv != CRYPT_OK) croak("FATAL: rsa_me failed: %s", error_to_string(rv));
444 1           RETVAL = newSVpvn((char*)buffer, buffer_len);
445             }
446             else {
447 0           croak("FATAL: rsa_encrypt invalid padding '%s'", padding);
448             }
449             }
450             OUTPUT:
451             RETVAL
452              
453             SV *
454             sign_hash(Crypt::PK::RSA self, SV * data, const char * hash_name = "SHA1", const char * padding = "pss", unsigned long saltlen=12)
455             ALIAS:
456             sign_message = 1
457             CODE:
458             {
459             int rv, hash_id;
460 4           unsigned char buffer[1024], tmp[MAXBLOCKSIZE], *data_ptr = NULL;
461 4           unsigned long tmp_len = MAXBLOCKSIZE, buffer_len = 1024;
462 4           STRLEN data_len = 0;
463              
464 4           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
465 4 100         if (ix == 1) {
466 2           hash_id = cryptx_internal_find_hash(hash_name);
467 2 50         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
468 2           rv = hash_memory(hash_id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
469 2 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
470 2           data_ptr = tmp;
471 2           data_len = tmp_len;
472             }
473 4 50         if (strnEQ(padding, "pss", 3)) {
474 4           hash_id = cryptx_internal_find_hash(hash_name);
475 4 50         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
476 4           rv = rsa_sign_hash_ex(data_ptr, (unsigned long)data_len, buffer, &buffer_len, LTC_PKCS_1_PSS,
477             &self->pstate, self->pindex,
478 4           hash_id, saltlen, &self->key);
479 4 50         if (rv != CRYPT_OK) croak("FATAL: rsa_sign_hash_ex failed: %s", error_to_string(rv));
480 4           RETVAL = newSVpvn((char*)buffer, buffer_len);
481             }
482 0 0         else if (strnEQ(padding, "v1.5", 4)) {
483 0           hash_id = cryptx_internal_find_hash(hash_name);
484 0 0         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
485 0           rv = rsa_sign_hash_ex(data_ptr, (unsigned long)data_len, buffer, &buffer_len, LTC_PKCS_1_V1_5,
486             &self->pstate, self->pindex,
487 0           hash_id, 0, &self->key);
488 0 0         if (rv != CRYPT_OK) croak("FATAL: rsa_sign_hash_ex failed: %s", error_to_string(rv));
489 0           RETVAL = newSVpvn((char*)buffer, buffer_len);
490             }
491 0 0         else if (strnEQ(padding, "none", 4)) {
492             /* raw RSA */
493 0           rv = ltc_mp.rsa_me(data_ptr, (unsigned long)data_len, buffer, &buffer_len, PK_PRIVATE, &self->key);
494 0 0         if (rv != CRYPT_OK) croak("FATAL: rsa_me failed: %s", error_to_string(rv));
495 0           RETVAL = newSVpvn((char*)buffer, buffer_len);
496             }
497             else {
498 0           croak("FATAL: rsa_sign invalid padding '%s'", padding);
499             }
500             }
501             OUTPUT:
502             RETVAL
503              
504             int
505             verify_hash(Crypt::PK::RSA self, SV * sig, SV * data, const char * hash_name = "SHA1", const char * padding = "pss", unsigned long saltlen = 12)
506             ALIAS:
507             verify_message = 1
508             CODE:
509             {
510             int rv, hash_id, stat;
511 109           unsigned char tmp[MAXBLOCKSIZE], buffer[1024], *data_ptr = NULL, *sig_ptr = NULL;
512 109           unsigned long i, tmp_len = MAXBLOCKSIZE, buffer_len = 1024;
513 109           STRLEN data_len = 0, sig_len = 0;
514              
515 109           data_ptr = (unsigned char *)SvPVbyte(data, data_len);
516 109           sig_ptr = (unsigned char *)SvPVbyte(sig, sig_len);
517 109 100         if (ix == 1) {
518 107           hash_id = cryptx_internal_find_hash(hash_name);
519 107 50         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
520 107           rv = hash_memory(hash_id, data_ptr, (unsigned long)data_len, tmp, &tmp_len);
521 107 50         if (rv != CRYPT_OK) croak("FATAL: hash_memory failed: %s", error_to_string(rv));
522 107           data_ptr = tmp;
523 107           data_len = tmp_len;
524             }
525 109           RETVAL = 1;
526 109           stat = 0;
527 109 100         if (strnEQ(padding, "pss", 3)) {
528 4           hash_id = cryptx_internal_find_hash(hash_name);
529 4 50         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
530 4           rv = rsa_verify_hash_ex(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, LTC_PKCS_1_PSS,
531 4           hash_id, saltlen, &stat, &self->key);
532 4 50         if (rv != CRYPT_OK || stat != 1) RETVAL = 0;
    50          
533             }
534 105 50         else if (strnEQ(padding, "v1.5", 4)) {
535 105           hash_id = cryptx_internal_find_hash(hash_name);
536 105 50         if (hash_id == -1) croak("FATAL: find_hash failed for '%s'", hash_name);
537 105           rv = rsa_verify_hash_ex(sig_ptr, (unsigned long)sig_len, data_ptr, (unsigned long)data_len, LTC_PKCS_1_V1_5,
538 105           hash_id, 0, &stat, &self->key);
539 105 100         if (rv != CRYPT_OK || stat != 1) RETVAL = 0;
    50          
540             }
541 0 0         else if (strnEQ(padding, "none", 4)) {
542             /* raw RSA */
543 0           Zero(buffer, buffer_len, unsigned char);
544 0           rv = ltc_mp.rsa_me(sig_ptr, (unsigned long)sig_len, buffer, &buffer_len, PK_PUBLIC, &self->key);
545 0 0         if (rv != CRYPT_OK) croak("FATAL: rsa_me failed: %s", error_to_string(rv));
546 0 0         if (data_len <= buffer_len && buffer_len > 0 && data_len > 0) {
    0          
    0          
547 0 0         for (i = 0; i < buffer_len - data_len; i++) if (buffer[i] != 0) RETVAL = 0;
    0          
548 0 0         if (memNE(data_ptr, buffer + buffer_len - data_len, data_len)) RETVAL = 0;
549             }
550             else {
551 0           RETVAL = 0;
552             }
553             }
554             else {
555 0           croak("FATAL: rsa_verify invalid padding '%s'", padding);
556             }
557             }
558             OUTPUT:
559             RETVAL
560              
561             void
562             DESTROY(Crypt::PK::RSA self)
563             CODE:
564 107 50         if (self->key.type != -1) { rsa_free(&self->key); self->key.type = -1; }
565 107           Safefree(self);