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