安全協議系列(二)----CCM與CCMP

CCMP(CTR with CBC-MAC Protocol) 是 IEEE 802.11i 中推出使用基於 AES 的 CCM 模式的安全加密協議。
與原來脆弱的 WEP 算法及臨時補救措施 TKIP 協議相比,它具備更好的安全性,在 WiFi 中獲得普遍的應用。算法

CCM(Counter with CBC-MAC) 定義在 RFC 3610 中,它是一種使用分組算法(例如 AES)進行數據認證和加密的通用模式。安全

下面是 RFC 3610 中重要部分的中文註釋說明網絡

1.  Introductionapp

   Counter with CBC-MAC (CCM) is a generic authenticated encryption block cipher mode.
   CCM 對明文數據(記爲 m,其長度記爲 l(m))進行分組加密和認證,處理結果同時包括密文和認證字段
curl

   CCM is defined for use with 128-bit block ciphers, such as the Advanced Encryption Standard (AES).
   專門用於 block size 爲 128 位的分組加密算法,如 AES
ide

2.  CCM Mode Specification函數

   For the generic CCM mode there are two parameter choices.
   CCM 有 2 個參數選項
測試

   The first choice is M, the size of the authentication field.
   Valid values are 4, 6, 8, 10, 12, 14, and 16 octets.
   第 1 個選項: M -- 輸出的認證字段長度(單位:字節),取值範圍:4, 6, 8, 10, 12, 14, and 16
ui

   The second choice is L, the size of the length field.
   Valid values of L range between 2 octets and 8 octets.
   第 2 個選項: L -- 表示 l(m) 值的字節數( l(m) < 2^(8L) ),取值範圍:2-8
this

   將 M 和 L 轉換爲 M' 和 L'(以便容納在一個字節中),轉換關係以下
     Name  Description                               Size    Encoding
     ----  ----------------------------------------  ------  --------
     M'    Number of octets in authentication field  3 bits  (M-2)/2
     L'    Number of octets in length field          3 bits  L-1

   CCMP 協議規定:M = 8 L = 2, 即 m 最長爲 65535 字節,認證字段爲 8 字節

2.1.  Inputs -- 認證加密 m 所需的參數

   1.  An encryption key K suitable for the block cipher.
       分組密鑰 K

   2.  A nonce N of 15-L octets.  Within the scope of any encryption key K,
       the nonce value MUST be unique.
       隨機數 N,15-L 字節長,在 K 的生命過程當中要確保 N 不被重複使用

   3.  The message m, consisting of a string of l(m) octets where 0 <=
       l(m) < 2^(8L).  The length restriction ensures that l(m) can be
       encoded in a field of L octets.
       此段內容上面已講得很清楚

   4.  Additional authenticated data a, consisting of a string of l(a)
       octets where 0 <= l(a) < 2^64.  This additional data is
       authenticated but not encrypted, and is not included in the
       output of this mode.  It can be used to authenticate plaintext
       packet headers, or contextual information that affects the
       interpretation of the message.  Users who do not wish to
       authenticate additional data can provide a string of length zero.
       附加認證數據 a,用於數據的完整性校驗(不參與加密運算),可選
       一般用於認證 報文頭的明文字段 或 對消息理解有影響的上下文

   The inputs are summarized as:

      Name  Description                                 Size
      ----  -----------------------------------         -----------------------
      K     Block cipher key/分組加密密鑰                 Depends on block cipher
      N     Nonce/隨機數                                 15-L octets
      m     Message to authenticate and encrypt         l(m) octets
      a     Additional authenticated data/附加認證數據    l(a) octets

