Home | History | Annotate | Download | only in chc
      1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
      2  *
      3  * LibTomCrypt is a library that provides various cryptographic
      4  * algorithms in a highly modular and flexible manner.
      5  *
      6  * The library is free for all purposes without any express
      7  * guarantee it works.
      8  *
      9  * Tom St Denis, tomstdenis (at) gmail.com, http://libtomcrypt.com
     10  */
     11 
     12 #include "tomcrypt.h"
     13 
     14 /**
     15   @file chc.c
     16   CHC support. (Tom St Denis)
     17 */
     18 
     19 #ifdef CHC_HASH
     20 
     21 #define UNDEFED_HASH  -17
     22 
     23 /* chc settings */
     24 static int            cipher_idx=UNDEFED_HASH,        /* which cipher */
     25                       cipher_blocksize;               /* blocksize of cipher */
     26 
     27 
     28 const struct ltc_hash_descriptor chc_desc = {
     29    "chc_hash", 12, 0, 0, { 0 }, 0,
     30    &chc_init,
     31    &chc_process,
     32    &chc_done,
     33    &chc_test,
     34    NULL
     35 };
     36 
     37 /**
     38   Initialize the CHC state with a given cipher
     39   @param cipher  The index of the cipher you wish to bind
     40   @return CRYPT_OK if successful
     41 */
     42 int chc_register(int cipher)
     43 {
     44    int err, kl, idx;
     45 
     46    if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
     47       return err;
     48    }
     49 
     50    /* will it be valid? */
     51    kl = cipher_descriptor[cipher].block_length;
     52 
     53    /* must be >64 bit block */
     54    if (kl <= 8) {
     55       return CRYPT_INVALID_CIPHER;
     56    }
     57 
     58    /* can we use the ideal keysize? */
     59    if ((err = cipher_descriptor[cipher].keysize(&kl)) != CRYPT_OK) {
     60       return err;
     61    }
     62    /* we require that key size == block size be a valid choice */
     63    if (kl != cipher_descriptor[cipher].block_length) {
     64       return CRYPT_INVALID_CIPHER;
     65    }
     66 
     67    /* determine if chc_hash has been register_hash'ed already */
     68    if ((err = hash_is_valid(idx = find_hash("chc_hash"))) != CRYPT_OK) {
     69       return err;
     70    }
     71 
     72    /* store into descriptor */
     73    hash_descriptor[idx].hashsize  =
     74    hash_descriptor[idx].blocksize = cipher_descriptor[cipher].block_length;
     75 
     76    /* store the idx and block size */
     77    cipher_idx       = cipher;
     78    cipher_blocksize = cipher_descriptor[cipher].block_length;
     79    return CRYPT_OK;
     80 }
     81 
     82 /**
     83    Initialize the hash state
     84    @param md   The hash state you wish to initialize
     85    @return CRYPT_OK if successful
     86 */
     87 int chc_init(hash_state *md)
     88 {
     89    symmetric_key *key;
     90    unsigned char  buf[MAXBLOCKSIZE];
     91    int            err;
     92 
     93    LTC_ARGCHK(md != NULL);
     94 
     95    /* is the cipher valid? */
     96    if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
     97       return err;
     98    }
     99 
    100    if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) {
    101       return CRYPT_INVALID_CIPHER;
    102    }
    103 
    104    if ((key = XMALLOC(sizeof(*key))) == NULL) {
    105       return CRYPT_MEM;
    106    }
    107 
    108    /* zero key and what not */
    109    zeromem(buf, cipher_blocksize);
    110    if ((err = cipher_descriptor[cipher_idx].setup(buf, cipher_blocksize, 0, key)) != CRYPT_OK) {
    111       XFREE(key);
    112       return err;
    113    }
    114 
    115    /* encrypt zero block */
    116    cipher_descriptor[cipher_idx].ecb_encrypt(buf, md->chc.state, key);
    117 
    118    /* zero other members */
    119    md->chc.length = 0;
    120    md->chc.curlen = 0;
    121    zeromem(md->chc.buf, sizeof(md->chc.buf));
    122    XFREE(key);
    123    return CRYPT_OK;
    124 }
    125 
    126 /*
    127    key    <= state
    128    T0,T1  <= block
    129    T0     <= encrypt T0
    130    state  <= state xor T0 xor T1
    131 */
    132 static int chc_compress(hash_state *md, unsigned char *buf)
    133 {
    134    unsigned char  T[2][MAXBLOCKSIZE];
    135    symmetric_key *key;
    136    int            err, x;
    137 
    138    if ((key = XMALLOC(sizeof(*key))) == NULL) {
    139       return CRYPT_MEM;
    140    }
    141    if ((err = cipher_descriptor[cipher_idx].setup(md->chc.state, cipher_blocksize, 0, key)) != CRYPT_OK) {
    142       XFREE(key);
    143       return err;
    144    }
    145    XMEMCPY(T[1], buf, cipher_blocksize);
    146    cipher_descriptor[cipher_idx].ecb_encrypt(buf, T[0], key);
    147    for (x = 0; x < cipher_blocksize; x++) {
    148        md->chc.state[x] ^= T[0][x] ^ T[1][x];
    149    }
    150    XFREE(key);
    151 #ifdef LTC_CLEAN_STACK
    152    zeromem(T, sizeof(T));
    153    zeromem(&key, sizeof(key));
    154 #endif
    155    return CRYPT_OK;
    156 }
    157 
    158 /* function for processing blocks */
    159 int _chc_process(hash_state * md, const unsigned char *buf, unsigned long len);
    160 HASH_PROCESS(_chc_process, chc_compress, chc, (unsigned long)cipher_blocksize)
    161 
    162 /**
    163    Process a block of memory though the hash
    164    @param md   The hash state
    165    @param in   The data to hash
    166    @param inlen  The length of the data (octets)
    167    @return CRYPT_OK if successful
    168 */
    169 int chc_process(hash_state * md, const unsigned char *in, unsigned long inlen)
    170 {
    171    int err;
    172 
    173    LTC_ARGCHK(md   != NULL);
    174    LTC_ARGCHK(in  != NULL);
    175 
    176    /* is the cipher valid? */
    177    if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
    178       return err;
    179    }
    180    if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) {
    181       return CRYPT_INVALID_CIPHER;
    182    }
    183 
    184    return _chc_process(md, in, inlen);
    185 }
    186 
    187 /**
    188    Terminate the hash to get the digest
    189    @param md   The hash state
    190    @param out [out] The destination of the hash (length of the block size of the block cipher)
    191    @return CRYPT_OK if successful
    192 */
    193 int chc_done(hash_state *md, unsigned char *out)
    194 {
    195     int err;
    196 
    197     LTC_ARGCHK(md   != NULL);
    198     LTC_ARGCHK(out  != NULL);
    199 
    200     /* is the cipher valid? */
    201     if ((err = cipher_is_valid(cipher_idx)) != CRYPT_OK) {
    202        return err;
    203     }
    204     if (cipher_blocksize != cipher_descriptor[cipher_idx].block_length) {
    205        return CRYPT_INVALID_CIPHER;
    206     }
    207 
    208     if (md->chc.curlen >= sizeof(md->chc.buf)) {
    209        return CRYPT_INVALID_ARG;
    210     }
    211 
    212     /* increase the length of the message */
    213     md->chc.length += md->chc.curlen * 8;
    214 
    215     /* append the '1' bit */
    216     md->chc.buf[md->chc.curlen++] = (unsigned char)0x80;
    217 
    218     /* if the length is currently above l-8 bytes we append zeros
    219      * then compress.  Then we can fall back to padding zeros and length
    220      * encoding like normal.
    221      */
    222     if (md->chc.curlen > (unsigned long)(cipher_blocksize - 8)) {
    223         while (md->chc.curlen < (unsigned long)cipher_blocksize) {
    224             md->chc.buf[md->chc.curlen++] = (unsigned char)0;
    225         }
    226         chc_compress(md, md->chc.buf);
    227         md->chc.curlen = 0;
    228     }
    229 
    230     /* pad upto l-8 bytes of zeroes */
    231     while (md->chc.curlen < (unsigned long)(cipher_blocksize - 8)) {
    232         md->chc.buf[md->chc.curlen++] = (unsigned char)0;
    233     }
    234 
    235     /* store length */
    236     STORE64L(md->chc.length, md->chc.buf+(cipher_blocksize-8));
    237     chc_compress(md, md->chc.buf);
    238 
    239     /* copy output */
    240     XMEMCPY(out, md->chc.state, cipher_blocksize);
    241 
    242 #ifdef LTC_CLEAN_STACK
    243     zeromem(md, sizeof(hash_state));
    244 #endif
    245     return CRYPT_OK;
    246 }
    247 
    248 /**
    249   Self-test the hash
    250   @return CRYPT_OK if successful, CRYPT_NOP if self-tests have been disabled
    251 */
    252 int chc_test(void)
    253 {
    254    static const struct {
    255       unsigned char *msg,
    256                      md[MAXBLOCKSIZE];
    257       int            len;
    258    } tests[] = {
    259 {
    260    (unsigned char *)"hello world",
    261    { 0xcf, 0x57, 0x9d, 0xc3, 0x0a, 0x0e, 0xea, 0x61,
    262      0x0d, 0x54, 0x47, 0xc4, 0x3c, 0x06, 0xf5, 0x4e },
    263    16
    264 }
    265 };
    266    int x, oldhashidx, idx;
    267    unsigned char out[MAXBLOCKSIZE];
    268    hash_state md;
    269 
    270    /* AES can be under rijndael or aes... try to find it */
    271    if ((idx = find_cipher("aes")) == -1) {
    272       if ((idx = find_cipher("rijndael")) == -1) {
    273          return CRYPT_NOP;
    274       }
    275    }
    276    oldhashidx = cipher_idx;
    277    chc_register(idx);
    278 
    279    for (x = 0; x < (int)(sizeof(tests)/sizeof(tests[0])); x++) {
    280        chc_init(&md);
    281        chc_process(&md, tests[x].msg, strlen((char *)tests[x].msg));
    282        chc_done(&md, out);
    283        if (XMEMCMP(out, tests[x].md, tests[x].len)) {
    284           return CRYPT_FAIL_TESTVECTOR;
    285        }
    286    }
    287    if (oldhashidx != UNDEFED_HASH) {
    288       chc_register(oldhashidx);
    289    }
    290 
    291    return CRYPT_OK;
    292 }
    293 
    294 #endif
    295 
    296 /* $Source: /cvs/libtom/libtomcrypt/src/hashes/chc/chc.c,v $ */
    297 /* $Revision: 1.6 $ */
    298 /* $Date: 2006/11/01 09:28:17 $ */
    299