xref: /optee_os/core/lib/libtomcrypt/src/modes/ctr/ctr_encrypt.c (revision d1957bb3a58f8b0a412dc07aa4b37b68105c8b02)
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