2.2.  Authentication -- 生成認證字段

   The first step is to compute the authentication field T.  This is
   done using CBC-MAC [MAC].  We first define a sequence of blocks B_0,
   B_1, ..., B_n and then apply CBC-MAC to these blocks.
   第一步計算認證字段 T,使用 CBC-MAC 算法,該算法涉及輸入分組 B_0,B_1, ..., B_n

   The first block B_0 is formatted as follows, where l(m) is encoded in
   most-significant-byte first order:
   第一個數據分組 B_0 構成以下
      Octet Number   Contents
      ------------   ---------
      0              Flags          1    字節
      1 ... 15-L     Nonce N        15-L 字節
      16-L ... 15    l(m)           L    字節(L 的值見 Flags 字節)

   Within the first block B_0, the Flags field is formatted as follows:
   分組 B_0 中的首字節 Flags 構成以下
      Bit Number   Contents
      ----------   ----------------------
      7            Reserved (always zero)
      6            Adata
      5 ... 3      M' (1--7) = (M-2)/2  (M:4--16)
      2 ... 0      L' (1--7) = L-1      (L:2--8)
   Another way say the same thing is:  Flags = 64*Adata + 8*M' + L'.

   B_0 構成以下
    長度   1      15-L           L
   +----+-----+-----------+------------+
   |字節 |  0  | 1 .. 15-L | 16-L .. 15 |
   +----+-----+-----------+------------+
   |內容 |Flags|  Nonce N  |  m 的長度  |
   +----+-----+-----------+------------+
       /      \                  ^
      /        \                 |
     /          \     L -- m 的長度表示範圍
    /            \     (L 越大,m 能夠越長)
   / Flags 展開後  \              |
   +----+-+-----+-+-+-+-+-+-+    |L'(L) 決定
   |位  |7|  6  |5|4|3|2|1|0|    |Nonce 的長度
   +----+-+-----+-+-+-+-+-+-+    |
   |內容 |0|Adata| M'  | L'  | ---+
   +----+-+-----+-+-+-+-+-+-+

   The Adata bit is set to zero if l(a)=0, and set to one if l(a)>0.
   若是 Bit6(Adata 位)=0,表示要生成附加認證數據 a,不然表示沒有

   If l(a)>0 (as indicated by the Adata field), then one or more blocks
   of authentication data are added.  These blocks contain l(a) and a
   encoded in a reversible manner.  We first construct a string that
   encodes l(a).
   生成附加認證數據 a,須要構造認證數據塊(一個或多個),數據塊編碼以下

   If 0 < l(a) < (2^16 - 2^8), then the length field is encoded as two
   octets which contain the value l(a) in most-significant-byte first
   order.
   a 長度 < 65536-256,此狀況比較廣泛

   The length encoding conventions are summarized in the following
   table.  Note that all fields are interpreted in most-significant-byte
   first order.

    First two octets   Followed by       Comment
    -----------------  ----------------  -------------------------------
    0x0000             Nothing           Reserved
    0x0001 ... 0xFEFF  Nothing           For 0 < l(a) < (2^16 - 2^8)
    0xFF00 ... 0xFFFD  Nothing           Reserved
    0xFFFE             4 octets of l(a)  For (2^16 - 2^8) <= l(a) < 2^32
    0xFFFF             8 octets of l(a)  For 2^32 <= l(a) < 2^64

   The blocks encoding a are formed by concatenating this string that
   encodes l(a) with a itself, and splitting the result into 16-octet
   blocks, and then padding the last block with zeroes if necessary.
   These blocks are appended to the first block B0.
   將 l(a)||a 分紅 16 字節長的分組,必要時最後一個分組添加 0x00 補齊
   這些分組依次添加到 B_0 後面(記爲 B_一、B_2……)

   After the (optional) additional authentication blocks have been
   added, we add the message blocks.  The message blocks are formed by
   splitting the message m into 16-octet blocks, and then padding the
   last block with zeroes if necessary.  If the message m consists of
   the empty string, then no blocks are added in this step.
   附加認證分組添加後,咱們構造明文分組,將 m 分紅 16 字節長的分組
   必要時最後一個分組補 0 對齊(若是 m 爲空串,則此步省略)

   The result is a sequence of blocks B0, B1, ..., Bn.  The CBC-MAC is
   computed by:
   最終獲得 B_0||附加認證分組||明文分組,按下列公式計算 CBC-MAC

      X_1   := E( K, B_0 )
      X_i+1 := E( K, X_i XOR B_i )  for i=1, ..., n
      T     := first-M-bytes( X_n+1 ) -- T 做爲 MAC 值

        B_0       B_1       B_2               B_n
         |         |         |                 |
         |         V         V                 V
         |    +-->XOR   +-->XOR           +-->XOR
         |    |    |    |    |            |    |
         V    |    V    |    V            |    V
       +----+ | +----+  | +----+          | +----+
   K-->|加密 | | |加密|  | |加密 |   ...    | |加密|
       +----+ | +----+  | +----+          | +----+
         |    |    |    |    |            |    |
         +----+    +----+    +-->      ->-+    |
         |         |         |         X_n     |
         V         V         V                 V
        X_1       X_2       X_3               X_n+1

