1 // SPDX-License-Identifier: BSD-2-Clause
2 /* LibTomCrypt, modular cryptographic library -- Tom St Denis
3  *
4  * LibTomCrypt is a library that provides various cryptographic
5  * algorithms in a highly modular and flexible manner.
6  *
7  * The library is free for all purposes without any express
8  * guarantee it works.
9  */
10 #include "tomcrypt_private.h"
11 
12 /**
13   @file ctr_encrypt.c
14   CTR implementation, encrypt data, Tom St Denis
15 */
16 
17 
18 #ifdef LTC_CTR_MODE
19 
ctr_increment_counter(symmetric_CTR * ctr)20 static void ctr_increment_counter(symmetric_CTR *ctr)
21 {
22 	int x;
23 
24 	if (ctr->mode == CTR_COUNTER_LITTLE_ENDIAN) {
25 		for (x = 0; x < ctr->ctrlen; x++) {
26 			ctr->ctr[x] = (ctr->ctr[x] + 1) & 0xff;
27 			if (ctr->ctr[x])
28 				return;
29 		}
30 	} else {
31 		for (x = ctr->blocklen - 1; x >= ctr->ctrlen; x--) {
32 			ctr->ctr[x] = (ctr->ctr[x] + 1) & 0xff;
33 			if (ctr->ctr[x]) {
34 				return;
35 			}
36 		}
37 	}
38 }
39 
40 /**
41   CTR encrypt software implementation
42   @param pt     Plaintext
43   @param ct     [out] Ciphertext
44   @param len    Length of plaintext (octets)
45   @param ctr    CTR state
46   @return CRYPT_OK if successful
47 */
_ctr_encrypt(const unsigned char * pt,unsigned char * ct,unsigned long len,symmetric_CTR * ctr)48 static int _ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr)
49 {
50    int err;
51 
52    while (len) {
53       /* is the pad empty? */
54       if (ctr->padlen == ctr->blocklen) {
55         /* encrypt counter into pad */
56         if ((err = cipher_descriptor[ctr->cipher]->ecb_encrypt(ctr->ctr, ctr->pad, &ctr->key)) != CRYPT_OK) {
57           return err;
58         }
59         ctr->padlen = 0;
60       }
61 #ifdef LTC_FAST
62       if ((ctr->padlen == 0) && (len >= (unsigned long)ctr->blocklen)) {
63          for (x = 0; x < ctr->blocklen; x += sizeof(LTC_FAST_TYPE)) {
64             *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ct + x)) = *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)pt + x)) ^
65                                                            *(LTC_FAST_TYPE_PTR_CAST((unsigned char *)ctr->pad + x));
66          }
67        pt         += ctr->blocklen;
68        ct         += ctr->blocklen;
69        len        -= ctr->blocklen;
70        ctr->padlen = ctr->blocklen;
71        continue;
72       }
73 #endif
74       *ct++ = *pt++ ^ ctr->pad[ctr->padlen++];
75       --len;
76 
77       /* done with one full block? if so, set counter for next block. */
78       if (ctr->padlen == ctr->blocklen) {
79          ctr_increment_counter(ctr);
80       }
81    }
82    return CRYPT_OK;
83 }
84 
85 /**
86   CTR encrypt
87   @param pt     Plaintext
88   @param ct     [out] Ciphertext
89   @param len    Length of plaintext (octets)
90   @param ctr    CTR state
91   @return CRYPT_OK if successful
92 */
ctr_encrypt(const unsigned char * pt,unsigned char * ct,unsigned long len,symmetric_CTR * ctr)93 int ctr_encrypt(const unsigned char *pt, unsigned char *ct, unsigned long len, symmetric_CTR *ctr)
94 {
95    unsigned long incr;
96    int err;
97 
98    LTC_ARGCHK(pt != NULL);
99    LTC_ARGCHK(ct != NULL);
100    LTC_ARGCHK(ctr != NULL);
101 
102    if ((err = cipher_is_valid(ctr->cipher)) != CRYPT_OK) {
103        return err;
104    }
105 
106    /* is blocklen/padlen valid? */
107    if ((ctr->blocklen < 1) || (ctr->blocklen > (int)sizeof(ctr->ctr)) ||
108        (ctr->padlen   < 0) || (ctr->padlen   > (int)sizeof(ctr->pad))) {
109       return CRYPT_INVALID_ARG;
110    }
111 
112 #ifdef LTC_FAST
113    if (ctr->blocklen % sizeof(LTC_FAST_TYPE)) {
114       return CRYPT_INVALID_ARG;
115    }
116 #endif
117 
118    if (cipher_descriptor[ctr->cipher]->accel_ctr_encrypt != NULL ) {
119      /* handle acceleration only if not in the middle of a block, accelerator is present and length is >= a block size */
120      if ((ctr->padlen == 0 || ctr->padlen == ctr->blocklen) && len >= (unsigned long)ctr->blocklen) {
121        if ((err = cipher_descriptor[ctr->cipher]->accel_ctr_encrypt(pt, ct, len/ctr->blocklen, ctr->ctr, ctr->mode, &ctr->key)) != CRYPT_OK) {
122          return err;
123        }
124        pt += (len / ctr->blocklen) * ctr->blocklen;
125        ct += (len / ctr->blocklen) * ctr->blocklen;
126        len %= ctr->blocklen;
127        /* counter was changed by accelerator so mark pad empty (will need updating in _ctr_encrypt()) */
128        ctr->padlen = ctr->blocklen;
129      }
130 
131      /* try to re-synchronize on a block boundary for maximum use of acceleration */
132      incr = ctr->blocklen - ctr->padlen;
133      if (len >= incr + (unsigned long)ctr->blocklen) {
134        if ((err = _ctr_encrypt(pt, ct, incr, ctr)) != CRYPT_OK) {
135          return err;
136        }
137        pt += incr;
138        ct += incr;
139        len -= incr;
140        return ctr_encrypt(pt, ct, len, ctr);
141      }
142    }
143 
144    return _ctr_encrypt(pt, ct, len, ctr);
145 }
146 
147 #endif
148 
149 /* ref:         $Format:%D$ */
150 /* git commit:  $Format:%H$ */
151 /* commit time: $Format:%ai$ */
152