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