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