BeRTOS
x917.c
Go to the documentation of this file.
00001 
00038 #include "x917.h"
00039 #include <sec/util.h>
00040 #include <drv/timer.h>
00041 #include "hw/hw_timer.h"
00042 
00043 static void x917_next(X917Context *ctx, BlockCipher *cipher, uint8_t *out)
00044 {
00045     const size_t blen = cipher_block_len(cipher);
00046 
00047     struct
00048     {
00049         time_t t0;
00050         hptime_t t1;
00051         uint8_t padding[blen - sizeof(time_t) - sizeof(hptime_t)];
00052     } DT;
00053 
00054     ASSERT(sizeof(DT) == blen);
00055 
00056     memset(&DT, 0, sizeof(DT));
00057     DT.t0 = timer_clock();
00058     DT.t1 = timer_hw_hpread();
00059 
00060     cipher_ecb_encrypt(cipher, &DT);
00061 
00062     xor_block(out, (uint8_t*)&DT, ctx->state, blen);
00063     cipher_ecb_encrypt(cipher, out);
00064 
00065     xor_block(ctx->state, (uint8_t*)&DT, out, blen);
00066     cipher_ecb_encrypt(cipher, ctx->state);
00067 
00068     PURGE(DT);
00069 }
00070 
00071 
00072 static void x917_generate(PRNG *ctx_, uint8_t *data, size_t len)
00073 {
00074     X917Context *ctx = (X917Context *)ctx_;
00075     BlockCipher *cipher = AES128_stackinit();
00076 
00077     const size_t blen = cipher_block_len(cipher);
00078     uint8_t temp[blen];
00079 
00080     ASSERT(len);
00081     ASSERT(sizeof(ctx->state) >= blen);
00082     ASSERT(sizeof(ctx->key) >= cipher_key_len(cipher));
00083 
00084     cipher_set_key(cipher, ctx->key);
00085 
00086     while (len)
00087     {
00088         size_t L = MIN(blen, len);
00089         x917_next(ctx, cipher, temp);
00090         memcpy(data, temp, L);
00091         len -= L;
00092         data += L;
00093     }
00094 }
00095 
00096 static void x917_reseed(PRNG *ctx_, const uint8_t *seed)
00097 {
00098     // The X9.17 standard does not specify reseeding. To avoid external
00099     // dependencies, we implement it this way:
00100     //   * Generate a new random block, xor it with the first part
00101     //     of the seed, and use the result as new seed.
00102     //   * Generate and throw away a block to update the state.
00103     X917Context *ctx = (X917Context *)ctx_;
00104     const size_t klen = sizeof(ctx->key);
00105     const size_t blen = sizeof(ctx->state);
00106 
00107     if (!ctx->rng.seeded)
00108     {
00109         memcpy(ctx->key, seed, klen);
00110         memcpy(ctx->state, seed+klen, blen);
00111     }
00112     else
00113     {
00114         uint8_t buf[klen];
00115         x917_generate(ctx_, buf, klen);
00116 
00117         xor_block(ctx->key, buf, seed, klen);
00118         xor_block(ctx->state, ctx->state, seed+klen, blen);
00119 
00120         PURGE(buf);
00121     }
00122 }
00123 
00124 /*********************************************************************/
00125 
00126 void x917_init(X917Context *ctx)
00127 {
00128     ctx->rng.reseed = x917_reseed;
00129     ctx->rng.generate = x917_generate;
00130     ctx->rng.seed_len = sizeof(ctx->key) + sizeof(ctx->state);
00131     ctx->rng.seeded = 0;
00132 }