1 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
2 /* SPDX-License-Identifier: Unlicense */
3 #include "tomcrypt_private.h"
4 
5 /**
6    @file ctr_start.c
7    CTR implementation, start chain, Tom St Denis
8 */
9 
10 
11 #ifdef LTC_CTR_MODE
12 
13 /**
14    Initialize a CTR context
15    @param cipher      The index of the cipher desired
16    @param IV          The initialization vector
17    @param key         The secret key
18    @param keylen      The length of the secret key (octets)
19    @param num_rounds  Number of rounds in the cipher desired (0 for default)
20    @param ctr_mode    The counter mode (CTR_COUNTER_LITTLE_ENDIAN or CTR_COUNTER_BIG_ENDIAN)
21    @param ctr         The CTR state to initialize
22    @return CRYPT_OK if successful
23 */
ctr_start(int cipher,const unsigned char * IV,const unsigned char * key,int keylen,int num_rounds,int ctr_mode,symmetric_CTR * ctr)24 int ctr_start(               int   cipher,
25               const unsigned char *IV,
26               const unsigned char *key,       int keylen,
27                              int  num_rounds, int ctr_mode,
28                    symmetric_CTR *ctr)
29 {
30    int x, err;
31 
32    LTC_ARGCHK(IV  != NULL);
33    LTC_ARGCHK(key != NULL);
34    LTC_ARGCHK(ctr != NULL);
35 
36    /* bad param? */
37    if ((err = cipher_is_valid(cipher)) != CRYPT_OK) {
38       return err;
39    }
40 
41    /* ctrlen == counter width */
42    ctr->ctrlen   = (ctr_mode & 255) ? (ctr_mode & 255) : cipher_descriptor[cipher]->block_length;
43    if (ctr->ctrlen > cipher_descriptor[cipher]->block_length) {
44       return CRYPT_INVALID_ARG;
45    }
46 
47    if ((ctr_mode & 0x1000) == CTR_COUNTER_BIG_ENDIAN) {
48       ctr->ctrlen = cipher_descriptor[cipher]->block_length - ctr->ctrlen;
49    }
50 
51    /* setup cipher */
52    if ((err = cipher_descriptor[cipher]->setup(key, keylen, num_rounds, &ctr->key)) != CRYPT_OK) {
53       return err;
54    }
55 
56    /* copy ctr */
57    ctr->blocklen = cipher_descriptor[cipher]->block_length;
58    ctr->cipher   = cipher;
59    ctr->padlen   = 0;
60    ctr->mode     = ctr_mode & 0x1000;
61    for (x = 0; x < ctr->blocklen; x++) {
62        ctr->ctr[x] = IV[x];
63    }
64 
65    if (ctr_mode & LTC_CTR_RFC3686) {
66       /* increment the IV as per RFC 3686 */
67       if (ctr->mode == CTR_COUNTER_LITTLE_ENDIAN) {
68          /* little-endian */
69          for (x = 0; x < ctr->ctrlen; x++) {
70              ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255;
71              if (ctr->ctr[x] != (unsigned char)0) {
72                 break;
73              }
74          }
75       } else {
76          /* big-endian */
77          for (x = ctr->blocklen-1; x >= ctr->ctrlen; x--) {
78              ctr->ctr[x] = (ctr->ctr[x] + (unsigned char)1) & (unsigned char)255;
79              if (ctr->ctr[x] != (unsigned char)0) {
80                 break;
81              }
82          }
83       }
84    }
85 
86    return cipher_descriptor[ctr->cipher]->ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key);
87 }
88 
89 #endif
90