| 137 | } |
| 138 | |
| 139 | void TestChaCha20(const std::string &hex_message, const std::string &hexkey, ChaCha20::Nonce96 nonce, uint32_t seek, const std::string& hexout) |
| 140 | { |
| 141 | auto key = ParseHex<std::byte>(hexkey); |
| 142 | assert(key.size() == 32); |
| 143 | auto m = ParseHex<std::byte>(hex_message); |
| 144 | ChaCha20 rng{key}; |
| 145 | rng.Seek(nonce, seek); |
| 146 | std::vector<std::byte> outres; |
| 147 | outres.resize(hexout.size() / 2); |
| 148 | assert(hex_message.empty() || m.size() * 2 == hexout.size()); |
| 149 | |
| 150 | // perform the ChaCha20 round(s), if message is provided it will output the encrypted ciphertext otherwise the keystream |
| 151 | if (!hex_message.empty()) { |
| 152 | rng.Crypt(m, outres); |
| 153 | } else { |
| 154 | rng.Keystream(outres); |
| 155 | } |
| 156 | BOOST_CHECK_EQUAL(hexout, HexStr(outres)); |
| 157 | if (!hex_message.empty()) { |
| 158 | // Manually XOR with the keystream and compare the output |
| 159 | rng.Seek(nonce, seek); |
| 160 | std::vector<std::byte> only_keystream(outres.size()); |
| 161 | rng.Keystream(only_keystream); |
| 162 | for (size_t i = 0; i != m.size(); i++) { |
| 163 | outres[i] = m[i] ^ only_keystream[i]; |
| 164 | } |
| 165 | BOOST_CHECK_EQUAL(hexout, HexStr(outres)); |
| 166 | } |
| 167 | |
| 168 | // Repeat 10x, but fragmented into 3 chunks, to exercise the ChaCha20 class's caching. |
| 169 | for (int i = 0; i < 10; ++i) { |
| 170 | size_t lens[3]; |
| 171 | lens[0] = m_rng.randrange(hexout.size() / 2U + 1U); |
| 172 | lens[1] = m_rng.randrange(hexout.size() / 2U + 1U - lens[0]); |
| 173 | lens[2] = hexout.size() / 2U - lens[0] - lens[1]; |
| 174 | |
| 175 | rng.Seek(nonce, seek); |
| 176 | outres.assign(hexout.size() / 2U, {}); |
| 177 | size_t pos = 0; |
| 178 | for (int j = 0; j < 3; ++j) { |
| 179 | if (!hex_message.empty()) { |
| 180 | rng.Crypt(std::span{m}.subspan(pos, lens[j]), std::span{outres}.subspan(pos, lens[j])); |
| 181 | } else { |
| 182 | rng.Keystream(std::span{outres}.subspan(pos, lens[j])); |
| 183 | } |
| 184 | pos += lens[j]; |
| 185 | } |
| 186 | BOOST_CHECK_EQUAL(hexout, HexStr(outres)); |
| 187 | } |
| 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 | { |