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_prng.c Source File

crypto_prng.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_prng.c
00021  * \copyright Copyright (c) AppNearMe Ltd 2013
00022  * \author Donatien Garnier
00023  */
00024 
00025 #define __DEBUG__ 0//4
00026 #ifndef __MODULE__
00027 #define __MODULE__ "crypto_prng.c"
00028 #endif
00029 
00030 #include "core/fwk.h"
00031 #include "inc/minitls_errors.h"
00032 #include "crypto_prng.h"
00033 
00034 #include "crypto_aes_128.h"
00035 #include "crypto_sha1.h"
00036 
00037 #define YARROW_REGENERATE_VALUE 10
00038 
00039 static void crypto_prng_update_internal(crypto_prng_t* prng);
00040 
00041 void crypto_prng_init(crypto_prng_t* prng, rtos_mtx_t* mtx)
00042 {
00043   memset(prng->pool, 0, SHA1_SIZE);
00044   prng->counter = 0xFFFFFFFFUL; //Will force update
00045   prng->mtx = mtx;
00046   prng->buf_pos = AES_128_BLOCK_SIZE; //invalidate buffer
00047   prng->fed = false;
00048 }
00049 
00050 #define LOCK() do{ if(prng->mtx) { rtos_mtx_lock(prng->mtx); } }while(0)
00051 #define UNLOCK() do{ if(prng->mtx) { rtos_mtx_unlock(prng->mtx); } }while(0)
00052 
00053 void crypto_prng_feed(crypto_prng_t* prng, uint8_t* data, size_t size)
00054 {
00055   LOCK();
00056   //Update pool
00057   crypto_sha1_t hash;
00058   crypto_sha1_init(&hash);
00059   crypto_sha1_update(&hash, prng->pool, SHA1_SIZE);
00060   crypto_sha1_update(&hash, data, size);
00061   crypto_sha1_end(&hash, prng->pool);
00062   prng->fed = true;
00063   UNLOCK();
00064 }
00065 
00066 void crypto_prng_update_internal(crypto_prng_t* prng)
00067 {
00068   if(!prng->fed)
00069   {
00070     //Rehash the pool to "rotate" key
00071     crypto_sha1_t hash;
00072     crypto_sha1_init(&hash);
00073     crypto_sha1_update(&hash, prng->pool, SHA1_SIZE);
00074     crypto_sha1_end(&hash, prng->pool);
00075   }
00076   prng->fed = false;
00077   //Generate key from pool
00078   crypto_aes_128_init(&prng->cipher, prng->pool, expand_encryption_key); //OK because AES_128_BLOCK_SIZE < SHA1_SIZE
00079   prng->counter = 0;
00080 }
00081 
00082 void crypto_prng_update(crypto_prng_t* prng)
00083 {
00084   LOCK();
00085   crypto_prng_update_internal(prng);
00086   UNLOCK();
00087 }
00088 
00089 void crypto_prng_get(crypto_prng_t* prng, uint8_t* data, size_t size)
00090 {
00091   LOCK();
00092 
00093   //Regenerate data as needed
00094   while(size > 0)
00095   {
00096     if(prng->counter > YARROW_REGENERATE_VALUE)
00097     {
00098       crypto_prng_update_internal(prng);
00099     }
00100 
00101     //Copy any remaining data from buffer
00102     size_t cpy_size = MIN(size, AES_128_BLOCK_SIZE - prng->buf_pos);
00103     memcpy(data, prng->buf + prng->buf_pos, cpy_size);
00104     data += cpy_size;
00105     size -= cpy_size;
00106     prng->buf_pos += cpy_size;
00107 
00108     if(prng->buf_pos >= AES_128_BLOCK_SIZE)
00109     {
00110       memset(prng->buf + sizeof(uint32_t), 0, AES_128_BLOCK_SIZE - sizeof(uint32_t));
00111       memcpy(prng->buf, &prng->counter, sizeof(uint32_t)); //We do not care about endianness as long as it's consistent (don't know of any system which would swap endianness during the execution of a program...)
00112       crypto_aes_128_encrypt(&prng->cipher, prng->buf, prng->buf);
00113       prng->counter++;
00114       prng->buf_pos = 0;
00115     }
00116   }
00117 
00118   UNLOCK();
00119 }
00120 
00121