Skip to content

Commit c7e3d73

Browse files
committed
FEAT: optional definition of the message digest algorithm to sign/verify data using rsa
1 parent 73c731b commit c7e3d73

File tree

4 files changed

+97
-25
lines changed

4 files changed

+97
-25
lines changed

src/boot/words.reb

+1-1
Original file line numberDiff line numberDiff line change
@@ -201,12 +201,12 @@ crc24
201201
crc32
202202
md4
203203
md5
204-
ripemd160
205204
sha1
206205
sha224
207206
sha256
208207
sha384
209208
sha512
209+
ripemd160
210210

211211
; Codec actions
212212
identify

src/core/n-crypt.c

+31-11
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,11 @@ static int myrand(void *rng_state, unsigned char *output, size_t len)
308308
// data [binary! none!] "Data to work with. Use NONE to release the RSA handle resources!"
309309
// /encrypt "Use public key to encrypt data"
310310
// /decrypt "Use private key to decrypt data"
311-
// /sign "Use private key to sign data"
311+
// /sign "Use private key to sign data. Result is PKCS1 v1.5 binary"
312312
// /verify "Use public key to verify signed data (returns TRUE or FALSE)"
313-
// signature [binary!] "Result of the sign call"
313+
// signature [binary!] "Result of the /sign call"
314+
// /hash "Signature's message digest algorithm"
315+
// algorithm [word!] "Default value is SHA256"
314316
// ]
315317
***********************************************************************/
316318
{
@@ -324,20 +326,23 @@ static int myrand(void *rng_state, unsigned char *output, size_t len)
324326
REBOOL refSign = D_REF(5);
325327
REBOOL refVerify = D_REF(6);
326328
REBVAL *val_sign = D_ARG(7);
329+
REBOOL refHash = D_REF(8);
330+
REBVAL *val_hash = D_ARG(9);
327331

328332
RSA_CTX *rsa;
329333
REBSER *data;
330334
REBYTE *inBinary;
331335
REBYTE *outBinary;
332-
REBYTE hash[32];
336+
REBYTE hash[64];
333337
REBINT inBytes;
334338
REBINT outBytes;
335339
REBINT err = 0;
340+
mbedtls_md_type_t md_alg;
336341

337342
// make sure that only one refinement is used!
338343
if(
339-
(refEncrypt && (refDecrypt || refSign || refVerify)) ||
340-
(refDecrypt && (refEncrypt || refSign || refVerify)) ||
344+
(refEncrypt && (refDecrypt || refSign || refVerify || refHash)) ||
345+
(refDecrypt && (refEncrypt || refSign || refVerify || refHash)) ||
341346
(refSign && (refDecrypt || refEncrypt || refVerify)) ||
342347
(refVerify && (refDecrypt || refSign || refEncrypt))
343348
) {
@@ -365,10 +370,26 @@ static int myrand(void *rng_state, unsigned char *output, size_t len)
365370
inBinary = BIN_DATA(data);
366371
inBytes = BIN_LEN(data);
367372

368-
if (refVerify) {
369-
SHA256(inBinary, inBytes, hash);
370-
err = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsa, MBEDTLS_MD_SHA256, 32, hash, VAL_BIN(val_sign));
371-
return (err == 0) ? R_TRUE : R_FALSE;
373+
if (refVerify || refSign) {
374+
if (IS_NONE(val_hash)) {
375+
md_alg = MBEDTLS_MD_NONE;
376+
}
377+
else {
378+
// count message digest off the input data
379+
if (Message_Digest(hash, inBinary, inBytes, VAL_WORD_CANON(val_hash), &inBytes)) {
380+
// map Rebol word to mbedtls_md_type_t (expets that have same order!)
381+
// no need to test a range as only known will pass above run
382+
md_alg = VAL_WORD_CANON(val_hash) - SYM_MD5 + 1;
383+
inBinary = hash;
384+
}
385+
else {
386+
return R_NONE;
387+
}
388+
}
389+
if (refVerify) {
390+
err = mbedtls_rsa_rsassa_pkcs1_v15_verify(rsa, md_alg, inBytes, inBinary, VAL_BIN(val_sign));
391+
return (err == 0) ? R_TRUE : R_FALSE;
392+
}
372393
}
373394

374395
//allocate new binary!
@@ -377,8 +398,7 @@ static int myrand(void *rng_state, unsigned char *output, size_t len)
377398
outBinary = BIN_DATA(data);
378399

379400
if (refSign) {
380-
SHA256(inBinary, inBytes, hash);
381-
err = mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa, mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_MD_SHA256, 32, hash, outBinary);
401+
err = mbedtls_rsa_rsassa_pkcs1_v15_sign(rsa, mbedtls_ctr_drbg_random, &ctr_drbg, md_alg, inBytes, inBinary, outBinary);
382402
}
383403
else if (refEncrypt) {
384404
err = mbedtls_rsa_rsaes_pkcs1_v15_encrypt(rsa, mbedtls_ctr_drbg_random, &ctr_drbg, inBytes, inBinary, outBinary);

src/core/n-strings.c

+52
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,58 @@ static struct digest {
7070
};
7171

7272

73+
/***********************************************************************
74+
**
75+
*/ REBOOL *Message_Digest(REBYTE *output, REBYTE *input, REBCNT length, REBCNT method, REBCNT *olen)
76+
/*
77+
***********************************************************************/
78+
{
79+
switch (method) {
80+
case SYM_MD5:
81+
MD5(input, length, output);
82+
*olen = 16;
83+
break;
84+
case SYM_SHA1:
85+
SHA1(input, length, output);
86+
*olen = 20;
87+
break;
88+
case SYM_SHA256:
89+
SHA256(input, length, output);
90+
*olen = 32;
91+
break;
92+
case SYM_SHA224:
93+
SHA224(input, length, output);
94+
*olen = 28;
95+
break;
96+
case SYM_SHA512:
97+
SHA512(input, length, output);
98+
*olen = 64;
99+
break;
100+
#ifdef INCLUDE_SHA384
101+
case SYM_SHA384:
102+
SHA384(input, length, output);
103+
*olen = 48;
104+
break;
105+
#endif
106+
#ifdef INCLUDE_RIPEMD160
107+
case SYM_RIPEMD160:
108+
RIPEMD160(input, length, output);
109+
*olen = 20;
110+
break;
111+
#endif
112+
#ifdef INCLUDE_MD4
113+
case SYM_MD4:
114+
MD4(input, length, output);
115+
*olen = 16;
116+
break;
117+
#endif
118+
default:
119+
return FALSE;
120+
}
121+
return TRUE;
122+
}
123+
124+
73125
/***********************************************************************
74126
**
75127
*/ REBNATIVE(ajoin)

src/tests/units/rsa-test.r3

+13-13
Original file line numberDiff line numberDiff line change
@@ -89,36 +89,36 @@ Rebol [
8989

9090
--test-- "RSA verification"
9191
;you can use both keys for verification (only the public parts are used)
92-
--assert true? rsa/verify key-pub bin-data sign-hash
93-
--assert true? rsa/verify key-pri bin-data sign-hash
92+
--assert rsa/verify key-pub bin-data sign-hash
93+
--assert rsa/verify key-pri bin-data sign-hash
9494

9595
--test-- "RSA key release"
9696
;once RSA key is not needed, release the resources using NONE data
9797
--assert rsa key-pub none
9898
--assert rsa key-pri none
99+
; released handle is now unusable:
100+
--assert error? try [rsa/verify/hash key-pub bin-data signature 'SHA512]
99101

100102
===end-group===
101103

102104

103105
===start-group=== "RSA initialization using codecs"
104106
--test-- "RSA sign/verify using external file"
105107
; Bob has data, which wants to sign, so it's clear, that nobody modifies them
106-
data: "Hello!"
107-
; As RSA is slow, it is used on hashes.. for example SHA1
108-
hash: checksum data 'sha1
108+
data: read %units/files/apiserver.crt
109109
; Bob uses private key which keeps secret...
110110
--assert handle? try [private-key: load %units/files/rebol-private-no-pass.ppk]
111-
; .. to sign the hash..
112-
--assert binary? signed-hash: rsa/sign private-key hash
111+
; .. and signs data with specified message digest algorithm
112+
--assert binary? signature: rsa/sign/hash private-key data 'SHA512
113113

114-
; than sends data, and signed hash to Eve, who have his public key
114+
; than sends data and its signature to Eve, who have his public key, even using some unsecure way
115115
--assert handle? try [public-key: load %units/files/rebol-public.ppk]
116-
; Eve uses the key to verify the checksum...
117-
--assert true? rsa/verify public-key (checksum data 'sha1) signed-hash
118-
; so she know, that data were not modified
116+
; Eve uses the key to verify the received data using its signature and hash
117+
--assert rsa/verify/hash public-key data signature 'SHA512
118+
; so she knows, that data were not modified
119119

120-
; cleanup:
121-
rsa public-key none
120+
; used keys should be released by GC, when not referenced, but we can release them immediately:
121+
rsa public-key none
122122
rsa private-key none
123123
===end-group===
124124

0 commit comments

Comments
 (0)