2.3.  Encryption -- 生成密文

   To encrypt the message data we use Counter (CTR) mode.  We first
   define the key stream blocks by:
   使用 Counter (CTR) 模式加密,首先計算以下密鑰流
      S_i := E( K, A_i )   for i=0, 1, 2, ...

   The values A_i are formatted as follows, where the Counter field i is
   encoded in most-significant-byte first order:

      Octet Number   Contents
      ------------   ---------
      0              Flags
      1 ... 15-L     Nonce N
      16-L ... 15    Counter i

   The Flags field is formatted as follows:

      Bit Number   Contents
      ----------   ----------------------
      7            Reserved (always zero)
      6            Reserved (always zero)
      5 ... 3      Zero
      2 ... 0      L'

   Another way say the same thing is:  Flags = L'.

   A_i 構成以下
    長度   1      15-L           L
   +----+-----+-----------+------------+
   |字節 |  0  | 1 .. 15-L | 16-L .. 15 |
   +----+-----+-----------+------------+
   |內容 |Flags|  Nonce N  | Counter i  | -- Counter i 的值可以在 L 字節內表示
   +----+-----+-----------+------------+    (由於 i <= l(m))
       /      \                  ^
      /        \                 |
     /          \                |
    /            \               |
   / Flags 展開後  \              |
   +----+-+-----+-+-+-+-+-+-+    |L'(L) 決定
   |位   |7|Adata|5|4|3|2|1|0|    |Nonce 的長度
   +----+-+-----+-+-+-+-+-+-+    |
   |內容 |0|  0  |M'=0 | L'  | ---+
   +----+-+-----+-+-+-+-+-+-+
                 |
                 M' 不一樣於 B_0(B_0 中始終不爲 0)

   The message is encrypted by XORing the octets of message m with the
   first l(m) octets of the concatenation of S_1, S_2, S_3, ... .  Note
   that S_0 is not used to encrypt the message.
   明文與密鑰流異或,獲得密文,S_0 不用於加密,但參與數據校驗
        A_0       A_1        A_2        A_n
         |         |          |          |
         V         V          V          V
       +----+   +----+     +----+     +----+
   K-->|加密 |   |加密|     | 加密| ... |加密|
       +----+   +----+     +----+     +----+
         |         |          |          |
         |         |S_1       |S_2       |S_n
         |         |          |          |       密鑰: S_1 | S_2 | ... | S_n
         |         V          V          V       XOR
         |  M_1-->XOR  M_2-->XOR  M_n-->XOR      明文: M_1 | M_2 | ... | M_n
         |         |          |          |        |
         V         V          V          V        V
        S_0       C_1        C_2        C_n      密文: C_1 | C_2 | ... | C_n

   The authentication value U is computed by encrypting T with the key
   stream block S_0 and truncating it to the desired length.
   T 與 S_0 的異或結果取前 M 字節,獲得認證字段
      U := T XOR first-M-bytes( S_0 )

2.4.  Output -- 最終輸出

       取前 l(m) 字節                        取前 M 字節
       =================================    ============
       S_1/E(K,A_1) | S_2/E(K,A_2) | ... || S_0/E(K,A_0)
   XOR m                                 || X_n+1
   -----------------------------------------------------
     = 最終輸出 c

   其中 X_i 計算以下
        X_1   := E( K, B_0 )
        X_i+1 := E( K, X_i XOR B_i )  for i=1, ..., n

