1#include "crypto/tests/test_internal.h"
2
3TEST_GROUP_DECLARE(chacha20, .intensity_desc = {
4 .curve = SCALE_PIECEWISE_LOG,
5 .unit = "bytes",
6 });
7
8/* RFC 7539 Section 2.4.2 official test vector */
9TEST_DECLARE_UNIT(chacha20, rfc7539_kat) {
10 static const uint8_t key[32] = {
11 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a,
12 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
13 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
14 };
15 static const uint8_t nonce[12] = {
16 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, 0x00,
17 };
18 uint32_t counter = 1;
19
20 const char *plaintext =
21 "Ladies and Gentlemen of the class of '99: If I could offer you "
22 "only one tip for the future, sunscreen would be it.";
23 size_t len = strlen(str: plaintext);
24
25 static const uint8_t expected_cipher[114] = {
26 0x6e, 0x2e, 0x35, 0x9a, 0x25, 0x68, 0xf9, 0x80, 0x41, 0xba, 0x07, 0x28,
27 0xdd, 0x0d, 0x69, 0x81, 0xe9, 0x7e, 0x7a, 0xec, 0x1d, 0x43, 0x60, 0xc2,
28 0x0a, 0x27, 0xaf, 0xcc, 0xfd, 0x9f, 0xae, 0x0b, 0xf9, 0x1b, 0x65, 0xc5,
29 0x52, 0x47, 0x33, 0xab, 0x8f, 0x59, 0x3d, 0xab, 0xcd, 0x62, 0xb3, 0x57,
30 0x16, 0x39, 0xd6, 0x24, 0xe6, 0x51, 0x52, 0xab, 0x8f, 0x53, 0x0c, 0x35,
31 0x9f, 0x08, 0x61, 0xd8, 0x07, 0xca, 0x0d, 0xbf, 0x50, 0x0d, 0x6a, 0x61,
32 0x56, 0xa3, 0x8e, 0x08, 0x8a, 0x22, 0xb6, 0x5e, 0x52, 0xbc, 0x51, 0x4d,
33 0x16, 0xcc, 0xf8, 0x06, 0x81, 0x8c, 0xe9, 0x1a, 0xb7, 0x79, 0x37, 0x36,
34 0x5a, 0xf9, 0x0b, 0xbf, 0x74, 0xa3, 0x5b, 0xe6, 0xb4, 0x0b, 0x8e, 0xed,
35 0xf2, 0x78, 0x5e, 0x42, 0x87, 0x4d,
36 };
37
38 uint8_t out[114] = {0};
39 chacha20_encrypt(key, nonce, counter, in: (const uint8_t *) plaintext, out,
40 len);
41 TEST_ASSERT_MEM_EQ(out, expected_cipher, len);
42
43 /* D(E(M)) == M */
44 uint8_t decrypted[114] = {0};
45 chacha20_encrypt(key, nonce, counter, in: out, out: decrypted, len);
46 TEST_ASSERT_MEM_EQ(decrypted, plaintext, len);
47
48 return TEST_SUCCESS;
49}
50
51/* chunking and stream boundaries */
52TEST_DECLARE_UNIT(chacha20, block_seams, TEST_INTENSITY(128, 512, 65536)) {
53 size_t total = ctx->intensity_val ? ctx->intensity_val : 512;
54 uint8_t key[32] = {0x42};
55 uint8_t nonce[12] = {0x24};
56 uint8_t *src = kmalloc(total, ALLOC_FLAGS_NONE);
57 uint8_t *dst = kmalloc(total, ALLOC_FLAGS_NONE);
58 uint8_t *roundtrip = kmalloc(total, ALLOC_FLAGS_NONE);
59 TEST_ASSERT_NONNULL(src);
60 TEST_ASSERT_NONNULL(dst);
61 TEST_ASSERT_NONNULL(roundtrip);
62
63 for (size_t i = 0; i < total; i++)
64 src[i] = (uint8_t) i;
65
66 /* Boundary lengths: 0, 1, 63, 64 (1 block),
67 * 65 (crosses block), 128 (2 blocks), 129, total / 2, total */
68 size_t lens[] = {0, 1, 63, 64, 65, 128, 129, total / 2, total};
69 for (size_t i = 0; i < TEST_ARRAY_LEN(lens); i++) {
70 size_t l = lens[i];
71 if (l > total)
72 l = total;
73 memset(dst, 0, total);
74 memset(roundtrip, 0, total);
75
76 chacha20_encrypt(key, nonce, counter: 1, in: src, out: dst, len: l);
77 chacha20_encrypt(key, nonce, counter: 1, in: dst, out: roundtrip, len: l);
78
79 TEST_ASSERT_MEM_EQ(roundtrip, src, l);
80 }
81
82 kfree(src);
83 kfree(dst);
84 kfree(roundtrip);
85 return TEST_SUCCESS;
86}
87