ARM Shanghai IoT Team (Internal) / newMiniTLS-GPL

Fork of MiniTLS-GPL by Donatien Garnier

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers crypto_rsa.c Source File

crypto_rsa.c

Go to the documentation of this file.
00001 /*
00002 MiniTLS - A super trimmed down TLS/SSL Library for embedded devices
00003 Author: Donatien Garnier
00004 Copyright (C) 2013-2014 AppNearMe Ltd
00005 
00006 This program is free software; you can redistribute it and/or
00007 modify it under the terms of the GNU General Public License
00008 as published by the Free Software Foundation; either version 2
00009 of the License, or (at your option) any later version.
00010 
00011 This program is distributed in the hope that it will be useful,
00012 but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014 GNU General Public License for more details.
00015 
00016 You should have received a copy of the GNU General Public License
00017 along with this program; if not, write to the Free Software
00018 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00019 *//**
00020  * \file crypto_rsa.c
00021  * \copyright Copyright (c) AppNearMe Ltd 2014
00022  * \author Donatien Garnier
00023  */
00024 
00025 #define __DEBUG__ 0
00026 #ifndef __MODULE__
00027 #define __MODULE__ "crypto_rsa.c"
00028 #endif
00029 
00030 #include "core/fwk.h"
00031 #include "crypto_rsa.h"
00032 #include "inc/minitls_errors.h"
00033 #include "inc/minitls_config.h"
00034 
00035 #include "crypto_math.h"
00036 #include "ltc/ltc.h"
00037 
00038 static minitls_err_t crypto_pkcs_1_v1_5_encode(const uint8_t* msg,
00039     size_t  msglen,
00040     size_t  modulus_bitlen,
00041     crypto_prng_t* prng,
00042     uint8_t* out,
00043     size_t* outlen);
00044 static minitls_err_t crypto_rsa_exptmod(const uint8_t* in, size_t inlen,
00045     uint8_t *out, size_t* outlen,
00046     crypto_rsa_public_key_t* key);
00047 static minitls_err_t crypto_ecc_dsa_check_get_asn1_Ne(void* N, void* e, const uint8_t* key, size_t key_size);
00048 
00049 minitls_err_t crypto_rsa_pkcs1_import(crypto_rsa_public_key_t* key, const uint8_t* pkcs1, size_t size)
00050 {
00051   int           err;
00052 
00053   /* init key */
00054   if ((err = mp_init_multi(&key->e, &key->N, NULL)) != MINITLS_OK) {
00055      return err;
00056   }
00057 
00058   if( (err = crypto_ecc_dsa_check_get_asn1_Ne(&key->N, &key->e, pkcs1, size)) != MINITLS_OK )
00059   {
00060     goto LBL_ERR;
00061   }
00062 
00063   return MINITLS_OK;
00064 LBL_ERR:
00065   mp_clear_multi(&key->e, &key->N, NULL);
00066   return err;
00067 }
00068 
00069 minitls_err_t crypto_rsa_encrypt(const crypto_rsa_public_key_t* public_key,
00070     uint8_t* plaintext, size_t plaintext_size,
00071     uint8_t* secret, size_t max_secret_size, size_t* secret_size, crypto_prng_t* prng)
00072 {
00073   minitls_err_t ret;
00074 
00075   /* get modulus len in bits */
00076   size_t modulus_bitlen = mp_count_bits( (&public_key->N));
00077 
00078   /* outlen must be at least the size of the modulus */
00079   size_t modulus_bytelen = mp_unsigned_bin_size( (&public_key->N));
00080   if (modulus_bytelen > max_secret_size) {
00081     WARN("modulus_bytelen = %d but max_secret_size = %d", modulus_bytelen, max_secret_size);
00082      *secret_size = modulus_bytelen;
00083      return MINITLS_ERR_BUFFER_TOO_SMALL;
00084   }
00085 
00086   //Apply padding
00087   *secret_size = max_secret_size;
00088   ret = crypto_pkcs_1_v1_5_encode(plaintext, plaintext_size, modulus_bitlen, prng, secret, secret_size);
00089   if(ret)
00090   {
00091     return ret;
00092   }
00093 
00094   //Do the exponentiation
00095   ret = crypto_rsa_exptmod(secret, *secret_size, secret, secret_size, public_key);
00096   if(ret)
00097   {
00098     return ret;
00099   }
00100 
00101   return MINITLS_OK;
00102 }
00103 
00104 minitls_err_t crypto_rsa_exptmod(const uint8_t* in, size_t inlen,
00105                       uint8_t *out, size_t* outlen,
00106                       crypto_rsa_public_key_t* key)
00107 {
00108    fp_int        tmp;
00109    unsigned long x;
00110    int           err;
00111 
00112    /* init and copy into tmp */
00113    if ((err = mp_init_multi(&tmp, NULL)) != MINITLS_OK)                                    { return err; }
00114    mp_read_unsigned_bin(&tmp, (unsigned char *)in, (int)inlen);
00115 
00116    /* sanity check on the input */
00117    if (mp_cmp(&key->N, &tmp) == MP_LT) {
00118       err = MINITLS_ERR_WRONG_LENGTH;
00119       goto error;
00120    }
00121 
00122    /* exptmod it */
00123    if ((err = mp_exptmod(&tmp, &key->e, &key->N, &tmp)) != MINITLS_OK)                                { goto error; }
00124 
00125    /* read it back */
00126    x = (unsigned long)mp_unsigned_bin_size(&key->N);
00127    if (x > *outlen) {
00128       *outlen = x;
00129       err = MINITLS_ERR_BUFFER_TOO_SMALL;
00130       goto error;
00131    }
00132 
00133    /* this should never happen ... */
00134    if (mp_unsigned_bin_size(&tmp) > mp_unsigned_bin_size(&key->N)) {
00135       err = MINITLS_ERR_CRYPTO;
00136       goto error;
00137    }
00138    *outlen = x;
00139 
00140    /* convert it */
00141    zeromem(out, x);
00142    mp_to_unsigned_bin(&tmp, out+(x-mp_unsigned_bin_size(&tmp)));
00143 
00144    /* clean up and return */
00145    err = MINITLS_OK;
00146 error:
00147    mp_clear_multi(&tmp, NULL);
00148    return err;
00149 }
00150 
00151 minitls_err_t crypto_pkcs_1_v1_5_encode(const uint8_t* msg,
00152                              size_t  msglen,
00153                              size_t  modulus_bitlen,
00154                              crypto_prng_t* prng,
00155                              uint8_t* out,
00156                              size_t* outlen)
00157 {
00158   unsigned long modulus_len, ps_len, i;
00159   unsigned char *ps;
00160   int result;
00161 
00162   modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
00163 
00164   /* test message size */
00165   if ((msglen + 11) > modulus_len) {
00166     return MINITLS_ERR_WRONG_LENGTH;
00167   }
00168 
00169   if (*outlen < modulus_len) {
00170     *outlen = modulus_len;
00171     result = MINITLS_ERR_BUFFER_TOO_SMALL;
00172     goto bail;
00173   }
00174 
00175   /* generate an octets string PS */
00176   ps = &out[2];
00177   ps_len = modulus_len - msglen - 3;
00178 
00179 
00180   /* now choose a random ps */
00181   crypto_prng_get(prng, ps, ps_len);
00182 
00183   /* transform zero bytes (if any) to non-zero random bytes */
00184   for (i = 0; i < ps_len; i++) {
00185     while (ps[i] == 0) {
00186       crypto_prng_get(prng, &ps[i], 1);
00187     }
00188   }
00189 
00190   /* create string of length modulus_len */
00191   out[0]          = 0x00;
00192   out[1]          = 2;  /* block_type is Block type 2 (LTC_PKCS #1 v1.5 encryption padding) */
00193   out[2 + ps_len] = 0x00;
00194   memcpy(&out[2 + ps_len + 1], msg, msglen);
00195   *outlen = modulus_len;
00196 
00197   result  = MINITLS_OK;
00198 bail:
00199   return result;
00200 }
00201 
00202 
00203 //Decode (&N,&e) integers from ASN.1-encoded public key
00204 #define ENSURE_SIZE(actual_size, min_size) do{ if( (actual_size) < (min_size) ) { return MINITLS_ERR_PARAMETERS; } }while(0)
00205 minitls_err_t crypto_ecc_dsa_check_get_asn1_Ne(void* N, void* e, const uint8_t* key, size_t key_size)
00206 {
00207   const uint8_t* p = key;
00208   size_t sz = key_size;
00209 
00210   /* OpenSSL encoded keys have this format:
00211    *
00212    * SEQUENCE(2 elem)
00213    * * SEQUENCE(2 elem)
00214    * * * OBJECT IDENTIFIER1.2.840.113549.1.1.1
00215    * * * NULL
00216    * * BIT STRING(1 elem)
00217    * * * SEQUENCE(2 elem)
00218    * * * * INTEGER(1024 bit)
00219    * * * * INTEGER 65537
00220    *
00221    *
00222    */
00223 
00224 
00225 
00226 
00227   ENSURE_SIZE(sz, 1);
00228 
00229   if( (p[0] != 0x30) && (p[0] != 0x31) ) //Sequence, SET types
00230   {
00231     return MINITLS_ERR_PARAMETERS;
00232   }
00233 
00234   p++;
00235   sz--;
00236 
00237   ENSURE_SIZE(sz, 1);
00238 
00239   size_t seq_size;
00240   //Get sequence length
00241   if(*p < 0x80)
00242   {
00243     seq_size = p[0];
00244     p++;
00245     sz--;
00246   }
00247   else if(*p == 0x81)
00248   {
00249     ENSURE_SIZE(sz, 2);
00250     seq_size = p[1];
00251     p+=2;
00252     sz-=2;
00253   }
00254   else if(*p == 0x82)
00255   {
00256     ENSURE_SIZE(sz, 3);
00257     seq_size = (p[1] << 8) | p[2];
00258     p+=3;
00259     sz-=3;
00260   }
00261   else if(*p == 0x83)
00262   {
00263     ENSURE_SIZE(sz, 4);
00264     seq_size = (p[1] << 16) | (p[2] << 8) | p[3];
00265     p+=4;
00266     sz-=4;
00267   }
00268   else if(*p == 0x84)
00269   {
00270     ENSURE_SIZE(sz, 5);
00271     seq_size = (p[1] << 24) |(p[2] << 16) | (p[3] << 8) | p[4];
00272     p+=5;
00273     sz-=5;
00274   }
00275   else
00276   {
00277     return MINITLS_ERR_PARAMETERS;
00278   }
00279 
00280   //Check that sequence size == remaining bytes size
00281   if( seq_size != sz )
00282   {
00283     return MINITLS_ERR_PARAMETERS;
00284   }
00285 
00286   //Read integers
00287   for(int i = 0; i < 2; i++)
00288   {
00289     ENSURE_SIZE(sz, 1);
00290 
00291     if( p[0] != 2 ) //Integer type
00292     {
00293       return MINITLS_ERR_PARAMETERS;
00294     }
00295 
00296     p++;
00297     sz--;
00298 
00299     ENSURE_SIZE(sz, 1);
00300 
00301     size_t integer_size;
00302     //Get sequence length
00303     if(*p < 0x80)
00304     {
00305       integer_size = p[0];
00306       p++;
00307       sz--;
00308     }
00309     else if(*p == 0x81)
00310     {
00311       ENSURE_SIZE(sz, 2);
00312       integer_size = p[1];
00313       p+=2;
00314       sz-=2;
00315     }
00316     else if(*p == 0x82)
00317     {
00318       ENSURE_SIZE(sz, 3);
00319       integer_size = (p[1] << 8) | p[2];
00320       p+=3;
00321       sz-=3;
00322     }
00323     else if(*p == 0x83)
00324     {
00325       ENSURE_SIZE(sz, 4);
00326       integer_size = (p[1] << 16) | (p[2] << 8) | p[3];
00327       p+=4;
00328       sz-=4;
00329     }
00330     else if(*p == 0x84)
00331     {
00332       ENSURE_SIZE(sz, 5);
00333       integer_size = (p[1] << 24) |(p[2] << 16) | (p[3] << 8) | p[4];
00334       p+=5;
00335       sz-=5;
00336     }
00337     else
00338     {
00339       return MINITLS_ERR_PARAMETERS;
00340     }
00341 
00342     //Check that we have enough bytes remaining
00343     ENSURE_SIZE(sz, integer_size);
00344 
00345     DBG("Integer of size %d", integer_size);
00346 
00347     //Read integer
00348     void* integer = (i==0)?N:e;
00349 
00350     /*int err;*/
00351     /*if ((err = */mp_read_unsigned_bin(integer, (unsigned char *)p, integer_size);/*) != MINITLS_OK) {
00352        return err;
00353     }*/
00354 
00355     p+=integer_size;
00356     sz-=integer_size;
00357   }
00358 
00359   if(sz > 0)
00360   {
00361     //Unread parameters left in sequence
00362     return MINITLS_ERR_PARAMETERS;
00363   }
00364 
00365   return MINITLS_OK;
00366 }
00367