8.  Test Vectors -- 使用測試數據進行計算演示

   =============== Packet Vector #1 ==================
   AES Key =  C0 C1 C2 C3  C4 C5 C6 C7  C8 C9 CA CB  CC CD CE CF
   Nonce =    00 00 00 03  02 01 00 A0  A1 A2 A3 A4  A5
   Total packet length = 31. [Input with 8 cleartext header octets]
              扣除 8 字節明文頭,只有 31-8=23 字節須要處理
              00 01 02 03  04 05 06 07  08 09 0A 0B  0C 0D 0E 0F
              10 11 12 13  14 15 16 17  18 19 1A 1B  1C 1D 1E

   明文分組
   M_1 -- 08 09 0A 0B 0C 0D 0E 0F 10 11 12 13 14 15 16 17
   M_2 -- 18 19 1A 1B 1C 1D 1E

   如下計算數據認證字段
   CBC IV in: 59 00 00 00  03 02 01 00  A0 A1 A2 A3  A4 A5 00 17 -- 實際就是 B_0
              |  |                                       |     |
              |  |<--------------- Nonce --------------->|     |
              
|                                            23 字節
              Flags = 0 1 0 1 1 0 0 1 (binary)
                      | | |---| |---|
                      | |   |     |
                      | |   |   L'=1 <--> L=2
                      | |  M'=3 <--> M=8
                      | Adata=1 表示有認證字段
                  Reserved (always zero)

   CBC IV out:EB 9D 55 47  73 09 55 AB  23 1E 0A 2D  FE 4B 90 D6
驗證 X_1 := E( K, B_0 )
C:\>perl -e "binmode STDOUT; print pack('H*','5900000003020100A0A1A2A3A4A50017')" > B_0.txt
C:\>openssl enc -aes-128-ecb -K C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF -iv 0 -nopad -in B_0.txt > X_1.txt
C:\>od -An -tx1 -v X_1.txt

eb 9d 55 47 73 09 55 ab 23 1e 0a 2d fe 4b 90 d6

   After xor: EB 95 55 46  71 0A 51 AE  25 19 0A 2D  FE 4B 90 D6   [hdr]
驗證 X_1 XOR B_1 -- xor.pl 源碼見後面
C:\>perl xor.pl 00080001020304050607000000000000 EB9D5547730955AB231E0A2DFE4B90D6
          00080001020304050607000000000000 B_1 附加認證數據(8 字節)
          EB9D5547730955AB231E0A2DFE4B90D6 X_1
    --------------------------------------
    XOR = EB955546710A51AE25190A2DFE4B90D6

   After AES: CD B6 41 1E  3C DC 9B 4F  5D 92 58 B6  9E E7 F0 91
驗證 X_2 := E( K, X_1 XOR B_1 )
C:\>perl -e "binmode STDOUT; print pack('H*','EB955546710A51AE25190A2DFE4B90D6')" > X_1_XOR_B_1.txt
C:\>openssl enc -aes-128-ecb -K C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF -iv 0 -nopad -in X_1_XOR_B_1.txt > X_2.txt
C:\>od -An -tx1 -v X_2.txt
cd b6 41 1e 3c dc 9b 4f 5d 92 58 b6 9e e7 f0 91

   After xor: C5 BF 4B 15  30 D1 95 40  4D 83 4A A5  8A F2 E6 86   [msg]
驗證 X_2 XOR B_2
C:\>perl xor.pl 08090A0B0C0D0E0F1011121314151617 CDB6411E3CDC9B4F5D9258B69EE7F091
          08090A0B0C0D0E0F1011121314151617 B_2 -- 從 B_2 開始起爲明文部分
          CDB6411E3CDC9B4F5D9258B69EE7F091 X_2
    --------------------------------------
    XOR = C5BF4B1530D195404D834AA58AF2E686

   After AES: 9C 38 40 5E  A0 3C 1B C9  04 B5 8B 40  C7 6C A2 EB
驗證 X_3 := E( K, X_2 XOR B_2 )
C:\>perl -e "binmode STDOUT; print pack('H*','C5BF4B1530D195404D834AA58AF2E686')" > X_2_XOR_B_2.txt
C:\>openssl enc -aes-128-ecb -K C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF -iv 0 -nopad -in X_2_XOR_B_2.txt > X_3.txt
C:\>od -An -tx1 -v X_3.txt
9c 38 40 5e a0 3c 1b c9 04 b5 8b 40 c7 6c a2 eb

   After xor: 84 21 5A 45  BC 21 05 C9  04 B5 8B 40  C7 6C A2 EB   [msg]
