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
Diff: crypto/crypto_rsa.c
- Revision:
- 0:35aa5be3b78d
diff -r 000000000000 -r 35aa5be3b78d crypto/crypto_rsa.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/crypto/crypto_rsa.c Fri Jun 06 10:49:02 2014 +0000
@@ -0,0 +1,366 @@
+/*
+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;
+}
+
