Files
crypto/ChaCha20_Poly1305_64/doc/notes3.md
2026-07-26 17:35:24 -07:00

3.4 KiB

Data from wireshark

Ok lets work this out by hand. The encyrpted packet matches exaactly, so we know that the chacha20 part is correct, and this must include the first block which is used for the keys.

84 bytes rounded to nearest multiple of 16 is 96 bytes. plus 16 for tag is 112.

so we do know that wireguard is including the tag.

the first output of chacha20, which becomes the keys, is 118b9bfd676a3bd991483cb1746252272e032bfbf2597dafec72576a54d9263ae32c815b30dbd75e7000d9ec14aac879075ada63f40d22180741336f9132e14a

The bottm 256 bits of that is

e32c815b30dbd75e7000d9ec14aac879075ada63f40d22180741336f9132e14a

splitting that into 128 bit sections, we get

0xe32c815b30dbd75e7000d9ec14aac879 0x075ada63f40d22180741336f9132e14a

r_mask is 0x0ffffffc0ffffffc0ffffffc0fffffff

so out final values of r and s are

r = 0x075ada60040d22180741336c0132e14a s = 0xe32c815b30dbd75e7000d9ec14aac879

oh and p = 2**130-5

These values line up with what what we see in the hardware.

according to the spec, the algorithm for poly1305 is as follows:

         a = 0  /* a is the accumulator */
         p = (1<<130)-5
         for i=1 upto ceil(msg length in bytes / 16)
            n = le_bytes_to_num(msg[((i-1)*16)..(i*16)] | [0x01])
            a += n
            a = (r * a) % p
            end
         a += s
         return num_to_16_le_bytes(a)
         end

Here is the cipher, which is msg in this case b"\xa4\xeb\xc1.\xe3\xf9\x90\xda\x18\x03:\x07\x89\xc0N'\x00\xf6\xf5\xc2q\xd4*\xc4\xb4\xd6&.feI\xb4E\xa7Cn\x82\x9b\xff\xb6\xace\xf0VH\xbc\x0c9\x1f\xe7\xc5\x88Ht7a'\x16I@\x18\x8f\x03\xdb\xa6z\xf88\x8e\xaa\xb7lY6(\xbf\x9d\xc7\xbe\x034m\x91.\x91m\xad\x86%EEG\x016O-"

here it is split up into 16 byte chunks

b"\xa4\xeb\xc1.\xe3\xf9\x90\xda\x18\x03:\x07\x89\xc0N'" b'\x00\xf6\xf5\xc2q\xd4*\xc4\xb4\xd6&.feI\xb4' b'E\xa7Cn\x82\x9b\xff\xb6\xace\xf0VH\xbc\x0c9' b"\x1f\xe7\xc5\x88Ht7a'\x16I@\x18\x8f\x03\xdb" b'\xa6z\xf88\x8e\xaa\xb7lY6(\xbf\x9d\xc7\xbe\x03' b'4m\x91.\x91m\xad\x86%EEG\x016O-'

The length of the message is 96 bytes, so we have our 6 16 byte chunks.

the next step is to interpret these as little endian integers, then add a leading 1.

0x1274ec089073a0318da90f9e32ec1eba4 0x1b44965662e26d6b4c42ad471c2f5f600 0x1390cbc4856f065acb6ff9b826e43a745 0x1db038f18404916276137744888c5e71f 0x103bec79dbf2836596cb7aa8e38f87aa6 0x12d4f36014745452586ad6d912e916d34

DON'T FORGET ABOUT THE LENGTHS! The length of AAD is 0, and the length of the ciphertext is 96, that becomes

this is aad length, data_length be careful of the order, since aad length comes first, it is on the right side of this hex number, since its little endian.

0x100000000000000600000000000000000

And these also match the hardware, so we are doing good so far.

so after the first round, a = (r * n) % p, since a started at 0, a+=n is just n so a = 0xcfd86a9543d3377baf5be686c46d8491

ok looks good so far.

next is 0x312e451b2a526811c5bd976ce3c27d5e7, looks good as well. the next values in a row are

0x22097b74ef42792da5e02cf9dd8249776 0x2586a4ee24499da642fb6392be59137b2 0xff1ba4984e72db7199c786a00de9de1e 0x2850e6cbbf9869bf410976e82e2ee9b04 0x38878751382017086bc63eee8ba2cbdab

which all match still. So the final step is to add s,

0x46ba4f66eb2dd47e52c64c8d4ced78624

SO basically we need to appaned the length to the data when it is going through poly1305. poly1305 should be able to look at the input fifo and know when it is outputting the last valid beat. After this, we need to output the lengths.