diff options
Diffstat (limited to 'networking/tls_rsa.c')
-rw-r--r-- | networking/tls_rsa.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/networking/tls_rsa.c b/networking/tls_rsa.c new file mode 100644 index 000000000..058b09cee --- /dev/null +++ b/networking/tls_rsa.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "tls.h" + +#define pkcs1Pad(in, inlen, out, outlen, cryptType, userPtr) \ + pkcs1Pad(in, inlen, out, outlen, cryptType) +static ///bbox +int32 pkcs1Pad(unsigned char *in, uint32 inlen, unsigned char *out, + uint32 outlen, int32 cryptType, void *userPtr) +{ + unsigned char *c; + int32 randomLen; + + randomLen = outlen - 3 - inlen; + if (randomLen < 8) { + psTraceCrypto("pkcs1Pad failure\n"); + return PS_LIMIT_FAIL; + } + c = out; + *c = 0x00; + c++; + *c = (unsigned char)cryptType; + c++; + if (cryptType == PUBKEY_TYPE) { + while (randomLen-- > 0) { + *c++ = 0xFF; + } + } else { + if (matrixCryptoGetPrngData(c, (uint32)randomLen, userPtr) < 0) { + return PS_PLATFORM_FAIL; + } +/* + SECURITY: Read through the random data and change all 0x0 to 0x01. + This is per spec that no random bytes should be 0 +*/ + while (randomLen-- > 0) { + if (*c == 0x0) { + *c = 0x01; + } + c++; + } + } + *c = 0x00; + c++; + memcpy(c, in, inlen); + + return outlen; +} + +#define psRsaCrypt(pool, in, inlen, out, outlen, key, type, data) \ + psRsaCrypt(pool, in, inlen, out, outlen, key, type) +static ///bbox +int32 psRsaCrypt(psPool_t *pool, const unsigned char *in, uint32 inlen, + unsigned char *out, uint32 *outlen, psRsaKey_t *key, int32 type, + void *data) +{ + pstm_int tmp, tmpa, tmpb; + int32 res; + uint32 x; + + if (in == NULL || out == NULL || outlen == NULL || key == NULL) { + psTraceCrypto("NULL parameter error in psRsaCrypt\n"); + return PS_ARG_FAIL; + } + + tmp.dp = tmpa.dp = tmpb.dp = NULL; + + /* Init and copy into tmp */ + if (pstm_init_for_read_unsigned_bin(pool, &tmp, inlen + sizeof(pstm_digit)) + != PS_SUCCESS) { + return PS_FAILURE; + } + if (pstm_read_unsigned_bin(&tmp, (unsigned char *)in, inlen) != PS_SUCCESS){ + pstm_clear(&tmp); + return PS_FAILURE; + } + /* Sanity check on the input */ + if (pstm_cmp(&key->N, &tmp) == PSTM_LT) { + res = PS_LIMIT_FAIL; + goto done; + } + if (type == PRIVKEY_TYPE) { + if (key->optimized) { + if (pstm_init_size(pool, &tmpa, key->p.alloc) != PS_SUCCESS) { + res = PS_FAILURE; + goto done; + } + if (pstm_init_size(pool, &tmpb, key->q.alloc) != PS_SUCCESS) { + pstm_clear(&tmpa); + res = PS_FAILURE; + goto done; + } + if (pstm_exptmod(pool, &tmp, &key->dP, &key->p, &tmpa) != + PS_SUCCESS) { + psTraceCrypto("decrypt error: pstm_exptmod dP, p\n"); + goto error; + } + if (pstm_exptmod(pool, &tmp, &key->dQ, &key->q, &tmpb) != + PS_SUCCESS) { + psTraceCrypto("decrypt error: pstm_exptmod dQ, q\n"); + goto error; + } + if (pstm_sub(&tmpa, &tmpb, &tmp) != PS_SUCCESS) { + psTraceCrypto("decrypt error: sub tmpb, tmp\n"); + goto error; + } + if (pstm_mulmod(pool, &tmp, &key->qP, &key->p, &tmp) != PS_SUCCESS) { + psTraceCrypto("decrypt error: pstm_mulmod qP, p\n"); + goto error; + } + if (pstm_mul_comba(pool, &tmp, &key->q, &tmp, NULL, 0) + != PS_SUCCESS){ + psTraceCrypto("decrypt error: pstm_mul q \n"); + goto error; + } + if (pstm_add(&tmp, &tmpb, &tmp) != PS_SUCCESS) { + psTraceCrypto("decrypt error: pstm_add tmp \n"); + goto error; + } + } else { + if (pstm_exptmod(pool, &tmp, &key->d, &key->N, &tmp) != + PS_SUCCESS) { + psTraceCrypto("psRsaCrypt error: pstm_exptmod\n"); + goto error; + } + } + } else if (type == PUBKEY_TYPE) { + if (pstm_exptmod(pool, &tmp, &key->e, &key->N, &tmp) != PS_SUCCESS) { + psTraceCrypto("psRsaCrypt error: pstm_exptmod\n"); + goto error; + } + } else { + psTraceCrypto("psRsaCrypt error: invalid type param\n"); + goto error; + } + /* Read it back */ + x = pstm_unsigned_bin_size(&key->N); + + if ((uint32)x > *outlen) { + res = -1; + psTraceCrypto("psRsaCrypt error: pstm_unsigned_bin_size\n"); + goto done; + } + /* We want the encrypted value to always be the key size. Pad with 0x0 */ + while ((uint32)x < (unsigned long)key->size) { + *out++ = 0x0; + x++; + } + + *outlen = x; + /* Convert it */ + memset(out, 0x0, x); + + if (pstm_to_unsigned_bin(pool, &tmp, out+(x-pstm_unsigned_bin_size(&tmp))) + != PS_SUCCESS) { + psTraceCrypto("psRsaCrypt error: pstm_to_unsigned_bin\n"); + goto error; + } + /* Clean up and return */ + res = PS_SUCCESS; + goto done; +error: + res = PS_FAILURE; +done: + if (type == PRIVKEY_TYPE && key->optimized) { + pstm_clear_multi(&tmpa, &tmpb, NULL, NULL, NULL, NULL, NULL, NULL); + } + pstm_clear(&tmp); + return res; +} + +int32 psRsaEncryptPub(psPool_t *pool, psRsaKey_t *key, + unsigned char *in, uint32 inlen, + unsigned char *out, uint32 outlen, void *data) +{ + int32 err; + uint32 size; + + size = key->size; + if (outlen < size) { + psTraceCrypto("Error on bad outlen parameter to psRsaEncryptPub\n"); + return PS_ARG_FAIL; + } + + if ((err = pkcs1Pad(in, inlen, out, size, PRIVKEY_TYPE, data)) + < PS_SUCCESS) { + psTraceCrypto("Error padding psRsaEncryptPub. Likely data too long\n"); + return err; + } + if ((err = psRsaCrypt(pool, out, size, out, (uint32*)&outlen, key, + PUBKEY_TYPE, data)) < PS_SUCCESS) { + psTraceCrypto("Error performing psRsaEncryptPub\n"); + return err; + } + if (outlen != size) { + psTraceCrypto("Encrypted size error in psRsaEncryptPub\n"); + return PS_FAILURE; + } + return size; +} |