XChaCha20Poly1305

From Crypto++ Wiki
Jump to navigation Jump to search

XChaCha20Poly1305 is a modified version of ChaCha20Poly1305 created by Scott Arciszewski that is hardened against nonce misuse. Crypto++ provides the algorithm by way of the XChaCha20Poly1305 class. XChaCha20Poly1305 only offers a 32-byte key with a 24-byte nonce and 20 rounds. Also see Issue 727, XChaCha20 support and draft-arciszewski-xchacha, XChaCha: eXtended-nonce ChaCha and AEAD_XChaCha20_Poly1305.

Crypto++ added XChaCha20Poly1305 to the library version 8.1. Also see Issue 724 and Commit 76b47204dfc4.

A related page is ChaCha20Poly1305.

Example

The example below uses a test vector from the Botan library.

#include "cryptlib.h"
#include "chachapoly.h"
#include "filters.h"
#include "files.h"
#include "hex.h"

int main(int argc, char* argv[])
{
    using namespace CryptoPP;

    const byte pt[] = {
        0x4c,0x61,0x64,0x69,0x65,0x73,0x20,0x61,0x6e,0x64,0x20,0x47,0x65,0x6e,0x74,0x6c,
        0x65,0x6d,0x65,0x6e,0x20,0x6f,0x66,0x20,0x74,0x68,0x65,0x20,0x63,0x6c,0x61,0x73,
        0x73,0x20,0x6f,0x66,0x20,0x27,0x39,0x39,0x3a,0x20,0x49,0x66,0x20,0x49,0x20,0x63,
        0x6f,0x75,0x6c,0x64,0x20,0x6f,0x66,0x66,0x65,0x72,0x20,0x79,0x6f,0x75,0x20,0x6f,
        0x6e,0x6c,0x79,0x20,0x6f,0x6e,0x65,0x20,0x74,0x69,0x70,0x20,0x66,0x6f,0x72,0x20,
        0x74,0x68,0x65,0x20,0x66,0x75,0x74,0x75,0x72,0x65,0x2c,0x20,0x73,0x75,0x6e,0x73,
        0x63,0x72,0x65,0x65,0x6e,0x20,0x77,0x6f,0x75,0x6c,0x64,0x20,0x62,0x65,0x20,0x69,
        0x74,0x2e
    };

    const byte aad[] = {
        0x50,0x51,0x52,0x53,0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7
    };

    const byte key[] = {
        0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
        0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f
    };

    const byte iv[] = {
        0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
        0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x58
    };

    byte ct[sizeof(pt)], rt[sizeof(ct)], mac[16];

    XChaCha20Poly1305::Encryption enc;
    enc.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    enc.EncryptAndAuthenticate(ct, mac, sizeof(mac), iv, sizeof(iv), aad, sizeof(aad), pt, sizeof(pt));

    std::cout << "Plain: ";
    StringSource(pt, sizeof(pt), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << "\n" << std::endl;

    std::cout << "Cipher: ";
    StringSource(ct, sizeof(ct), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << std::endl;

    std::cout << "MAC: ";
    StringSource(mac, sizeof(mac), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << "\n" << std::endl;

    XChaCha20Poly1305::Decryption dec;
    dec.SetKeyWithIV(key, sizeof(key), iv, sizeof(iv));
    dec.DecryptAndVerify(rt, mac, sizeof(mac), iv, sizeof(iv), aad, sizeof(aad), ct, sizeof(ct));

    std::cout << "Recover: ";
    StringSource(rt, sizeof(rt), true, new HexEncoder(new FileSink(std::cout)));
    std::cout << "\n" << std::endl;

    return 0;
}

Running the code results in the following output.

$ ./test.exe
Plain: 4C616469657320616E642047656E746C656D656E206F662074686520636C617373206F662
02739393A204966204920636F756C64206F6666657220796F75206F6E6C79206F6E6520746970206
66F7220746865206675747572652C2073756E73637265656E20776F756C642062652069742E

Cipher: 65032F227E672AAF3D102E073E4F1C386ABAB35EE19A50DEB91A4AE3AEB7C687BF89E39F
C459675DEB350C69BB5B7B372BEA9B0561A5046C7AEEDCD2456FAA4A301A137209D61DA415499A44
CBF6D867E019831B89BEA709A3A706026C910C523F814911E77B826AF350A9FD2A93097FA84B
MAC: 7EA2404B69A2A6182BE9992CE53701BF

Recover: 4C616469657320616E642047656E746C656D656E206F662074686520636C617373206F6
6202739393A204966204920636F756C64206F6666657220796F75206F6E6C79206F6E65207469702
0666F7220746865206675747572652C2073756E73637265656E20776F756C642062652069742E

Benchmarks

XChaCha20Poly1305 benchmarks are respectable, and will likely exceed exceed non-AES accelerated authentication encryption modes of operations. The comparison below is from a Skylake Core-i5 6400 @ 2.7 GHz. AES and polynomial multiply are accelerated with AES-NI, and ChaCha is accelerated with AVX.

Algorithm MB/s Cpb
AES/GCM 2855 0.90
AES/CCM 847 3.04
AES/EAX 844 3.05
XChaCha20/Poly1305 659 3.91

As another example, here are the results from a PowerMac G5 @ 2.0 GHz. AES and polynomial multiply are not accelerated, and ChaCha is accelerated with Altivec.

Algorithm MB/s Cpb
AES/GCM 43 44.3
AES/CCM 28 68.5
AES/EAX 28 68.5
XChaCha20/Poly1305 80 23.87

As a final example, here are the results from a LeMake HiKey ARMv8 @ 1.2 GHz. AES and polynomial multiply are accelerated with crypto extensions, and ChaCha is accelerated with ASIMD (NEON).

Algorithm MB/s Cpb
AES/GCM 291 3.93
AES/CCM 169 6.77
AES/EAX 166 6.88
XChaCha20/Poly1305 96 11.98