RFC 6479

IPsec Anti-Replay Algorithm without Bit Shifting

πŸ“… published January 2012, from ietf

RFC 6479 πŸ¦‹ IPsec Anti-Replay Algorithm without Bit Shifting

okay so this one is by X. Zhang and T. Tsou from Futurewei Technologies πŸ’… It's an Independent Submission (so it's not from an IETF working group πŸ™ˆ), it's Informational (not a Standards Track spec, so nobody's required to follow it 🫢), and it was published in January 2012 with ISSN 2070-1721 ✨. The header doesn't list any RFCs it obsoletes or updates, so it's standing on its own πŸ‘‘

Abstract ✨

bestie, this doc shows a different way to do the anti-replay checks and updates for IP Authentication Header (AH) and Encapsulating Security Protocol (ESP) πŸ”₯ The big win is that it gets rid of bit shifting entirely, and it means the anti-replay window gets adjusted way less often πŸ’–

Status of This Memo 🌸

This document is not an Internet Standards Track specification. It's published for informational purposes πŸŽ€

It's a contribution to the RFC Series, made independently of any other RFC stream. The RFC Editor picked to publish it at their discretion, and they make no statement about how useful it is for implementation or deployment 🧚 Documents the RFC Editor approves for publication aren't candidates for any level of Internet Standard, see Section 2 of RFC 5741 πŸ’…

Info about the current status of this doc, any errata, and how to give feedback can be found at http://www.rfc-editor.org/info/rfc6479 🌈