驗證 X_3 XOR B_3
C:\>perl xor.pl 18191A1B1C1D1E000000000000000000 9C38405EA03C1BC904B58B40C76CA2EB
          18191A1B1C1D1E000000000000000000 B_3 -- B_3 做爲明文最後一個分組,以 0 字節補齊
          9C38405EA03C1BC904B58B40C76CA2EB X_3
    --------------------------------------
    XOR = 84215A45BC2105C904B58B40C76CA2EB

   After AES: 2D C6 97 E4  11 CA 83 A8  60 C2 C4 06  CC AA 54 2F
驗證 X_4 := E( K, X_3 XOR B_3 )
C:\>perl -e "binmode STDOUT; print pack('H*','84215A45BC2105C904B58B40C76CA2EB')" > X_3_XOR_B_3.txt
C:\>openssl enc -aes-128-ecb -K C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF -iv 0 -nopad -in X_3_XOR_B_3.txt > X_4.txt
C:\>od -An -tx1 -v X_4.txt
2d c6 97 e4 11 ca 83 a8 60 c2 c4 06 cc aa 54 2f

   CBC-MAC  : 2D C6 97 E4  11 CA 83 A8 -- 取前 8 字節

   如下計算密鑰流
   S_i := E( K, A_i )   for i=0, 1, 2, ...
   A_i 是 L、Nonce、i 的函數,格式以下
       01 00 00 00  03 02 01 00  A0 A1 A2 A3  A4 A5 00 00
       |  |                                       |     |
       |  |<--------------- Nonce --------------->|     |
       |                                            Counter(0000、000一、0002...)
       Flags = 0 0 0 0 0 0 0 1 (binary)
               | | |---| |---|
               | |   |     |
               | |   |   L'=1 <--> L=2
               | |  Zero
               | 至關於 Adata=0
           Reserved (always zero)

   CTR Start: 01 00 00 00  03 02 01 00  A0 A1 A2 A3  A4 A5 00 01 -- A_1
   CTR[0001]: 50 85 9D 91  6D CB 6D DD  E0 77 C2 D1  D4 EC 9F 97 -- S_1
   CTR[0002]: 75 46 71 7A  C6 DE 9A FF  64 0C 9C 06  DE 6D 0D 8F -- S_2
   CTR[MAC ]: 3A 2E 46 C8  EC 33 A5 48                           -- S_0 取前 M 字節
   C:\>od -An -tx1 -v A_.txt
    01 00 00 00 03 02 01 00 a0 a1 a2 a3 a4 a5 00 00 -- A_0
    01 00 00 00 03 02 01 00 a0 a1 a2 a3 a4 a5 00 01 -- A_1
    01 00 00 00 03 02 01 00 a0 a1 a2 a3 a4 a5 00 02 -- A_2
   C:\>openssl enc -aes-128-ecb -K C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF -iv 0 -nopad -in A_.txt > key.txt
   C:\>od -An -tx1 -v key.txt
    3a 2e 46 c8 ec 33 a5 48 56 20 54 2c 02 2c c0 7d -- S_0
    50 85 9d 91 6d cb 6d dd e0 77 c2 d1 d4 ec 9f 97 -- S_1
    75 46 71 7a c6 de 9a ff 64 0c 9c 06 de 6d 0d 8f -- S_2

   Total packet length = 39. [Authenticated and Encrypted Output]
              00 01 02 03  04 05 06 07  58 8C 97 9A  61 C6 63 D2
              F0 66 D0 C2  C0 F9 89 80  6D 5F 6B 61  DA C3 84 17
              E8 D1 2C FD  F9 26 E0
注意
m                                             T
----------------------------------------------================
08090A0B0C0D0E0F101112131415161718191A1B1C1D1E2DC697E411CA83A8

S_1                             S_2           S_0                   
--------------------------------==============----------------

50859d916dcb6ddde077c2d1d4ec9f977546717ac6de9a3a2e46c8ec33a548

