Poly1305
Poly1305 is an AES-based MAC algorithm by D. J. Bernstein specified at Poly1305-AES: A state-of-the-art message-authentication code. Poly1305 computes a 16-byte authenticator of a message of any length, using a 16-byte nonce and a 32-byte secret key.
ChaCha20 combined with Poly1305 results in an authenticated encryption scheme. Crypto++ provides the authenticated encryption scheme using the ChaCha20Poly1305 class. Also see XChaCha20Poly1305, which is ChaCha20Poly1305 hardened against nonce misuse.
All Crypto++ hashes derive from HashTransformation
. The base class provides functions like Update
, Final
and Verify
. You can swap-in any hash for any other hash in your program. You can also use ChannelSwitch
to send data to multiple hashes at the same time.
Sample Programs
There are two sample programs below. The first sample program below demonstrates a Poly1305 using filters (see pipelining). The second sample program uses HashTransformation
member functions.
Pipelines
#include "cryptlib.h" #include "poly1305.h" #include "filters.h" #include "osrng.h" #include "aes.h" #include "hex.h" #include <iostream> #include <iomanip> #include <string> int main(int argc, char* argv) { using namespace CryptoPP; AutoSeededRandomPool prng; SecByteBlock key(32); prng.GenerateBlock(key, key.size()); std::string plain = "Poly1305 Test"; std::string mac, encoded; /*********************************\ \*********************************/ // Pretty print key encoded.clear(); StringSource ss1(key, key.size(), true, new HexEncoder( new StringSink(encoded) ) // HexEncoder ); // StringSource std::cout << "key: " << encoded << std::endl; std::cout << "plain: " << plain << std::endl; /*********************************\ \*********************************/ try { Poly1305<AES> poly1305(key, key.size()); StringSource ss2(plain, true, new HashFilter(poly1305, new StringSink(mac) ) // HashFilter ); // StringSource } catch(const CryptoPP::Exception& e) { std::cerr << e.what() << std::endl; exit(1); } /*********************************\ \*********************************/ // Pretty print encoded.clear(); StringSource ss3(mac, true, new HexEncoder( new StringSink(encoded) ) // HexEncoder ); // StringSource std::cout << "mac: " << encoded << std::endl; return 0; }
A typical output is shown below. Note that each run will produce different results because the key is randomly generated.
$ ./test.exe key: 96D246CF3B7159C4E3A532E9DBF9B90061D7FF14977053BC227F9AB4AD74BA0D plain: Poly1305 Test mac: 1EA2F653C4E45C81732E72E09A53D8E2
To verify a Poly1305 on a message, use a HashVerificationFilter.
try { Poly1305<AES> poly1305(key, key.size()); const int flags = HashVerificationFilter::THROW_EXCEPTION | HashVerificationFilter::HASH_AT_END; StringSource(plain + mac, true, new HashVerificationFilter(poly1305, NULL, flags) ); // StringSource std::cout << "Verified message" << std::endl; } catch(const CryptoPP::Exception& e) { std::cerr << e.what() << std::endl; ... }
We can tamper with a message as follows, which will cause the HashVerificationFilter
to throw the exception, HashVerificationFilter: message hash or MAC not valid:
Poly1305 poly1305(key, key.size()); // Tamper with message plain[0] ^= 0x01; // Tamper with MAC mac[0] ^= 0x01; StringSource(plain + mac, true, new HashVerificationFilter(poly1305, NULL, THROW_EXCEPTION | HASH_AT_END) ); // StringSource
Switching to another block cipher, such as Camellia, is as simple as the following:
Poly1305<Camellia> poly1305(key, key.size()); StringSource(plain, true, new HashFilter(poly1305, new StringSink(mac) ) // HashFilter ); // StringSource
HashTransformation
Below is an example of using HashTransformation
member functions to calculate a Poly1305. Internally, pipelines do this for you.
#include "cryptlib.h" #include "poly1305.h" #include "files.h" #include "aes.h" #include "hex.h" #include <string> #include <iostream> int main(int argc, char* argv[]) { using namespace CryptoPP; const byte m[28] = { 0x5,0x8,0xC,0xE,0x1,0xE,0x6,0x0,0x1,0x1, 0x1,0x1,0x1,0x1,0x1,0x1,0x6,0x4,0x6,0x1, 0x7,0x4,0x6,0x1,0x0,0x0,0x0,0x0 }; const byte k[32] = { 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, 0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1,0x1, 0x1,0x1 }; HexEncoder hex(new FileSink(std::cout)); Poly1305<AES> poly1305(k, sizeof(k)); poly1305.Update(m, sizeof(m)); byte d[Poly1305<AES>::DIGESTSIZE]; poly1305.Final(d); std::cout << "Message: "; hex.Put(m, sizeof(m)); hex.MessageEnd(); std::cout << std::endl; std::cout << "Mac: "; hex.Put(d, sizeof(d)); hex.MessageEnd(); std::cout << std::endl; return 0; }
The program produces the expected output:
$ ./test.exe Message: 05080C0E010E06000101010101010101060406010704060100000000 Mac: 202A1A4DC096A54EC8E65FF59BDB752C
Downloads
No downloads available.