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