Understanding FCS in 802.11: CRC-32 Explained

FCS (Frame Check Sequence) is the name of the 802.11 MAC address frame field, which is calculated over both the 802.11 header and frame body. This calculation serves as a simple integrity check. If any part of the header or data is altered during transmission, the receiver can detect it by performing the same calculation and comparing the results.

It is important to note that this is not intended to be a security feature. A malicious user could easily tamper with the message and recalculate the FCS value. Instead, its purpose is to ensure data integrity, mainly to detect errors caused by noise on the communication channel.

  • The basis of CRC-32 is polynomial division, where the remainder is the CRC. This process occurs in the finite field GF(2), using the generator polynomial G(x):
    • G(x) = x32 +26+ x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1 This can be represented in hexadecimal as 0x4C11DB7, and in binary, it is: 100000100110000010001110110110111.

So, how is it calculated?

  1. The first step is to append 32 zeros to the input data.
  2. The 802.11 CRC implementation performs byte reflection, meaning each byte has its most significant bit moved to the position of the least significant bit (RefIn).
  3. Next, an initial XOR operation is applied with the value 0xFFFFFF.
  4. The data is then divided by the generator polynomial using XOR as the division operation. The division process continues until the remainder is smaller than the highest degree of the generator polynomial (x32)
  5. Once the division is complete, the bits are inverted. (RefOut)
  6. A final XOR operation is performed with 0xFFFFFF.
  7. Lastly, each byte is inverted.

Example
This is an example of a test vector for CCMP in 802.11, where a frame is shown along with its calculated FCS.

Input Data: 08 48 c3 2c 0f d2 e1 28 a5 7c 50 30 f1 84 44 08 ab ae a5 b8 fc ba 80 33 0c e7 00 20 76 97 03 b5 f3 d0 a2 fe 9a 3d bf 23 42 a6 43 e4 32 46 e8 0c 3c 04 d0 19 78 45 ce 0b 16 f9 76 23

Input Data is the 802.11 Header , CCMP Header , Encrypted Data .

In Binary we have: 000010000100100011000011001011000000111111010010111000010010100010100101011111000101000000110000111100011000010001000100000010001010101110101110101001011011100011111100101110101000000000110011000011001110011100000000001000000111011010010111000000111011010111110011110100001010001011111110100110100011110110111111001000110100001010100110010000111110010000110010010001101110100000001100001111000000010011010000000110010111100001000101110011100000101100010110111110010111011000100011

1 – Adding 32 bits

00001000010010001100001100101100000011111101001011100001001010001010010101111100010100000011000011110001100001000100010000001000101010111010111010100101101110001111110010111010100000000011001100001100111001110000000000100000011101101001011100000011101101011111001111010000101000101111111010011010001111011011111100100011010000101010011001000011111001000011001001000110111010000000110000111100000001001101000000011001011110000100010111001110000010110001011011111001011101100010001100000000000000000000000000000000

2 – Inverting each byte (RefIn)

The first byte is 00001000; when inverted, it becomes 00010000.

The second byte is 01001000; when inverted, it becomes 00010010.

The third byte is 11000011; when inverted, it remains 11000011.

By repeating this process for each byte and concatenating the results, we get:

‘00010000000100101100001100110100111100000100101110000111000101001010010100111110000010100000110010001111001000010010001000010000110101010111010110100101000111010011111101011101000000011100110000110000111001110000000000000100011011101110100111000000101011011100111100001011010001010111111101011001101111001111110111000100010000100110010111000010001001110100110001100010000101110011000000111100001000000000101110011000000111101010001001110011110100000110100010011111011011101100010000000000000000000000000000000000’

3 – Initial XOR

XOR of 0xFFFFFF with with the most significant bits, resulting in:

11101111111011010011110011001011111100000100101110000111000101001010010100111110000010100000110010001111001000010010001000010000110101010111010110100101000111010011111101011101000000011100110000110000111001110000000000000100011011101110100111000000101011011100111100001011010001010111111101011001101111001111110111000100010000100110010111000010001001110100110001100010000101110011000000111100001000000000101110011000000111101010001001110011110100000110100010011111011011101100010000000000000000000000000000000000′

4 – Division by Generator G(x)

Now, let’s align the first 33 bits (the length of G(x)) of the pre-processed data and perform a XOR operation:

111011111110110100111100110010111 ⊕ 100000100110000010001110110110111

= 011011011000110110110010000100000

By aligning the most significant bit of the pre-processed data with G(x) and performing the XOR operation, we will always reduce the degree of the polynomial.

011011011000110110110010000100000, the XOR operation will not affect the other bits, so you can think of it as if we now have the updated data.:

01101101100011011011001000010000011100000100101110000111000101001010010100111110000010100000110010001111001000010010001000010000110101010111010110100101000111010011111101011101000000011100110000110000111001110000000000000100011011101110100111000000101011011100111100001011010001010111111101011001101111001111110111000100010000100110010111000010001001110100110001100010000101110011000000111100001000000000101110011000000111101010001001110011110100000110100010011111011011101100010000000000000000000000000000000000′

Keep repeating the process: align G(x) with the most significant bit of the pre-processed data and perform the XOR operation.

0110110110001101101100100001000001 ⊕ 0100000100110000010001110110110111

I am demonstrating the right shift by adding zeros to the left of G(x)

The result of XOR is: 0010110010111101111101010111110110

I created a spreadsheet to illustrate this process.

The process continues, shifting G(x) and performing the XOR operation until the resulting CRC has a degree lower than G(x).

5 – Inverting bits (RefOut)

After the final XOR operation at degree x33 , we obtain 01000111011001101111000010011001 Now, inverting the bits gives us 10011001000011110110011011100010.

6 – Last XOR

The last 32 bits are XORed with 0xFFFFFF, resulting in 01100110111100001001100100011101 (0x66F0991D).

7 – The bytes are then appended to the frame in reverse order, giving 1D99F066.

This final value is added to the FCS field.

The Frame Check Sequence (FCS) in 802.11 provides a robust error detection mechanism using CRC-32 polynomial division. While it cannot prevent malicious tampering, it effectively detects transmission errors caused by interference or noise.

I hope you enjoyed this short post.

If you’d like to download the spreadsheet to follow along with the example, you can use the link below:

Stay tuned for more technical insights!

Thanks,

Diego Capassi

References

https://www.zlib.net/crc_v3.txt

IEEE Std 802.11™-2016, "IEEE Standard for Information technology—Telecommunications and information exchange between systems—Local and metropolitan area networks—Specific requirements—Part 11: Wireless LAN Medium Access Control (MAC) and Physical Layer (PHY) Specifications," IEEE, 2016.