# 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: ```text 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 and truncate to 128 bits 6ba4f66eb2dd47e52c64c8d4ced78624 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. ## Keepalive Packets These packets have zero data. They will need to be handled separately. After We can look at the UDP length to figure out if it is a keepalive packet, this only serves to tell software if the connection has failed. We will need to support sending and receiving these at some point, most likely in hardware since they need to be authenticated, but they have no data. perhaps some tuser flag can be passed in to bypass the crypto. We can send in 16 bytes of zeroes but the user flag says to not actually send this to poly1305, and the result can just be dropped after resetting some kind of counter, or we can drop the data and just encapsulate the poly1305 tag. ## Padding is not always 16 bytes The packets are 16 byte aligned UNLESS this would bring the packet over the MTU. What this means in practice is that we might receive packets which are not 16 byte aligned. If we are decrypting a packet, the length must be what the packet actually is and not rounded up. We also need to be careful when we are sending out packets that we can't always go up to 1500 bytes. (Might have to tell end users to set their MTU to 1300 or something). If we are decrypting then, the width convert should not round up. Or... we can just put that in a different module and not have random rules in the crypto block itself. This also breaks the poly1305, because it is expecting exactly 128 bits every time, so it has a specific cycle for the lengths. BUT if the incoming data is not 16 byte aligned, then the lengths will be added at the wrong time. So, based on the length of the packet, we need to be adding the lengths at a varying position at the end of the packet. It might be split over 2 cycles, depending on what the length is. we can figure this out easily by simply taking the length of the packet (which we have counted already) modulo 16, aka & 0xf. In this case, the length of the packet is 1420, so the counter is 12. What this means is that the last packet is only 12 bytes, so we need to shift 4 bytes of the counter into the last data beat. How do we know its the last data beat? the upconvert module gives us last. Technically we calulate the total length based on this output. whatever. So in the sum state, we set the last flag based on upconvert_last. If this is true, we also need to check if upconvert_countm1 is 0xf, or if its smaller than that. if its 15, then we do what we normally do, just 1 extend the existing data. If it is not, then we need to do 15 - countm1 bytes of the length packet. * padding2 -- the padding is up to 15 zero bytes, and it brings the total length so far to an integral multiple of 16. If the length of the ciphertext was already an integral multiple of 16 bytes, this field is zero-length. wait... we should still be adding this padding ourselves... this is actually an embarassingly easy fix. 1420 bytes of inner ip 16 bytes of wireguard header 16 bytes of wireguard signature 8 bytes of udp 20 bytes of ipv4 14 bytes of ethernet so if you are just looking at wireguard itself, its max is 1420 + 32? or, is it that we set the MTU to 1420 which is the max sized of the encrypted packet, so we can't add any padding? OK in the width expander we expand to 1420 max. we could have a check at the begining that checks the total length. If it is larger than 1420 then we can send the packet to the CPU to fragment or do something with But really all computers that are on the network should have the MTU set to 1420 so that we can avoid this. One thing we still need to support is keepalive packets. These have no payload, but still need to be decrypted. The input FSM will take in just the encrypted wireguard packet, without the wireguard header. It will then strip off the tag and put it in a fifo for the output fsm to read. If it does this to a keepalive packet, there will be no data. If this happens, the input FSM will send in 64 bytes of dummy data, all zeroes, along with a keepalive signal. this signal will be stored along with the packet and when it is output to the output fsm, it will know to ignore the actual data. I think this can be done entirely outside of the crypto block. OK so that tells us what we need to do next, the pre and postformat FSM. preformat FSM removes the tag, postformat FSM adds the tag back for encyrpt, or compares the tag with the expected tag for decrypt. We need a metadata FIFO which tells us whether to encyrpt or decrypt. ohhhh right. what I really wanted to do today was synthesize this block and see what the timing looks like. We pass timing at 67 MHz. Lets try to reduce the number of flop stages in chacha to see if we can reduce the number of flops we use.