| 1 | #include "crypto/tests/test_internal.h" |
| 2 | |
| 3 | TEST_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 */ |
| 9 | TEST_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 */ |
| 52 | TEST_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 | |