C:\>perl xor.pl 08090A0B0C0D0E0F101112131415161718191A1B1C1D1E2DC697E411CA83A8 50859d916dcb6ddde077c2d1d4ec9f977546717ac6de9a3a2e46c8ec33a548
          08090A0B0C0D0E0F101112131415161718191A1B1C1D1E2DC697E411CA83A8
          50859d916dcb6ddde077c2d1d4ec9f977546717ac6de9a3a2e46c8ec33a548
    --------------------------------------------------------------------
    XOR = 588C979A61C663D2F066D0C2C0F989806D5F6B61DAC38417E8D12CFDF926E0 正確

在 CCMP 中,對稱密鑰 K 同時對明文數據進行加密和認證,C(Confidentiality) 和 I(Integrality) 都獲得了保證
而 S(Signature) 和 A(Authentication) 是否達標,則取決於對稱密鑰 K 的安全性
從 IEEE 802.11i 中咱們知道,K 是由著名的 EAPOL-Key 四次握手衍生獲得,其安全性又取決於 PMK
PMK 又來自哪裏?

IEEE 802.11i 標準中有兩種工做模式:PSK 和 802.1X。
在 PSK 模式中,AP 和全部 STA 預先共享同一個密鑰,該共享密鑰通過簡單的變換獲得 PMK(後面將給出公式)
原則上 AP 沒法區別不一樣的 STA -- 排除其餘方式好比 MAC 地址過濾 -- 因此作不到 A(Authentication)
由於 AP 只知道有一個掌握了預共享密鑰的傢伙連上我了
至於這個傢伙是誰?他的預共享密鑰是否是偷來的?AP 一律不知
PSK 模式下 STA 反過來也沒法認證 AP,這有點相似 GSM 網絡中的僞基站

在 802.1X 模式中,安全性獲得了加強,認證協議爲 EAP,包含的認證子協議有 EAP-TLS/EAP-TTLS/EAP-PEAP 等
上述三種子協議都採用 TLS 隧道加密,自然支持 STA 對 AP 的認證
若是是 EAP-TLS 協議,還須要部署 STA 證書,於是能夠作到相互認證,在這種狀況下 SCIA,安全特性一個也很多

最後附上 xor.pl 源代碼

 1 if ( $#ARGV <= 0 )
 2 {
 3   print <<QQQ;
 4     用法:perl $0 arg1[十六進制] arg2[十六進制] ...
 5     舉例:perl $0 01234567 23456789 34567890
 6     規定:入參個數必須 >= 2,且全部入參長度必須相同(由於是位操做)
 7 QQQ
 8   exit 0;
 9 }
10 
11 $debug = 1;
12 
13 $first_arg = $ARGV[0];
14 $first_arg_len = length $first_arg;
15 die "$first_arg is NOT hex number\n" if ( ! is_hex($first_arg) );
16 die $first_arg, "'s length is NOT even number\n" if ( $first_arg_len % 2 );
17 
18 # 檢查其他入參是否爲十六進制和長度相等
19 foreach (@ARGV){
20   $cur = $_;
21   die "$cur is NOT hex number\n" if ( ! is_hex($cur) );
22   $curlen = length($cur);
23   die $cur, "'s length is NOT equal to first arg: [$first_arg]'s\n" if ( $curlen != $first_arg_len );
24 }
25 
26 print "       $_\n" foreach @ARGV;
27 print " ------", "-" x $first_arg_len, "\n XOR = ";
28 
29 # 從前日後,逐一抽取全部入參的每一個字節,進行 XOR
30 $xor_len = $first_arg_len / 2;
31 foreach $cur_index (1 .. $xor_len){
32   my @bytearry = map {substr($_,2*($cur_index-1),2)} @ARGV;
33   xor_args(@bytearry);
34 }
35 
36 sub xor_args {
37   my $result = pack('H2', "00");
38   foreach (@_){
39     my $cur_byte = pack('H2', $_);
40     $result = $result ^ $cur_byte;
41   }
42   print uc unpack('H2', $result);
43 }
44 
45 sub is_hex {
46   return 0 if ($_[0] =~ /[^A-Fa-f0-9]/);
47   1;
48 }
View Code
相關文章
相關標籤/搜索