Copyright (c) 2012 IETF Trust and the persons identified as the document authors. All rights reserved. 🫢

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (http://trustee.ietf.org/license-info) as they stand on the publication date. Please read these carefully, because they spell out your rights and restrictions for this document πŸ’–

Table of Contents πŸ¦‹

1. Introduction ....................................................2
2. Description of New Anti-Replay Algorithm ........................3
3. Example of New Anti-Replay Algorithm ............................5
4. Security Considerations .........................................9
5. Normative References ............................................9
6. Acknowledgements ................................................9

1. Introduction ✨

"IP Authentication Header" [RFC4302] and "IP Encapsulating Security Payload (ESP)" [RFC4303] both define an anti-replay service that uses a sliding window mechanism 🌸 When a receiver turns it on, it uses an anti-replay window of size W. This window limits how far out of order a packet can be, compared to the packet with the highest sequence number authenticated so far πŸ”₯

The window can be written as a range [WB, WT], where WB=WT-W+1. Think of the whole thing as a string of bits. Each bit says whether a packet with that sequence number has been received and authenticated, so a replayed packet can be spotted and rejected πŸŽ€

Here's the flow. The receiver gets the sequence number S from the packet. If S is inside the window (S<=WT and S>=WB), the receiver checks the matching bit (at location S-WB) to see if that S has already been seen. If S<WB, the packet gets dropped. If S>WT and the packet is validated, the window moves forward by (S-WT) bits, so the new window becomes [WB+S-WT, S] πŸ’… The new bits in that new window get set to say no packets with those sequence numbers have arrived yet πŸ’œ

The typical implementation (like the integrity algorithm in [RFC4302]) does this by shifting (S-WT) bits. In normal cases packets show up in order, so you get constant updates and bit-shifting ops 😭

[RFC4302] and [RFC4303] set minimum window sizes of 32 and 64 πŸ“ But nobody's set a minimum or recommended window size beyond 64 packets. The window size needs to be based on realistic expectations for packet re-ordering 🧚

Now here's the tea πŸ«– A high-end, multi-core network processor with multiple crypto cores needs a window bigger than 64 or 128, because IPsec processing latency varies between cores. In that case, sliding the window is super costly, even with hardware acceleration doing the bit shifting πŸ’€ This document describes an alternate method that avoids bit shifting. It only talks about anti-replay processing on the receiving side ✨ The processing is always safe and has no interoperability effects. Even with a window bigger than the usual 32- or 64-bit window, no interoperability issues get caused πŸ‘‘

Any node that uses practices which could cause reordering beyond the usual 32- or 64-bit window may run into interoperability or performance problems. For example, if either the sending node or routers along the path cause significant re-ordering, the receiving IPsec endpoint may not be able to process the packets, because many current implementations don't support the extensions defined in this memo 😭 Reordering like this can also cause significant problems for transport and upper-layer protocols, so it's generally best avoided πŸ™ˆ

2. Description of the New Anti-Replay Algorithm πŸ’–

Here we present an easy way to update just the window index, which also cuts down on the number of window updates πŸ¦‹ The basic idea shows up in the figures below. Say we configure a window size W, made of M-1 blocks, where M is a power of two (2). Each block has N bits, where N is also a power of two (2). A block can be a byte (8 bits), a word (32 bits), or multiple words 🌈 The supported sliding window size is (M-1)*N. But it actually covers M blocks (four blocks, as shown in Figure 1) πŸŽ€ All M blocks get circulated and become a ring of blocks, each with N bits. This way, the supported sliding window (M-1 blocks) is always a subset window of the actual window as the window slides ✨

At the start, the actual window is defined by a low and high end index, [WB, WT], as shown in Figure 1 🌸

      +--------+--------+--------+--------+
      |xxxxxxcc|cccccccc|cccccccc|ccccc100|
      +--------+--------+--------+--------+
             ^                         ^
             |                         |
             WB                        WT

Figure 1: The sliding window [WB, WT], where WT is the last validated sequence number, and the supported window size W is WT-WB+1. (x = don't care bit, c = check bit) πŸ’…

If we get a packet with sequence number S greater than WT, we slide the window. But we only change the window index, by adding the difference (S-WT) to both WT and WB. (WB changes automatically, since the window size is fixed.) So S becomes the largest sequence number of the received packets πŸ”₯ Figure 2 shows the case where the packet with sequence number S=WT+1 arrives 🧚

   +--------+--------+--------+--------+
   |xxxxxxcc|cccccccc|cccccccc|ccccc110|
   +--------+--------+--------+--------+
           ^                         ^
           |                         |
           WB                        WT

Figure 2: The sliding window [WB, WT] after S=WT+1 πŸ’–

If S is in a different block from where WT is, we have to initialize all the bit values in the blocks to 0, with no bit shifting. If S passes several blocks, we have to initialize several blocks instead of just one πŸ“ Figure 3 shows the sequence number passing the block boundary. Right after the update, all the check bits should be 0 in the block where WT resides 😭

   +--------+--------+--------+--------+
   |ccc10000|xxxxcccc|cccccccc|cccccccc|
   +--------+--------+--------+--------+
       ^         ^
       |         |
       WT        WB

Figure 3: The sliding window [WB, WT] after S passes the boundary 🌈

After the update, the new window still covers the configured window. This means the configured sub-window also slides, following the sliding window protocol πŸ¦‹ The actual effect is kind of like shifting the block. That's why bit shifting is considered unnecessary here πŸ‘‘

Checking the window is also way easier and faster, because the sequence number check doesn't depend on the lowest index WB. It only depends on the sequence number of the received packet πŸ’… If we receive sequence number S, the bit location is the lowest several bits of the sequence number, which only depends on the block size (N). The block index is the several bits just before the location bits, which only depends on the window size (M) ✨

We don't specify how many redundancy bits are needed, except that the number should be a power of two (2) for computation efficiency πŸŽ€ On a 32-bit microprocessor, 32 might be a better choice, while 64 might be better on a 64-bit microprocessor. For a microprocessor with cache support, one cache line is also a good choice. It also depends on the size of the sliding window 🌸 If we have N redundancy bits (32 bits in the example above, for instance), we only need 1/N as many block updates compared to the bit-shifting algorithm in [RFC4302] 🫢

The cost of this method is the extra byte(s) used as a redundant window. The cost is minimal once the window is big enough πŸ’– Plus, the extra redundant bits aren't totally wasted! We can reuse the unused bits in the block where index WB resides. In other words, the supported window size could be (M-1)*N, plus the unused bits in the last block 🧚

3. Example of the New Anti-Replay Algorithm 🌈

Here's the example code that implements the anti-replay checks and updates from the previous sections πŸ’…

<CODE BEGINS>

/**
 * Copyright (c) 2012 IETF Trust and the persons identified as
 * authors of the code. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, is permitted pursuant to, and subject to the license
 * terms contained in, the Simplified BSD License set forth in Section
 * 4.c of the IETF Trust's Legal Provisions Relating to IETF Documents
 * (http://trustee.ietf.org/license-info).
 *
 */

/**
 * In this algorithm, the hidden window size must be a power of two,
 * for example, 1024 bits.  The redundant bits must also be a power of
 * two, for example 32 bits.  Thus, the supported anti-replay window
 * size is the hidden window size minus the redundant bits.  It is 992
 * in this example.  The size of the integer depends on microprocessor
 * architecture.  In this example, we assume that the software runs on
 * a 32-bit microprocessor.  So the size of the integer is 32.  In order
 * to convert the bitmap into an array of integers, the total number of
 * integers is the hidden window size divided by the size of the
 * integer.
 *
 * struct ipsec_sa contains the window and window related parameters,
 * such as the window size and the last acknowledged sequence number.
 *
 * all the value of macro can be changed, but must follow the rule
 * defined in the algorithm.
 */

#define SIZE_OF_INTEGER       32 /** 32-bit microprocessor */
#define BITMAP_LEN            (1024/ SIZE_OF_INTEGER)
                                /** in terms of the 32-bit integer */
#define BITMAP_INDEX_MASK     (IPSEC_BITMAP_LEN-1)
#define REDUNDANT_BIT_SHIFTS  5
#define REDUNDANT_BITS        (1<<REDUNDANT_BIT_SHIFTS)
#define BITMAP_LOC_MASK       (IPSEC_REDUNDANT_BITS-1)

int
ipsec_check_replay_window (struct ipsec_sa *ipsa,
                           uint32_t sequence_number)
{
    int bit_location;
    int index;

    /**
     * replay shut off
     */
    if (ipsa->replaywin_size == 0) {
        return 1;
    }

    /**
     * first == 0 or wrapped
     */
    if (sequence_number == 0) {
        return 0;
    }

    /**
     * first check if the sequence number is in the range
     */
    if (sequence_number>ipsa->replaywin_lastseq) {
        return 1;  /** larger is always good */
    }
    /**
     * The packet is too old and out of the window
     */
    if ((sequence_number + ipsa->replaywin_size) <
        ipsa->replaywin_lastseq) {
          return 0;
    }

    /**
     * The sequence is inside the sliding window
     * now check the bit in the bitmap
     * bit location only depends on the sequence number
     */
    bit_location = sequence_number&BITMAP_LOC_MASK;
    index = (sequence_number>>REDUNDANT_BIT_SHIFTS)&BITMAP_INDEX_MASK;

    /*
     * this packet has already been received
     */
    if (ipsa->replaywin_bitmap[index]&(1<<bit_location)) {
        return 0;
    }

    return 1;
}

int
ipsec_update_replay_window (struct ipsec_sa *ipsa,
                            uint32_t sequence_number)
{
    int bit_location;
    int index, index_cur, id;
    int diff;

    if (ipsa->replaywin_size == 0) {  /** replay shut off */
        return 1;
    }

    if (sequence_number == 0) {
        return 0;     /** first == 0 or wrapped */
    }
    /**
     * the packet is too old, no need to update
     */
    if ((ipsa->replaywin_size + sequence_number) <
        ipsa->replaywin_lastseq) {
           return 0;
    }

    /**
     * now update the bit
     */
    index = (sequence_number>>REDUNDANT_BIT_SHIFTS);

/**
 * first check if the sequence number is in the range
 */
if (sequence_number>ipsa->replaywin_lastseq) {
    index_cur = ipsa->replaywin_lastseq>>REDUNDANT_BIT_SHIFTS;
    diff = index - index_cur;
    if (diff > BITMAP_LEN) {  /* something unusual in this case */
        diff = BITMAP_LEN;
    }

    for (id = 0; id < diff; ++id) {
        ipsa->replaywin_bitmap[(id+index_cur+1)&BITMAP_INDEX_MASK]
            = 0;
    }

    ipsa->replaywin_lastseq = sequence_number;
}

    index &= BITMAP_INDEX_MASK;
    bit_location = sequence_number&BITMAP_LOC_MASK;

    /* this packet has already been received */
    if (ipsa->replaywin_bitmap[index]&(1<<bit_location)) {
    return 0;
}

    ipsa->replaywin_bitmap[index] |= (1<<bit_location);

    return 1;
}

4. Security Considerations πŸ”’βœ¨

okay bestie, this one is short but it's a big deal πŸ’… This document does not change [RFC4302] or [RFC4303]. It just gives you an alternate method for anti-replay, so the existing specs stay exactly as they are 🫢

5. Acknowledgements 🌸

The idea in this document came from the software design on one high-performance multi-core network processor πŸ”₯ The new network processor core integrates a dozen of crypto core in a distributed way, which makes hardware anti-replay service impossible 😭 so the team had to think outside the box πŸ¦‹

6. Normative References πŸ“š

  • [RFC4302] Kent, S., "IP Authentication Header", RFC 4302, December 2005.
  • [RFC4303] Kent, S., "IP Encapsulating Security Payload (ESP)", RFC 4303, December 2005.

Authors' Addresses πŸ’–

Xiangyang Zhang Futurewei Technologies 2330 Central Expressway Santa Clara, California 95051 USA

Phone: +1-408-330-4545 EMail: xiangyang.zhang@huawei.com

Tina Tsou (Ting Zou) Futurewei Technologies 2330 Central Expressway Santa Clara, California 95051 USA

Phone: +1-408-859-4996 EMail: tena@huawei.com

πŸ“¦ where this page comes from