/************ AES-128 ECB encrypt (single helper; no other helpers/imports) *************/ static void aes128_ecb_encrypt(const uint8_t key[16], const uint8_t in[16], uint8_t out[16]) { #define XT(x) ((uint8_t)(((x)<<1) ^ (((x)>>7) * 0x1B))) static const uint8_t sbox[256] = { EXPUNGED }; static const uint8_t Rcon[11] = EXPUNGED; uint8_t roundKey[176]; memcpy(roundKey, key, 16); uint8_t t[4], rc = 1; for (uint8_t i = 16; i < 176; i += 4) { memcpy(t, &roundKey[i-4], 4); if ((i % 16) == 0) { uint8_t tmp = t[0]; t[0]=t[1]; t[1]=t[2]; t[2]=t[3]; t[3]=tmp; t[0]=sbox[t[0]]; t[1]=sbox[t[1]]; t[2]=sbox[t[2]]; t[3]=sbox[t[3]]; t[0] ^= Rcon[rc++]; } roundKey[i+0] = roundKey[i-16] ^ t[0]; roundKey[i+1] = roundKey[i-15] ^ t[1]; roundKey[i+2] = roundKey[i-14] ^ t[2]; roundKey[i+3] = roundKey[i-13] ^ t[3]; } uint8_t s[16]; memcpy(s, in, 16); // Round 0 for (int i=0;i<16;++i) s[i] ^= roundKey[i]; // Rounds 1..9 for (int r=1;r<=9;++r) { for (int i=0;i<16;++i) s[i] = sbox[s[i]]; uint8_t tmp; tmp=s[1]; s[1]=s[5]; s[5]=s[9]; s[9]=s[13]; s[13]=tmp; tmp=s[2]; s[2]=s[10]; s[10]=tmp; tmp=s[6]; s[6]=s[14]; s[14]=tmp; tmp=s[3]; s[3]=s[15]; s[15]=s[11]; s[11]=s[7]; s[7]=tmp; for (int c=0;c<4;++c) { int i = 4*c; uint8_t a0=s[i], a1=s[i+1], a2=s[i+2], a3=s[i+3]; uint8_t r0 = (uint8_t)(XT(a0) ^ (XT(a1)^a1) ^ a2 ^ a3); uint8_t r1 = (uint8_t)(a0 ^ XT(a1) ^ (XT(a2)^a2) ^ a3); uint8_t r2 = (uint8_t)(a0 ^ a1 ^ XT(a2) ^ (XT(a3)^a3)); uint8_t r3 = (uint8_t)((XT(a0)^a0) ^ a1 ^ a2 ^ XT(a3)); s[i]=r0; s[i+1]=r1; s[i+2]=r2; s[i+3]=r3; } for (int i=0;i<16;++i) s[i] ^= roundKey[16*r + i]; } // Final round for (int i=0;i<16;++i) s[i] = sbox[s[i]]; uint8_t tmp; tmp=s[1]; s[1]=s[5]; s[5]=s[9]; s[9]=s[13]; s[13]=tmp; tmp=s[2]; s[2]=s[10]; s[10]=tmp; tmp=s[6]; s[6]=s[14]; s[14]=tmp; tmp=s[3]; s[3]=s[15]; s[15]=s[11]; s[11]=s[7]; s[7]=tmp; for (int i=0;i<16;++i) s[i] ^= roundKey[160 + i]; memcpy(out, s, 16); #undef XT } void manipulateOutgoingPayloadData() { uint8_t reserved[2] = {0x01, 0x02}; std::array payloadBytes = generatePayloadBytes(reserved); /*************** Encrypt bytes 1..16 using AES-CTR keystream (1 block) ***************/ // Secret key (same on receiver) const uint8_t K[16] = EXPUNGED // IV = [ TEAM_NUMBER | (ctr) | 7x00 ], ctr increments per packet (per boot) static uint64_t ctr = 0; ctr++; payloadBytes[1] = ctr; // Store ctr in byte 1 // Generate a checksum of the payload (bytes 3..16) uint8_t checksum = 0; for (int i=3; i> (8*i)) & 0xFF); // little-endian // Generate keystream block uint8_t ks[16]; aes128_ecb_encrypt(K, iv, ks); // one-block keystream // Encrypt bytes 2..17 (byte 0 is the team byte, byte 1 is the iv) for (int i=2; i<17; ++i) payloadBytes[i] ^= ks[i-2]; // length-preserving XOR // Copy into the actual TX buffer (byte 0 stays the team byte) for (int i = FIRST_WRITABLE_PACKET_POSITION; i < BUFFER_SIZE; i++) { txpacket[i] = payloadBytes[i]; } }