Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: MiniTLS-HTTPS-Example
crypto/crypto_rsa.c
- Committer:
- MiniTLS
- Date:
- 2014-06-06
- Revision:
- 0:35aa5be3b78d
File content as of revision 0:35aa5be3b78d:
/*
MuTLS - A super trimmed down TLS/SSL Library for embedded devices
Author: Donatien Garnier
Copyright (C) 2013-2014 AppNearMe Ltd
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*//**
* \file crypto_rsa.c
* \copyright Copyright (c) AppNearMe Ltd 2014
* \author Donatien Garnier
*/
#define __DEBUG__ 0
#ifndef __MODULE__
#define __MODULE__ "crypto_rsa.c"
#endif
#include "core/fwk.h"
#include "crypto_rsa.h"
#include "inc/mutls_errors.h"
#include "inc/mutls_config.h"
#include "crypto_math.h"
#include "ltc/ltc.h"
static mutls_err_t crypto_pkcs_1_v1_5_encode(const uint8_t* msg,
size_t msglen,
size_t modulus_bitlen,
crypto_prng_t* prng,
uint8_t* out,
size_t* outlen);
static mutls_err_t crypto_rsa_exptmod(const uint8_t* in, size_t inlen,
uint8_t *out, size_t* outlen,
crypto_rsa_public_key_t* key);
static mutls_err_t crypto_ecc_dsa_check_get_asn1_Ne(void* N, void* e, const uint8_t* key, size_t key_size);
mutls_err_t crypto_rsa_pkcs1_import(crypto_rsa_public_key_t* key, const uint8_t* pkcs1, size_t size)
{
int err;
/* init key */
if ((err = mp_init_multi(&key->e, &key->N, NULL)) != MUTLS_OK) {
return err;
}
if( (err = crypto_ecc_dsa_check_get_asn1_Ne(&key->N, &key->e, pkcs1, size)) != MUTLS_OK )
{
goto LBL_ERR;
}
return MUTLS_OK;
LBL_ERR:
mp_clear_multi(&key->e, &key->N, NULL);
return err;
}
mutls_err_t crypto_rsa_encrypt(const crypto_rsa_public_key_t* public_key,
uint8_t* plaintext, size_t plaintext_size,
uint8_t* secret, size_t max_secret_size, size_t* secret_size, crypto_prng_t* prng)
{
mutls_err_t ret;
/* get modulus len in bits */
size_t modulus_bitlen = mp_count_bits( (&public_key->N));
/* outlen must be at least the size of the modulus */
size_t modulus_bytelen = mp_unsigned_bin_size( (&public_key->N));
if (modulus_bytelen > max_secret_size) {
*secret_size = modulus_bytelen;
return MUTLS_ERR_BUFFER_TOO_SMALL;
}
//Apply padding
*secret_size = max_secret_size;
ret = crypto_pkcs_1_v1_5_encode(plaintext, plaintext_size, modulus_bitlen, prng, secret, secret_size);
if(ret)
{
return ret;
}
//Do the exponentiation
ret = crypto_rsa_exptmod(secret, *secret_size, secret, secret_size, public_key);
if(ret)
{
return ret;
}
return MUTLS_OK;
}
mutls_err_t crypto_rsa_exptmod(const uint8_t* in, size_t inlen,
uint8_t *out, size_t* outlen,
crypto_rsa_public_key_t* key)
{
fp_int tmp;
unsigned long x;
int err;
/* init and copy into tmp */
if ((err = mp_init_multi(&tmp, NULL)) != MUTLS_OK) { return err; }
mp_read_unsigned_bin(&tmp, (unsigned char *)in, (int)inlen);
/* sanity check on the input */
if (mp_cmp(&key->N, &tmp) == MP_LT) {
err = MUTLS_ERR_WRONG_LENGTH;
goto error;
}
/* exptmod it */
if ((err = mp_exptmod(&tmp, &key->e, &key->N, &tmp)) != MUTLS_OK) { goto error; }
/* read it back */
x = (unsigned long)mp_unsigned_bin_size(&key->N);
if (x > *outlen) {
*outlen = x;
err = MUTLS_ERR_BUFFER_TOO_SMALL;
goto error;
}
/* this should never happen ... */
if (mp_unsigned_bin_size(&tmp) > mp_unsigned_bin_size(&key->N)) {
err = MUTLS_ERR_CRYPTO;
goto error;
}
*outlen = x;
/* convert it */
zeromem(out, x);
mp_to_unsigned_bin(&tmp, out+(x-mp_unsigned_bin_size(&tmp)));
/* clean up and return */
err = MUTLS_OK;
error:
mp_clear_multi(&tmp, NULL);
return err;
}
mutls_err_t crypto_pkcs_1_v1_5_encode(const uint8_t* msg,
size_t msglen,
size_t modulus_bitlen,
crypto_prng_t* prng,
uint8_t* out,
size_t* outlen)
{
unsigned long modulus_len, ps_len, i;
unsigned char *ps;
int result;
modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
/* test message size */
if ((msglen + 11) > modulus_len) {
return MUTLS_ERR_WRONG_LENGTH;
}
if (*outlen < modulus_len) {
*outlen = modulus_len;
result = MUTLS_ERR_BUFFER_TOO_SMALL;
goto bail;
}
/* generate an octets string PS */
ps = &out[2];
ps_len = modulus_len - msglen - 3;
/* now choose a random ps */
crypto_prng_get(prng, ps, ps_len);
/* transform zero bytes (if any) to non-zero random bytes */
for (i = 0; i < ps_len; i++) {
while (ps[i] == 0) {
crypto_prng_get(prng, &ps[i], 1);
}
}
/* create string of length modulus_len */
out[0] = 0x00;
out[1] = 2; /* block_type is Block type 2 (LTC_PKCS #1 v1.5 encryption padding) */
out[2 + ps_len] = 0x00;
memcpy(&out[2 + ps_len + 1], msg, msglen);
*outlen = modulus_len;
result = MUTLS_OK;
bail:
return result;
}
//Decode (&N,&e) integers from ASN.1-encoded public key
#define ENSURE_SIZE(actual_size, min_size) do{ if( (actual_size) < (min_size) ) { return MUTLS_ERR_PARAMETERS; } }while(0)
mutls_err_t crypto_ecc_dsa_check_get_asn1_Ne(void* N, void* e, const uint8_t* key, size_t key_size)
{
const uint8_t* p = key;
size_t sz = key_size;
/* OpenSSL encoded keys have this format:
*
* SEQUENCE(2 elem)
* * SEQUENCE(2 elem)
* * * OBJECT IDENTIFIER1.2.840.113549.1.1.1
* * * NULL
* * BIT STRING(1 elem)
* * * SEQUENCE(2 elem)
* * * * INTEGER(1024 bit)
* * * * INTEGER 65537
*
*
*/
ENSURE_SIZE(sz, 1);
if( (p[0] != 0x30) && (p[0] != 0x31) ) //Sequence, SET types
{
return MUTLS_ERR_PARAMETERS;
}
p++;
sz--;
ENSURE_SIZE(sz, 1);
size_t seq_size;
//Get sequence length
if(*p < 0x80)
{
seq_size = p[0];
p++;
sz--;
}
else if(*p == 0x81)
{
ENSURE_SIZE(sz, 2);
seq_size = p[1];
p+=2;
sz-=2;
}
else if(*p == 0x82)
{
ENSURE_SIZE(sz, 3);
seq_size = (p[1] << 8) | p[2];
p+=3;
sz-=3;
}
else if(*p == 0x83)
{
ENSURE_SIZE(sz, 4);
seq_size = (p[1] << 16) | (p[2] << 8) | p[3];
p+=4;
sz-=4;
}
else if(*p == 0x84)
{
ENSURE_SIZE(sz, 5);
seq_size = (p[1] << 24) |(p[2] << 16) | (p[3] << 8) | p[4];
p+=5;
sz-=5;
}
else
{
return MUTLS_ERR_PARAMETERS;
}
//Check that sequence size == remaining bytes size
if( seq_size != sz )
{
return MUTLS_ERR_PARAMETERS;
}
//Read integers
for(int i = 0; i < 2; i++)
{
ENSURE_SIZE(sz, 1);
if( p[0] != 2 ) //Integer type
{
return MUTLS_ERR_PARAMETERS;
}
p++;
sz--;
ENSURE_SIZE(sz, 1);
size_t integer_size;
//Get sequence length
if(*p < 0x80)
{
integer_size = p[0];
p++;
sz--;
}
else if(*p == 0x81)
{
ENSURE_SIZE(sz, 2);
integer_size = p[1];
p+=2;
sz-=2;
}
else if(*p == 0x82)
{
ENSURE_SIZE(sz, 3);
integer_size = (p[1] << 8) | p[2];
p+=3;
sz-=3;
}
else if(*p == 0x83)
{
ENSURE_SIZE(sz, 4);
integer_size = (p[1] << 16) | (p[2] << 8) | p[3];
p+=4;
sz-=4;
}
else if(*p == 0x84)
{
ENSURE_SIZE(sz, 5);
integer_size = (p[1] << 24) |(p[2] << 16) | (p[3] << 8) | p[4];
p+=5;
sz-=5;
}
else
{
return MUTLS_ERR_PARAMETERS;
}
//Check that we have enough bytes remaining
ENSURE_SIZE(sz, integer_size);
DBG("Integer of size %d", integer_size);
//Read integer
void* integer = (i==0)?N:e;
/*int err;*/
/*if ((err = */mp_read_unsigned_bin(integer, (unsigned char *)p, integer_size);/*) != MUTLS_OK) {
return err;
}*/
p+=integer_size;
sz-=integer_size;
}
if(sz > 0)
{
//Unread parameters left in sequence
return MUTLS_ERR_PARAMETERS;
}
return MUTLS_OK;
}
