aes.cpp raw
1 // Copyright (c) 2016-2019 The Limenka developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <crypto/aes.h>
6
7 #include <string.h>
8
9 extern "C" {
10 #include <crypto/ctaes/ctaes.c>
11 }
12
13 AES256Encrypt::AES256Encrypt(const unsigned char key[32])
14 {
15 AES256_init(&ctx, key);
16 }
17
18 AES256Encrypt::~AES256Encrypt()
19 {
20 memset(&ctx, 0, sizeof(ctx));
21 }
22
23 void AES256Encrypt::Encrypt(unsigned char ciphertext[16], const unsigned char plaintext[16]) const
24 {
25 AES256_encrypt(&ctx, 1, ciphertext, plaintext);
26 }
27
28 AES256Decrypt::AES256Decrypt(const unsigned char key[32])
29 {
30 AES256_init(&ctx, key);
31 }
32
33 AES256Decrypt::~AES256Decrypt()
34 {
35 memset(&ctx, 0, sizeof(ctx));
36 }
37
38 void AES256Decrypt::Decrypt(unsigned char plaintext[16], const unsigned char ciphertext[16]) const
39 {
40 AES256_decrypt(&ctx, 1, plaintext, ciphertext);
41 }
42
43
44 template <typename T>
45 static int CBCEncrypt(const T& enc, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
46 {
47 int written = 0;
48 int padsize = size % AES_BLOCKSIZE;
49 unsigned char mixed[AES_BLOCKSIZE];
50
51 if (!data || !size || !out)
52 return 0;
53
54 if (!pad && padsize != 0)
55 return 0;
56
57 memcpy(mixed, iv, AES_BLOCKSIZE);
58
59 // Write all but the last block
60 while (written + AES_BLOCKSIZE <= size) {
61 for (int i = 0; i != AES_BLOCKSIZE; i++)
62 mixed[i] ^= *data++;
63 enc.Encrypt(out + written, mixed);
64 memcpy(mixed, out + written, AES_BLOCKSIZE);
65 written += AES_BLOCKSIZE;
66 }
67 if (pad) {
68 // For all that remains, pad each byte with the value of the remaining
69 // space. If there is none, pad by a full block.
70 for (int i = 0; i != padsize; i++)
71 mixed[i] ^= *data++;
72 for (int i = padsize; i != AES_BLOCKSIZE; i++)
73 mixed[i] ^= AES_BLOCKSIZE - padsize;
74 enc.Encrypt(out + written, mixed);
75 written += AES_BLOCKSIZE;
76 }
77 return written;
78 }
79
80 template <typename T>
81 static int CBCDecrypt(const T& dec, const unsigned char iv[AES_BLOCKSIZE], const unsigned char* data, int size, bool pad, unsigned char* out)
82 {
83 int written = 0;
84 bool fail = false;
85 const unsigned char* prev = iv;
86
87 if (!data || !size || !out)
88 return 0;
89
90 if (size % AES_BLOCKSIZE != 0)
91 return 0;
92
93 // Decrypt all data. Padding will be checked in the output.
94 while (written != size) {
95 dec.Decrypt(out, data + written);
96 for (int i = 0; i != AES_BLOCKSIZE; i++)
97 *out++ ^= prev[i];
98 prev = data + written;
99 written += AES_BLOCKSIZE;
100 }
101
102 // When decrypting padding, attempt to run in constant-time
103 if (pad) {
104 // If used, padding size is the value of the last decrypted byte. For
105 // it to be valid, It must be between 1 and AES_BLOCKSIZE.
106 unsigned char padsize = *--out;
107 fail = !padsize | (padsize > AES_BLOCKSIZE);
108
109 // If not well-formed, treat it as though there's no padding.
110 padsize *= !fail;
111
112 // All padding must equal the last byte otherwise it's not well-formed
113 for (int i = AES_BLOCKSIZE; i != 0; i--)
114 fail |= ((i > AES_BLOCKSIZE - padsize) & (*out-- != padsize));
115
116 written -= padsize;
117 }
118 return written * !fail;
119 }
120
121 AES256CBCEncrypt::AES256CBCEncrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
122 : enc(key), pad(padIn)
123 {
124 memcpy(iv, ivIn, AES_BLOCKSIZE);
125 }
126
127 int AES256CBCEncrypt::Encrypt(const unsigned char* data, int size, unsigned char* out) const
128 {
129 return CBCEncrypt(enc, iv, data, size, pad, out);
130 }
131
132 AES256CBCEncrypt::~AES256CBCEncrypt()
133 {
134 memset(iv, 0, sizeof(iv));
135 }
136
137 AES256CBCDecrypt::AES256CBCDecrypt(const unsigned char key[AES256_KEYSIZE], const unsigned char ivIn[AES_BLOCKSIZE], bool padIn)
138 : dec(key), pad(padIn)
139 {
140 memcpy(iv, ivIn, AES_BLOCKSIZE);
141 }
142
143
144 int AES256CBCDecrypt::Decrypt(const unsigned char* data, int size, unsigned char* out) const
145 {
146 return CBCDecrypt(dec, iv, data, size, pad, out);
147 }
148
149 AES256CBCDecrypt::~AES256CBCDecrypt()
150 {
151 memset(iv, 0, sizeof(iv));
152 }
153