v / vlib / x / crypto / chacha20poly1305 / psiv_test.v
212 lines · 194 sloc · 9.97 KB · 5d4b307219477b9b8b381757cff1cdf26339f905
Raw
1// Copyright (c) 2025 blackshirt.
2// Use of this source code is governed by an MIT license
3// that can be found in the LICENSE file.
4//
5// ChaCha20-Poly1305-PSIV test.
6// The test was adapted from Rust reference implementation of ChaCha20-Poly1305-PSIV
7module chacha20poly1305
8
9import rand
10import encoding.hex
11
12struct PsivKatTest {
13 key string
14 nonce string
15 ad string
16 tag string
17 pt string
18 ct string
19}
20
21// This Konwn Answer Test (KAT) test material was adapted from this link:
22// https://codeberg.org/Gusted/chacha20-poly1305-psiv/raw/branch/main/testdata/KAT/chacha20-poly1305-psiv.json
23//
24const psiv_kattest_data = [
25 PsivKatTest{
26 key: 'da5e8b4dc96a45cbf6868996cf9374968639a0e462993a5a4ce0f50c30387b4d'
27 nonce: 'baf068c8aa4fecc4485f0673'
28 ad: 'fb69bf2be138f95831e2f80cd6'
29 tag: 'b414135310ce4430cddcdc883d0b8533'
30 pt: '53bc'
31 ct: 'be6d'
32 },
33 PsivKatTest{
34 key: '8c5f631e8f9d29efa780d031232022a1d388aeb3f4d50592dd0d05d7cc5d4bc1'
35 nonce: 'e5ddfb49845b9dc73dfa4b10'
36 ad: '126ce447818b55571d725495e6614a6f'
37 tag: '6d5c42a83ad867653625c10f6ef05385'
38 pt: '31d5c270085a9f80ef90ebf732d928e8'
39 ct: 'ae44247314351bfca354474c71998195'
40 },
41 PsivKatTest{
42 key: '81432e9fa573a3e0aaa352f668a15b754c81502ed14c8ee6fc9ec0fb7100344d'
43 nonce: '78904fc961c52e65e13d302e'
44 ad: '663f149d40338426e81e5257991630202dd06ced12a2bca83f89dc7296541782'
45 tag: '4e43af952bb555961f2910633ece24fc'
46 pt: 'd0037b9ad2e00b2f698c26a791c0a67ee5a298929ce5ce2ba4999a5d89befa92'
47 ct: '6266ba8132a9193af5e9d8511c27166050e01571e55a3d27d3ab98e5b6a3c11b'
48 },
49 PsivKatTest{
50 key: 'faad2687fe7fcaad896a50dd005089a8fee8d95e79e3705d8136b5c45ef03d1a'
51 nonce: '2748826716da2a887ff63885'
52 ad: 'e85d908a97f6673421e1c4ad674d792e914972147191be9e2b1158f489eb47a41a594112cc74854c521d84029a959cfd'
53 tag: '5bf71bbda8e147f51524395009d1bbd2'
54 pt: '93dd95401f779b9fcd64261c94e861ed0947c378654dfe8cda6776a0a5e5d35e83cbb595cbd1b449b2278f17e81ac83f'
55 ct: 'e898487b800760a38f2727161264ac3e439606a94a0525f8eb0f4ade565cccbd25e3df2415b5cf71fbf9e871816de8d7'
56 },
57 PsivKatTest{
58 key: '6df081bcb85c439a1def71c8aaf69d3c885b992ba9c8271fd6c969f48e0b11c6'
59 nonce: 'ebb85860f597fc51715eb5d6'
60 ad: '3e00e080c3bffc3ec4b2e45dc09faaf9caae0a92fb74eb4b245c0a6aa0109d4932208478022ed98a6815cd57cd34e0cc2ad0b85a37cd03d955012e2f69e6a030'
61 tag: '8beaf75797d5f4c316b946cfb0de31ee'
62 pt: '8525879de99305c0fdc4edeb66dc229faaaebf111804253afba2a2878313dda53009531fee0ff5613e39ea694efe7093ae7b349851700e5f6075cd5cbd784df0'
63 ct: 'f194e1e2f8288afd6a8013d8a14eb32851fedb97ce9151c25ca7678ec7eb7eb62652e1176666799f379307e92c79263c948bc3b6cd9aeeded02d98fcedb1c94f'
64 },
65 PsivKatTest{
66 key: 'fce8cb2c75f84f98f44ae5a48dbbebe46536ebae80a054aeeaefbdceb3a1a956'
67 nonce: '86c43a87f6082ca50a2cf552'
68 ad: 'c1d6753875f2f1a7223ef8769b2136f171124ce1bf502ded1429439407f91fabcb16a354d958dba41a475de6137b2cbd4e4c2dcf3334e351d09f504db6f78ed783c92b622637304e4e50faab674040f8'
69 tag: '056b0315e62c7925d20495f5ee1824cc'
70 pt: 'caa171079f29612875d0bac2772e563add27281d91376bc72c1e9ad7fbff3af3910fe2c1d6432df3cda86ccf931fb439f22c492d3e1cc1dd5aecbd312045aacafffabf3d4ef8cadafa685a371f299c38'
71 ct: '19c86459a6b3aa8ce0a99849e995a633461642553c0b8b5935d67d796b3bfc46888575636dfa7c4f8343a302dcc0296089115d0713c8a84376dbdd3afdb15b41b494c35feab382a876dec957abf6990a'
72 },
73 PsivKatTest{
74 key: '8b119e13f8ad308e0d2a15284b45dad10de7c700f30148e3bf12c137eaa4125b'
75 nonce: 'ce81fc611e7f1160413e6d52'
76 ad: '65536d29922a97570818bda61970f2130260bd404447552dc1b8be4f4fb3a7d403479926c82e18846bed7c326b43b605cdd9a589f5467bbac21735ae8d6000477936e294dde2ab0e58da59aa847be8b85207e437c53c61c879e2365e62357203'
77 tag: 'c463dea4dc1b6ccd711aef9823da39e9'
78 pt: '4e38a5eda409058b6ccfc9759f73042b3a91fa7f85757346f8199567b92c4702524942753e3f1b06aa2bd0a65b60fc555bd6e737e121ef27084938c5149e42d9421feba9201d9a553128b84c7de17fe34754829307f11a184057a05fc408a2fb'
79 ct: 'd70af5d8999d64ac57cf477e5b49b22ef39c0b9cde96b10312bfda93bbe4f2d0901dc3081c0439df34fe991383c1773f27e7c13a04d7c52ff2696fc60d076428ab03d3e7ef19618861fa99577da350ec7745779660f093c0bec764b7afd2a7df'
80 },
81 PsivKatTest{
82 key: '9d1efe472184bcedc72fc0ef1e1462d8f1e5a62a7430e08df26d04026e6135d8'
83 nonce: 'b5141ce04e81f40113337293'
84 ad: 'dbb0d72f901383b584eb7ab4cd070ad0dae9de2904fb03ae39d09bf96b9d1cd75cbb196154323321b2ed8ecb7dc14ece42008c889cab063250d15050f3281e4df55afcef1f411837a8ccc7546f4c571846e38c5afd846eadae7171b01f93f57c841ad02819bc2bfc7de607ef19a73ec3'
85 tag: '4d12a32e158b02657bd4a7c9fa676529'
86 pt: 'd1e946809fb78c7e4e145870f70982cf950dcb18856fb96477f5fdfc3e542227456cb3c501494facd3c2f08a31bdb5198993db98346241fb54559a650067d97e45227fd89408d33c322b70eb081f5b5b3ddd084147bb0cf8826790deb4bb0b5cd34e92475f141353e6dbdc839ff44697'
87 ct: 'fd1422017e046f8940669371ed905eda2cc8f0b33586794bdbd99625ae7694c9c6bb0f6d3cf3353d0ed732241800063b45c16ca0ddf616d1f82ac1fbb2a42a96e6fde25e7439c064d45766bbcd277b8908e6561cb52bc494635a6d1b7c4d86b05bac9f647f9197efee25ebaa1ab9a22c'
88 },
89 PsivKatTest{
90 key: 'af8ce66d984e6507f1a810bf372324cd91e1d52a2d232148f4ad240ac1620059'
91 nonce: '7d2a7c08cdc00e531bd8ef56'
92 ad: '88d029543383ecbb02783ddd4419d0e5af3b389a666dff57882b5c49a1e0fb50bc78f7c8b2f0d5cabd832d3a10d8ee2d06a414ce4f5e645bb8b6c032e3f9d17cbe31b1313d5345f109c8251759c6a415dcc0340779b6bb40aea06ca323c6ab5690b713e1dea52fc3fe99926bacaca9d7888b6dd39569d534494a63cc602dcc9b'
93 tag: '12c1ee0e495c42ef85fc602fa4393934'
94 pt: '505c5d76005285cd7f4dd9196023d466b4bdae3e03a9ad5ef6b63def0a74442fe27132496935e010a6a15f785eaaa7367bc0b2ca9381873dbb80eb22701113ca5a996faf3d97c85bb16d62c581ee90ff73ebaa6f7a34f7a1acf784a854d73aecbb5aede2c197a73b1ad057a8d1c7e798e7a686a94dcfb8b1047bc9442d42c535'
95 ct: 'ce98619c023027e08eeb67c44b3801547191c01db1bb840164490da254f2196669347b9db669feb505a7126fe29c2c3eb1a5aeb7a46dbc8f3966316bfb39b8e189d5e5be09e42ac668a6dd218b72652d3851c2895982bb52f055a172b729aaa351dc213db04738395565b3e31b4a4bb84823e33066dda7aca1c473dff2eaf964'
96 },
97 PsivKatTest{
98 key: 'd58e34f08258aadad1cdf264b893c34b6d8c9ea4048640310b96b937e3e344e3'
99 nonce: '2b0a958f3e2dfc64431b3410'
100 ad: '88b216f01541dd888e4fd04443e638b4498758643583a7b04d13277d48e6096f3f4d33e3e387a1d90ac6d1a53c0574c1290099386834f803f48ff8c21b68d9650dcebd2232c9c2775bdf0fe28765bd1f5bf1392f9ba262264ef19f371fa1351055a74c8566098e9e861759ffe58e14cacc909fcaaeac4fbe7466613ddc09ded32cec9e4a014d64ab7eccafd58914ed1b'
101 tag: '91329d284bad6b733d3d48467d4cce45'
102 pt: '4be34f526d428683def93efc38d2c4f710ee7637aba54ff086d278128d3b68420c31982a772b15c5438158ed090d65c6f8f5cba4e8a320eea7d500d1c490fc6c59f8991ef58164f46c8b2685c08b2d85bff6b480d30d5ba14e3d1e96e28e880ed63a6c1738b6575334076a42522fb9b22c9164faa9fcc69881976e3773345dacf232a6b7e1a852ee6ddf8dd51f84e6b0'
103 ct: '06e5d414215a1e2aefdfae18c54fe721e21f163dcf6454babce5b3a5be2f219a110e9b893addc5177b6ad48ddd6a6f4981c6309f67e3101387646a8970ab13593c3ac62cd57c608fa7f5f4be8c214171eaa223e7d291c9ee2979339d74438ad7084526224e8df5909b37d6a0fb2a97be1b2f1d26ac8a8024edabe05ac8828f1eb8bb0a9236669bf75613264272e81f2a'
104 },
105]
106
107// Test for Known Answert Test (KAT) of ChaCha20-Poly1305-PSIV
108// based on https://codeberg.org/Gusted/chacha20-poly1305-psiv/raw/branch/main/testdata/KAT/chacha20-poly1305-psiv.json
109// Thanks to @tankf33der to point this test vectors.
110fn test_aead_psiv_for_kat_tests() ! {
111 for i, item in psiv_kattest_data {
112 key := hex.decode(item.key)!
113 nonce := hex.decode(item.nonce)!
114 ad := hex.decode(item.ad)!
115 tag := hex.decode(item.tag)!
116 pt := hex.decode(item.pt)!
117 ct := hex.decode(item.ct)!
118
119 // full aead ciphertext = ct + tag
120 mut cxt := []u8{}
121 cxt << ct
122 cxt << tag
123
124 // psiv encryption
125 enc_msg := psiv_encrypt(pt, key, nonce, ad)!
126 assert cxt == enc_msg
127
128 // decrypts it back
129 dec_msg := psiv_decrypt(enc_msg, key, nonce, ad)!
130 assert dec_msg == pt
131 }
132}
133
134// test for internal encryption routine
135fn test_psiv_insternal_encryption_of_encrypted_text_is_plaintext() ! {
136 for i := 0; i < 1024; i++ {
137 input := rand.bytes(i)!
138 key := rand.bytes(36)!
139 mut dkey := [36]u8{}
140 unsafe { vmemcpy(dkey, key.data, key.len) }
141 tag := rand.bytes(16)!
142 nonce := rand.bytes(12)!
143
144 mut out := []u8{len: input.len}
145 psiv_encrypt_internal(mut out, input, dkey, tag, nonce)!
146
147 // encrypting this output with the same params was result in original input
148 // make a clone of ciphertext output as an input into internal encrypt routine
149 text := out.clone()
150 psiv_encrypt_internal(mut out, text, dkey, tag, nonce)!
151 assert out == input
152 }
153}
154
155// test for AEAD of ChaCha20Poly1305-PSIV encrypt and decrypt
156fn test_psiv_aead_encryption_of_encrypted_text_is_plaintext() ! {
157 for i := 0; i < 1024; i++ {
158 input := rand.bytes(i)!
159 key := rand.bytes(32)!
160 nonce := rand.bytes(12)!
161 ad := rand.bytes(i)!
162
163 // encrypt message input
164 out := psiv_encrypt(input, key, nonce, ad)!
165 // decrypting this output with the same params was resulting an original input
166 awal := psiv_decrypt(out, key, nonce, ad)!
167 assert awal == input
168
169 // test with object-based construct
170 mut c := new_psiv(key)!
171 out1 := c.encrypt(input, nonce, ad)!
172 back1 := c.decrypt(out1, nonce, ad)!
173 assert back1 == input
174 unsafe { c.free() }
175 }
176}
177
178fn test_for_wrong_tag() ! {
179 for i := 0; i < 1024; i++ {
180 input := rand.bytes(i)!
181 key := rand.bytes(32)!
182 nonce := rand.bytes(12)!
183 ad := rand.bytes(i)!
184
185 mut out := psiv_encrypt(input, key, nonce, ad)!
186 out[out.len - tag_size] ^= 1
187
188 // decrypting would fail
189 _ := psiv_decrypt(out, key, nonce, ad) or {
190 assert err == error('unmatching tag')
191 continue
192 }
193 }
194}
195
196fn test_chacha20_core() ! {
197 // null input
198 s := [16]u32{}
199 x0 := chacha20_core(s)
200 assert x0 == s
201
202 // u32 input
203 u32input := [u32(0x61707865), 0x3320646e, 0x79622d32, 0x6b206574, 0x03020100, 0x07060504,
204 0x0b0a0908, 0x0f0e0d0c, 0x13121110, 0x17161514, 0x1b1a1918, 0x1f1e1d1c, 0x00000001,
205 0x09000000, 0x4a000000, 0x00000000]!
206 // expected output
207 exp_x1 := [u32(0xe4e7f110), 0x15593bd1, 0x1fdd0f50, 0xc47120a3, 0xc7f4d1c7, 0x0368c033,
208 0x9aaa2204, 0x4e6cd4c3, 0x466482d2, 0x09aa9f07, 0x05d7c214, 0xa2028bd9, 0xd19c12b5,
209 0xb94e16de, 0xe883d0cb, 0x4e3c50a2]!
210 x1 := chacha20_core(u32input)
211 assert x1 == exp_x1
212}
213