| 188 | } |
| 189 | |
| 190 | void TestFSChaCha20(const std::string& hex_plaintext, const std::string& hexkey, uint32_t rekey_interval, const std::string& ciphertext_after_rotation) |
| 191 | { |
| 192 | auto key = ParseHex<std::byte>(hexkey); |
| 193 | BOOST_CHECK_EQUAL(FSChaCha20::KEYLEN, key.size()); |
| 194 | |
| 195 | auto plaintext = ParseHex<std::byte>(hex_plaintext); |
| 196 | |
| 197 | auto fsc20 = FSChaCha20{key, rekey_interval}; |
| 198 | auto c20 = ChaCha20{key}; |
| 199 | |
| 200 | std::vector<std::byte> fsc20_output; |
| 201 | fsc20_output.resize(plaintext.size()); |
| 202 | |
| 203 | std::vector<std::byte> c20_output; |
| 204 | c20_output.resize(plaintext.size()); |
| 205 | |
| 206 | for (size_t i = 0; i < rekey_interval; i++) { |
| 207 | fsc20.Crypt(plaintext, fsc20_output); |
| 208 | c20.Crypt(plaintext, c20_output); |
| 209 | BOOST_CHECK(c20_output == fsc20_output); |
| 210 | } |
| 211 | |
| 212 | // At the rotation interval, the outputs will no longer match |
| 213 | fsc20.Crypt(plaintext, fsc20_output); |
| 214 | auto c20_copy = c20; |
| 215 | c20.Crypt(plaintext, c20_output); |
| 216 | BOOST_CHECK(c20_output != fsc20_output); |
| 217 | |
| 218 | std::byte new_key[FSChaCha20::KEYLEN]; |
| 219 | c20_copy.Keystream(new_key); |
| 220 | c20.SetKey(new_key); |
| 221 | c20.Seek({0, 1}, 0); |
| 222 | |
| 223 | // Outputs should match again after simulating key rotation |
| 224 | c20.Crypt(plaintext, c20_output); |
| 225 | BOOST_CHECK(c20_output == fsc20_output); |
| 226 | |
| 227 | BOOST_CHECK_EQUAL(HexStr(fsc20_output), ciphertext_after_rotation); |
| 228 | } |
| 229 | |
| 230 | void TestPoly1305(const std::string &hexmessage, const std::string &hexkey, const std::string& hextag) |
| 231 | { |