Skip to content

Commit b179722

Browse files
Merge pull request #544 from anhu/aes_modes_ctr
AES modes extravaganza. CTR
2 parents eaff9c5 + a6ac31c commit b179722

1 file changed

Lines changed: 304 additions & 0 deletions

File tree

crypto/aes-modes/aes-ctr.c

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
/* aes-ctr.c
2+
*
3+
* Copyright (C) 2006-2025 wolfSSL Inc.
4+
*
5+
* This file is part of wolfSSL.
6+
*
7+
* wolfSSL is free software; you can redistribute it and/or modify
8+
* it under the terms of the GNU General Public License as published by
9+
* the Free Software Foundation; either version 2 of the License, or
10+
* (at your option) any later version.
11+
*
12+
* wolfSSL is distributed in the hope that it will be useful,
13+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
* GNU General Public License for more details.
16+
*
17+
* You should have received a copy of the GNU General Public License
18+
* along with this program; if not, write to the Free Software
19+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20+
*/
21+
22+
/* AES-CTR Example
23+
* This example demonstrates:
24+
* - One-shot encryption using wc_AesCtrEncrypt()
25+
* - Streaming decryption using wc_AesCtrEncrypt() in chunks
26+
* Note: CTR mode uses same function for encrypt/decrypt and inherently
27+
* supports streaming (no padding required)
28+
*/
29+
30+
#include <stdio.h>
31+
#include <stdlib.h>
32+
#include <string.h>
33+
34+
#ifndef WOLFSSL_USER_SETTINGS
35+
#include <wolfssl/options.h>
36+
#endif
37+
#include <wolfssl/wolfcrypt/settings.h>
38+
#include <wolfssl/wolfcrypt/aes.h>
39+
#include <wolfssl/wolfcrypt/random.h>
40+
#include <wolfssl/wolfcrypt/error-crypt.h>
41+
42+
#if !defined(NO_AES) && defined(WOLFSSL_AES_COUNTER)
43+
44+
#define AES_KEY_SIZE AES_256_KEY_SIZE
45+
46+
/* Small chunk size to demonstrate streaming */
47+
#define CHUNK_SIZE 64
48+
49+
static int read_file(const char* filename, byte** data, word32* dataSz)
50+
{
51+
FILE* fp;
52+
long fileSz;
53+
54+
fp = fopen(filename, "rb");
55+
if (fp == NULL) {
56+
printf("Error: Cannot open file %s\n", filename);
57+
return -1;
58+
}
59+
60+
fseek(fp, 0, SEEK_END);
61+
fileSz = ftell(fp);
62+
fseek(fp, 0, SEEK_SET);
63+
64+
*data = (byte*)malloc(fileSz);
65+
if (*data == NULL) {
66+
fclose(fp);
67+
printf("Error: Memory allocation failed\n");
68+
return -1;
69+
}
70+
71+
*dataSz = (word32)fread(*data, 1, fileSz, fp);
72+
fclose(fp);
73+
74+
return 0;
75+
}
76+
77+
static int write_file(const char* filename, const byte* data, word32 dataSz)
78+
{
79+
FILE* fp;
80+
81+
fp = fopen(filename, "wb");
82+
if (fp == NULL) {
83+
printf("Error: Cannot create file %s\n", filename);
84+
return -1;
85+
}
86+
87+
fwrite(data, 1, dataSz, fp);
88+
fclose(fp);
89+
90+
return 0;
91+
}
92+
93+
/* One-shot encryption */
94+
static int encrypt_file(const char* inFile, const char* outFile,
95+
const byte* key, word32 keySz)
96+
{
97+
Aes aes;
98+
WC_RNG rng;
99+
byte iv[AES_BLOCK_SIZE];
100+
byte* plaintext = NULL;
101+
byte* ciphertext = NULL;
102+
word32 plaintextSz;
103+
int ret;
104+
105+
ret = read_file(inFile, &plaintext, &plaintextSz);
106+
if (ret != 0) return ret;
107+
108+
/* IV + ciphertext */
109+
ciphertext = (byte*)malloc(plaintextSz + AES_BLOCK_SIZE);
110+
if (ciphertext == NULL) {
111+
free(plaintext);
112+
return -1;
113+
}
114+
115+
/* Generate random IV/nonce */
116+
ret = wc_InitRng(&rng);
117+
if (ret != 0) {
118+
free(plaintext);
119+
free(ciphertext);
120+
return ret;
121+
}
122+
123+
ret = wc_RNG_GenerateBlock(&rng, iv, AES_BLOCK_SIZE);
124+
wc_FreeRng(&rng);
125+
if (ret != 0) {
126+
free(plaintext);
127+
free(ciphertext);
128+
return ret;
129+
}
130+
131+
/* Initialize AES */
132+
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
133+
if (ret != 0) {
134+
free(plaintext);
135+
free(ciphertext);
136+
return ret;
137+
}
138+
139+
ret = wc_AesSetKey(&aes, key, keySz, iv, AES_ENCRYPTION);
140+
if (ret != 0) {
141+
wc_AesFree(&aes);
142+
free(plaintext);
143+
free(ciphertext);
144+
return ret;
145+
}
146+
147+
/* One-shot encrypt */
148+
ret = wc_AesCtrEncrypt(&aes, ciphertext + AES_BLOCK_SIZE, plaintext,
149+
plaintextSz);
150+
wc_AesFree(&aes);
151+
152+
if (ret != 0) {
153+
free(plaintext);
154+
free(ciphertext);
155+
return ret;
156+
}
157+
158+
/* Prepend IV to output */
159+
memcpy(ciphertext, iv, AES_BLOCK_SIZE);
160+
161+
ret = write_file(outFile, ciphertext, plaintextSz + AES_BLOCK_SIZE);
162+
163+
free(plaintext);
164+
free(ciphertext);
165+
166+
printf("AES-CTR encryption complete (one-shot)\n");
167+
return ret;
168+
}
169+
170+
/* Streaming decryption - process in chunks */
171+
static int decrypt_file(const char* inFile, const char* outFile,
172+
const byte* key, word32 keySz)
173+
{
174+
Aes aes;
175+
byte iv[AES_BLOCK_SIZE];
176+
byte* ciphertext = NULL;
177+
byte* plaintext = NULL;
178+
word32 ciphertextSz;
179+
word32 plaintextSz;
180+
word32 offset;
181+
word32 chunkSz;
182+
int ret;
183+
184+
ret = read_file(inFile, &ciphertext, &ciphertextSz);
185+
if (ret != 0) return ret;
186+
187+
if (ciphertextSz < AES_BLOCK_SIZE) {
188+
free(ciphertext);
189+
printf("Error: File too small\n");
190+
return -1;
191+
}
192+
193+
/* Extract IV from beginning */
194+
memcpy(iv, ciphertext, AES_BLOCK_SIZE);
195+
196+
plaintextSz = ciphertextSz - AES_BLOCK_SIZE;
197+
plaintext = (byte*)malloc(plaintextSz);
198+
if (plaintext == NULL) {
199+
free(ciphertext);
200+
return -1;
201+
}
202+
203+
/* Initialize AES */
204+
ret = wc_AesInit(&aes, NULL, INVALID_DEVID);
205+
if (ret != 0) {
206+
free(ciphertext);
207+
free(plaintext);
208+
return ret;
209+
}
210+
211+
ret = wc_AesSetKey(&aes, key, keySz, iv, AES_ENCRYPTION);
212+
if (ret != 0) {
213+
wc_AesFree(&aes);
214+
free(ciphertext);
215+
free(plaintext);
216+
return ret;
217+
}
218+
219+
/* Streaming decrypt - process in chunks
220+
* Note: CTR mode uses same function for encrypt and decrypt */
221+
printf("AES-CTR streaming decryption:\n");
222+
offset = 0;
223+
while (offset < plaintextSz) {
224+
chunkSz = plaintextSz - offset;
225+
if (chunkSz > CHUNK_SIZE) {
226+
chunkSz = CHUNK_SIZE;
227+
}
228+
229+
ret = wc_AesCtrEncrypt(&aes, plaintext + offset,
230+
ciphertext + AES_BLOCK_SIZE + offset, chunkSz);
231+
if (ret != 0) {
232+
wc_AesFree(&aes);
233+
free(ciphertext);
234+
free(plaintext);
235+
return ret;
236+
}
237+
238+
printf(" Decrypted chunk: offset=%u, size=%u\n", offset, chunkSz);
239+
offset += chunkSz;
240+
}
241+
242+
wc_AesFree(&aes);
243+
244+
ret = write_file(outFile, plaintext, plaintextSz);
245+
246+
free(ciphertext);
247+
free(plaintext);
248+
249+
printf("AES-CTR decryption complete (streaming)\n");
250+
return ret;
251+
}
252+
253+
int main(int argc, char** argv)
254+
{
255+
byte key[AES_KEY_SIZE];
256+
int ret;
257+
258+
if (argc != 3) {
259+
printf("Usage: %s <input file> <output file>\n", argv[0]);
260+
printf("Encrypts input file (one-shot), then decrypts to output file (streaming)\n");
261+
return 1;
262+
}
263+
264+
wolfCrypt_Init();
265+
266+
/* Use a fixed key for demonstration */
267+
memset(key, 0x07, AES_KEY_SIZE);
268+
269+
/* Encrypt to temporary file */
270+
ret = encrypt_file(argv[1], "temp_encrypted.bin", key, AES_KEY_SIZE);
271+
if (ret != 0) {
272+
printf("Encryption failed: %d\n", ret);
273+
wolfCrypt_Cleanup();
274+
return 1;
275+
}
276+
277+
/* Decrypt to output file */
278+
ret = decrypt_file("temp_encrypted.bin", argv[2], key, AES_KEY_SIZE);
279+
if (ret != 0) {
280+
printf("Decryption failed: %d\n", ret);
281+
wolfCrypt_Cleanup();
282+
return 1;
283+
}
284+
285+
/* Clean up temp file */
286+
remove("temp_encrypted.bin");
287+
288+
printf("Success! Decrypted file written to %s\n", argv[2]);
289+
290+
wolfCrypt_Cleanup();
291+
return 0;
292+
}
293+
294+
#else
295+
296+
int main(int argc, char** argv)
297+
{
298+
(void)argc;
299+
(void)argv;
300+
printf("AES-CTR not compiled in. Enable with WOLFSSL_AES_COUNTER\n");
301+
return 0;
302+
}
303+
304+
#endif

0 commit comments

Comments
 (0)