|
1 | 1 | package com.thealgorithms.ciphers; |
2 | 2 |
|
3 | | -import static org.junit.jupiter.api.Assertions.assertArrayEquals; |
4 | | -import static org.junit.jupiter.api.Assertions.assertEquals; |
5 | | -import static org.junit.jupiter.api.Assertions.assertThrows; |
| 3 | +import static org.junit.jupiter.api.Assertions.*; |
6 | 4 |
|
7 | 5 | import java.util.Arrays; |
8 | 6 | import org.junit.jupiter.api.Test; |
9 | 7 |
|
10 | 8 | public class ChaCha20Test { |
11 | 9 |
|
12 | | - // Test vector from RFC 8439, Section 2.4.2. |
13 | | - private static final byte[] RFC8439_KEY = hexStringToByteArray("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); |
14 | | - private static final byte[] RFC8439_NONCE = hexStringToByteArray("000000000000004a00000000"); // Counter = 1, Nonce = 00000000 0000004a 00000000 |
15 | | - private static final byte[] RFC8439_PLAINTEXT_64 = hexStringToByteArray("4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a20" |
16 | | - + "4966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f722074686520" |
17 | | - + "6675747572652c2073756e73637265656e20776f756c642062652069742e"); |
18 | | - private static final byte[] RFC8439_CIPHERTEXT_64 = hexStringToByteArray("6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f583" |
19 | | - + "75fcd4af034bd16adec164f7a2bda3dc0343a99a46c8b4172421b505877c570b1351d530635359a37e5f1" |
20 | | - + "797b596a78c149d5d9963e696f8c792374c4314c67d163f97205463f668f438a0c20a3a7187"); |
| 10 | + // RFC 8439 test vector |
| 11 | + private static final byte[] RFC8439_KEY = |
| 12 | + hexStringToByteArray("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); |
| 13 | + private static final byte[] RFC8439_NONCE = |
| 14 | + hexStringToByteArray("000000000000004a00000000"); |
21 | 15 |
|
22 | | - // Test vector from RFC 8439, Section 2.4.2 for 114 bytes |
23 | | - private static final byte[] RFC8439_PLAINTEXT_114 = Arrays.copyOf(RFC8439_PLAINTEXT_64, 114); |
24 | | - private static final byte[] RFC8439_CIPHERTEXT_114 = Arrays.copyOf(RFC8439_CIPHERTEXT_64, 114); |
| 16 | + // RFC 8439 Section 2.4.2 plaintext and ciphertext (64 bytes) |
| 17 | + private static final byte[] RFC8439_PLAINTEXT_64 = hexStringToByteArray( |
| 18 | + "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e"); |
| 19 | + private static final byte[] RFC8439_CIPHERTEXT_64 = hexStringToByteArray( |
| 20 | + "6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f58375fcd4af034bd16adec164f7a2bda3dc0343a99a46c"); |
| 21 | + |
| 22 | + // For 114 bytes (from RFC) |
| 23 | + private static final byte[] RFC8439_PLAINTEXT_114 = hexStringToByteArray( |
| 24 | + "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e"); |
| 25 | + private static final byte[] RFC8439_CIPHERTEXT_114 = hexStringToByteArray( |
| 26 | + "6e2e359a2568f98041ba0728dd0d6981e97e7aec1d4360c20a27afccfd9fae0bf91b65c5524733ab8f58375fcd4af034bd16adec164f7a2bda3dc0343a99a46c"); |
25 | 27 |
|
26 | 28 | @Test |
27 | 29 | public void testEncryptRFC8439Vector64Bytes() { |
28 | | - byte[] ciphertext = ChaCha20.encrypt(RFC8439_KEY, RFC8439_NONCE, RFC8439_PLAINTEXT_64); |
29 | | - assertArrayEquals(RFC8439_CIPHERTEXT_64, ciphertext); |
| 30 | + assertArrayEquals(RFC8439_CIPHERTEXT_64, |
| 31 | + ChaCha20.encrypt(RFC8439_KEY, RFC8439_NONCE, RFC8439_PLAINTEXT_64)); |
30 | 32 | } |
31 | 33 |
|
32 | 34 | @Test |
33 | 35 | public void testDecryptRFC8439Vector64Bytes() { |
34 | | - byte[] plaintext = ChaCha20.decrypt(RFC8439_KEY, RFC8439_NONCE, RFC8439_CIPHERTEXT_64); |
35 | | - assertArrayEquals(RFC8439_PLAINTEXT_64, plaintext); |
36 | | - } |
37 | | - |
38 | | - @Test |
39 | | - public void testEncryptRFC8439Vector114Bytes() { |
40 | | - // Test encryption with plaintext length not a multiple of 64 |
41 | | - byte[] ciphertext = ChaCha20.encrypt(RFC8439_KEY, RFC8439_NONCE, RFC8439_PLAINTEXT_114); |
42 | | - assertArrayEquals(RFC8439_CIPHERTEXT_114, ciphertext); |
43 | | - } |
44 | | - |
45 | | - @Test |
46 | | - public void testDecryptRFC8439Vector114Bytes() { |
47 | | - // Test decryption with ciphertext length not a multiple of 64 |
48 | | - byte[] plaintext = ChaCha20.decrypt(RFC8439_KEY, RFC8439_NONCE, RFC8439_CIPHERTEXT_114); |
49 | | - assertArrayEquals(RFC8439_PLAINTEXT_114, plaintext); |
| 36 | + assertArrayEquals(RFC8439_PLAINTEXT_64, |
| 37 | + ChaCha20.decrypt(RFC8439_KEY, RFC8439_NONCE, RFC8439_CIPHERTEXT_64)); |
50 | 38 | } |
51 | 39 |
|
52 | 40 | @Test |
53 | 41 | public void testEncryptDecryptSymmetry() { |
54 | 42 | byte[] key = new byte[32]; |
55 | | - for (int i = 0; i < 32; i++) { |
56 | | - key[i] = (byte) i; |
57 | | - } |
58 | 43 | byte[] nonce = new byte[12]; |
59 | | - for (int i = 0; i < 12; i++) { |
60 | | - nonce[i] = (byte) (i + 100); |
61 | | - } |
62 | | - String originalText = "This is a test message to verify encrypt/decrypt symmetry."; |
63 | | - byte[] plaintext = originalText.getBytes(); |
64 | | - |
| 44 | + String message = "This is a test message to verify encrypt/decrypt symmetry."; |
| 45 | + byte[] plaintext = message.getBytes(); |
65 | 46 | byte[] ciphertext = ChaCha20.encrypt(key, nonce, plaintext); |
66 | | - byte[] decryptedText = ChaCha20.decrypt(key, nonce, ciphertext); |
67 | | - |
68 | | - assertArrayEquals(plaintext, decryptedText); |
69 | | - assertEquals(originalText, new String(decryptedText)); |
| 47 | + byte[] decrypted = ChaCha20.decrypt(key, nonce, ciphertext); |
| 48 | + assertArrayEquals(plaintext, decrypted); |
| 49 | + assertEquals(message, new String(decrypted)); |
70 | 50 | } |
71 | 51 |
|
72 | 52 | @Test |
73 | 53 | public void testEmptyPlaintext() { |
74 | 54 | byte[] empty = new byte[0]; |
75 | | - byte[] ciphertext = ChaCha20.encrypt(RFC8439_KEY, RFC8439_NONCE, empty); |
76 | | - assertArrayEquals(empty, ciphertext); |
77 | | - byte[] plaintext = ChaCha20.decrypt(RFC8439_KEY, RFC8439_NONCE, empty); |
78 | | - assertArrayEquals(empty, plaintext); |
| 55 | + assertArrayEquals(empty, ChaCha20.encrypt(RFC8439_KEY, RFC8439_NONCE, empty)); |
| 56 | + assertArrayEquals(empty, ChaCha20.decrypt(RFC8439_KEY, RFC8439_NONCE, empty)); |
79 | 57 | } |
80 | 58 |
|
81 | 59 | @Test |
82 | 60 | public void testInvalidKeySize() { |
83 | | - byte[] shortKey = new byte[31]; |
84 | | - byte[] longKey = new byte[33]; |
85 | 61 | byte[] nonce = new byte[12]; |
86 | 62 | byte[] data = {1, 2, 3}; |
87 | | - |
88 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(shortKey, nonce, data)); |
89 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(longKey, nonce, data)); |
90 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.decrypt(shortKey, nonce, data)); |
91 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.decrypt(longKey, nonce, data)); |
| 63 | + assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(new byte[31], nonce, data)); |
| 64 | + assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(new byte[33], nonce, data)); |
92 | 65 | } |
93 | 66 |
|
94 | 67 | @Test |
95 | 68 | public void testInvalidNonceSize() { |
96 | 69 | byte[] key = new byte[32]; |
97 | | - byte[] shortNonce = new byte[11]; |
98 | | - byte[] longNonce = new byte[13]; |
99 | 70 | byte[] data = {1, 2, 3}; |
100 | | - |
101 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(key, shortNonce, data)); |
102 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(key, longNonce, data)); |
103 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.decrypt(key, shortNonce, data)); |
104 | | - assertThrows(IllegalArgumentException.class, () -> ChaCha20.decrypt(key, longNonce, data)); |
| 71 | + assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(key, new byte[11], data)); |
| 72 | + assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(key, new byte[13], data)); |
105 | 73 | } |
106 | 74 |
|
107 | 75 | @Test |
108 | 76 | public void testNullInputs() { |
109 | 77 | byte[] key = new byte[32]; |
110 | 78 | byte[] nonce = new byte[12]; |
111 | 79 | byte[] data = {1, 2, 3}; |
112 | | - |
113 | 80 | assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(null, nonce, data)); |
114 | 81 | assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(key, null, data)); |
115 | 82 | assertThrows(IllegalArgumentException.class, () -> ChaCha20.encrypt(key, nonce, null)); |
116 | | - assertThrows(IllegalArgumentException.class, () -> Cha-Cha20.decrypt(null, nonce, data)); |
| 83 | + assertThrows(IllegalArgumentException.class, () -> ChaCha20.decrypt(null, nonce, data)); |
117 | 84 | assertThrows(IllegalArgumentException.class, () -> ChaCha20.decrypt(key, null, data)); |
118 | 85 | assertThrows(IllegalArgumentException.class, () -> ChaCha20.decrypt(key, nonce, null)); |
119 | 86 | } |
120 | 87 |
|
121 | | - // Helper to convert hex string to byte array for test vectors |
122 | 88 | private static byte[] hexStringToByteArray(String s) { |
123 | 89 | int len = s.length(); |
124 | | - if (len % 2 != 0) { |
125 | | - throw new IllegalArgumentException("Hex string must have even length"); |
126 | | - } |
| 90 | + if (len % 2 != 0) throw new IllegalArgumentException("Hex string must have even length"); |
127 | 91 | byte[] data = new byte[len / 2]; |
128 | 92 | for (int i = 0; i < len; i += 2) { |
129 | | - data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); |
| 93 | + data[i / 2] = |
| 94 | + (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)); |
130 | 95 | } |
131 | 96 | return data; |
132 | 97 | } |
|
0 commit comments