Skip to content

Commit f04b572

Browse files
authored
Merge pull request #4 from ilvn/eng/ctr
Counter mode implementation
2 parents b4f5779 + d009689 commit f04b572

File tree

5 files changed

+283
-1
lines changed

5 files changed

+283
-1
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ This source code gives you a codebook, an ECB core that works
2121
on a 16-byte block, and it is up to you to choose and implement
2222
an appropriate [block cipher mode](https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation) yourself.
2323

24+
Check the [ctr](ctr) directory for a counter mode complementary implementation.
25+
2426
## Portablility
2527

2628
I try my best to keep this source code portable. But supporting
2729
a wide range of esoteric or long-obsolete compilers is no longer
28-
a priority. Take a look at [the basic edition](https://github.com/ilvn/aes256/releases/tag/basic) if you still need
30+
a priority. Look at [the basic edition](https://github.com/ilvn/aes256/releases/tag/basic) if you still need
2931
that support and can't use the current variant.
3032

3133
The primary development is with `clang` and `GCC` on macOS and

ctr/Makefile

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## AES-256-CTR
2+
##
3+
## Usage: make [target]
4+
## Targets:
5+
## obj compile the object file
6+
## test build the test executable
7+
## fast use with test for building a faster executable
8+
## help show this help message
9+
10+
CC := $(if $(shell which clang),clang,gcc)
11+
CFLAGS := -O3 -Wall -Wextra -pedantic
12+
override USE_TABLES := $(if $(findstring fast,$(MAKECMDGOALS)),-DBACK_TO_TABLES,)
13+
AESDIR := ..
14+
15+
.PHONY: help obj clean fast
16+
17+
help:
18+
@grep -h '^\##' $(MAKEFILE_LIST) | cut -c4-
19+
20+
aes256ctr.o: aes256ctr.c aes256ctr.h
21+
$(CC) $(CFLAGS) -I$(AESDIR) -c -o $@ $<
22+
23+
obj: aes256ctr.o
24+
25+
test: aes256ctr.c aes256ctr.h $(AESDIR)/aes256.c
26+
$(CC) $(CFLAGS) -I$(AESDIR) $(USE_TABLES) -DAES256CTR_SELF_TEST__ -o $@ $(?:%.h=)
27+
28+
clean:
29+
rm -f test *.o
30+
31+
fast:
32+
@:

ctr/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# AES-256-CTR
2+
3+
This is a source code for the counter mode encryption based on the byte-oriented AES-256 implementation.
4+
5+
## Usage
6+
7+
Use `make obj` to compile the object file or `make test` to build a test executable.
8+
9+
Building the test executable requires both aes256.c and aes256.h assumed residing in the parent directory. Otherwise, you may use `AESDIR` with `make test` to specify an actual location.

ctr/aes256ctr.c

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
//
2+
// A compact AES-256-CTR implementation.
3+
// Complies with RFC3686, http://tools.ietf.org/html/rfc3686
4+
//
5+
// Copyright (c) 2022 Ilia Levin (ilia@levin.sg)
6+
//
7+
// This source code is licensed under the terms of the MIT license.
8+
// For a copy, see <https://opensource.org/licenses/MIT>.
9+
10+
#include "aes256ctr.h"
11+
12+
// -----------------------------------------------------------------------------
13+
static inline uint8_t
14+
_inc_b(uint8_t b)
15+
{
16+
return ((b == 0xff) ? 0 : (1 + b));
17+
} // _inc_b
18+
19+
20+
// -----------------------------------------------------------------------------
21+
static inline uint8_t
22+
_inc_ctr(uint8_t val[static 4])
23+
{
24+
if (0 == (val[3] = _inc_b(val[3])))
25+
if (0 == (val[2] = _inc_b(val[2])))
26+
if (0 == (val[1] = _inc_b(val[1]))) {
27+
val[0] = _inc_b(val[0]);
28+
}
29+
return 0;
30+
} // _inc_ctr
31+
32+
33+
// -----------------------------------------------------------------------------
34+
static uint8_t
35+
_clock_keystream(aes256ctr_ctx_t *ctx, aes256_blk_t *kb)
36+
{
37+
*kb = *((aes256_blk_t *)&ctx->ctr.blk);
38+
aes256_encrypt_ecb(&ctx->ecb, kb);
39+
40+
return _inc_ctr(&ctx->ctr.blk.ctr[0]);
41+
} // _clock_keystream
42+
43+
44+
// -----------------------------------------------------------------------------
45+
uint8_t
46+
aes256ctr_setblk(aes256ctr_ctx_t *ctx, rfc3686_blk_t *blk)
47+
{
48+
if ((NULL != ctx) && (NULL != blk)) {
49+
ctx->ctr.blk = *blk;
50+
return AES_SUCCESS;
51+
}
52+
53+
return AES_ERROR;
54+
} // aes256ctr_setblk
55+
56+
57+
// -----------------------------------------------------------------------------
58+
aes256ctr_ctx_t
59+
aes256ctr_init(aes256_key_t *key, rfc3686_blk_t *blk)
60+
{
61+
aes256ctr_ctx_t ret = {0};
62+
63+
if (NULL != key) {
64+
ret.ctr.enckey = *key;
65+
}
66+
(void)aes256ctr_setblk(&ret, blk);
67+
68+
return ret;
69+
} // aes255ctr_init
70+
71+
72+
// -----------------------------------------------------------------------------
73+
uint8_t
74+
aes256ctr_encrypt(aes256ctr_ctx_t *ctx, uint8_t *buf, size_t size)
75+
{
76+
if ((NULL != ctx) && (NULL != buf)) {
77+
aes256_blk_t ctrkey;
78+
size_t j = sizeof(ctrkey);
79+
80+
for (size_t i = 0; i < size; i++) {
81+
if (j == sizeof(ctrkey)) {
82+
j = _clock_keystream(ctx, &ctrkey);
83+
}
84+
buf[i] ^= ctrkey.raw[j++];
85+
ctrkey.raw[j - 1] = 0;
86+
}
87+
return AES_SUCCESS;
88+
}
89+
90+
return AES_ERROR;
91+
} // aes256ctr_encrypt
92+
93+
94+
// -----------------------------------------------------------------------------
95+
uint8_t
96+
aes256ctr_done(aes256ctr_ctx_t *ctx)
97+
{
98+
return (NULL == ctx) ? AES_ERROR : aes256_done(&ctx->ecb);
99+
} // aes256ctr_done
100+
101+
102+
#if 0
103+
#pragma mark - Self Test
104+
#endif
105+
106+
#ifdef AES256CTR_SELF_TEST__
107+
#include <stdio.h>
108+
#include <string.h>
109+
110+
int
111+
main(void)
112+
{
113+
static const uint8_t kav[] = { // RFC3686 Test Vector #9
114+
0xEB, 0x6C, 0x52, 0x82, 0x1D, 0x0B, 0xBB, 0xF7, 0xCE, 0x75, 0x94, 0x46,
115+
0x2A, 0xCA, 0x4F, 0xAA, 0xB4, 0x07, 0xDF, 0x86, 0x65, 0x69, 0xFD, 0x07,
116+
0xF4, 0x8C, 0xC0, 0xB5, 0x83, 0xD6, 0x07, 0x1F, 0x1E, 0xC0, 0xE6, 0xB8
117+
};
118+
uint8_t buf[] = {
119+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
120+
0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
121+
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23
122+
};
123+
aes256_key_t key = {.raw = {
124+
0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E,
125+
0x2F, 0x43, 0x58, 0x1D, 0xE2, 0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53,
126+
0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D
127+
}
128+
};
129+
rfc3686_blk_t ctr = {
130+
.nonce = {0x00, 0x1C, 0xC5, 0xB7},
131+
.iv = {0x51, 0xA5, 0x1D, 0x70, 0xA1, 0xC1, 0x11, 0x48},
132+
.ctr = {0x00, 0x00, 0x00, 0x01}
133+
};
134+
135+
uint8_t ref[sizeof(buf)];
136+
memcpy(ref, buf, sizeof(ref));
137+
138+
aes256ctr_ctx_t ctx = aes256ctr_init(&key, &ctr);
139+
aes256ctr_encrypt(&ctx, buf, sizeof(buf));
140+
if ((sizeof(buf) != sizeof(kav)) || (0 != memcmp(buf, kav, sizeof(buf)))) {
141+
printf("Encrypt failed\n");
142+
return -1;
143+
}
144+
145+
aes256ctr_setblk(&ctx, &ctr);
146+
aes256ctr_decrypt(&ctx, buf, sizeof(buf));
147+
if (0 != memcmp(buf, ref, sizeof(buf))) {
148+
printf("Decrypt failed\n");
149+
return -1;
150+
}
151+
152+
printf("Success\n");
153+
return 0;
154+
}
155+
#endif // AES256CTR_SELF_TEST__

ctr/aes256ctr.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//
2+
// AES-256-CTR implementation.
3+
// Complies with RFC3686, http://tools.ietf.org/html/rfc3686
4+
//
5+
// Copyright (c) 2022 Ilia Levin (ilia@levin.sg)
6+
//
7+
// This source code is licensed under the terms of the MIT license.
8+
// For a copy, see <https://opensource.org/licenses/MIT>.
9+
10+
11+
#ifndef AES256CTR_H__
12+
#define AES256CTR_H__ 1
13+
14+
#include "aes256.h"
15+
#include <stddef.h>
16+
17+
#ifdef __cplusplus
18+
extern "C" {
19+
#endif
20+
21+
typedef struct rfc3686_blk {
22+
uint8_t nonce[4];
23+
uint8_t iv[8];
24+
uint8_t ctr[4];
25+
} rfc3686_blk_t;
26+
27+
typedef union aes256ctr_context {
28+
aes256_context_t ecb;
29+
struct ctr_ctx {
30+
aes256_key_t key;
31+
aes256_key_t enckey;
32+
rfc3686_blk_t blk;
33+
} ctr;
34+
} aes256ctr_ctx_t;
35+
36+
37+
/// Initialize a counter mode context.
38+
/// @param[in] key Pointer to an encryption key.
39+
/// @param[in] blk Pointer to a counter block.
40+
/// @return the initialized context structure.
41+
///
42+
aes256ctr_ctx_t aes256ctr_init(
43+
aes256_key_t *key,
44+
rfc3686_blk_t *blk
45+
);
46+
47+
48+
/// (Re)set a counter block within the context.
49+
/// @param[in,out] ctx Pointer to the initialized context variable.
50+
/// @param[in] blk Pointer to a source counter block.
51+
/// @return AES_SUCCESS on success, AES_ERROR on failure.
52+
///
53+
uint8_t aes256ctr_setblk(
54+
aes256ctr_ctx_t *ctx,
55+
rfc3686_blk_t *blk
56+
);
57+
58+
59+
/// Encrypt data, in place.
60+
/// @param[in,out] ctx Pointer to the initialized context variable.
61+
/// @param[in,out] buf Pointer to a data buffer.
62+
/// @param[in] size Data buffer size in bytes.
63+
/// @return AES_SUCCESS on success, AES_ERROR on failure.
64+
///
65+
uint8_t aes256ctr_encrypt(
66+
aes256ctr_ctx_t *ctx,
67+
uint8_t *buf,
68+
size_t size
69+
);
70+
71+
#define aes256ctr_decrypt aes256ctr_encrypt
72+
73+
/// Clear the context.
74+
/// @param[in,out] ctx Pointer to the context variable.
75+
/// @return AES_SUCCESS on success, AES_ERROR on failure.
76+
///
77+
uint8_t aes256ctr_done(
78+
aes256ctr_ctx_t *ctx
79+
);
80+
81+
#ifdef __cplusplus
82+
}
83+
#endif
84+
#endif // AES256CTR_H__

0 commit comments

Comments
 (0)