RFC 4493

The AES-CMAC Algorithm

πŸ“… published June 2006, from ietf

RFC 4493: The AES-CMAC Algorithm πŸ¦‹

Okay bestie, this is the one. RFC 4493 is an Informational document from June 2006, and it was written by JH. Song (Samsung Electronics), R. Poovendran (University of Washington), J. Lee (Samsung Electronics), and T. Iwata (Nagoya University) πŸ’…. It's not a standard. It just gives the Internet community info about an algorithm that's already cooking. The header doesn't list any obsoletes or updates, so nothing else is being replaced here 🌸.


Status of This Memo ✨

This memo gives information to the Internet community. It doesn't specify an Internet standard of any kind. Distribution of this memo is unlimited.

Copyright (C) The Internet Society (2006).

Abstract 🌈

Okay so NIST recently specified the Cipher-based Message Authentication Code (CMAC), and it's basically the same thing as the One-Key CBC MAC1 (OMAC1) that Iwata and Kurosawa submitted. This memo lays out an authentication algorithm based on CMAC using the 128-bit Advanced Encryption Standard (AES). It's called AES-CMAC, and the whole point is to make it easy for the Internet community to grab and use 🧚.

Table of Contents πŸŽ€

1. Introduction ....................................................2
2. Specification of AES-CMAC .......................................3
   2.1. Basic Definitions ..........................................3
   2.2. Overview ...................................................4
   2.3. Subkey Generation Algorithm ................................5
   2.4. MAC Generation Algorithm ...................................7
   2.5. MAC Verification Algorithm .................................9
3. Security Considerations ........................................10
4. Test Vectors ...................................................11
5. Acknowledgement ................................................12
6. References .....................................................12
   6.1. Normative References ......................................12
   6.2. Informative References ....................................12
Appendix A. Test Code .............................................14

1. Introduction πŸ“

NIST recently specified the Cipher-based Message Authentication Code (CMAC). CMAC [NIST-CMAC] is a keyed hash function built on a symmetric key block cipher, like the Advanced Encryption Standard [NIST-AES]. It's equivalent to the One-Key CBC MAC1 (OMAC1) that Iwata and Kurosawa submitted [OMAC1a, OMAC1b]. OMAC1 is an upgrade of the eXtended Cipher Block Chaining mode (XCBC) that Black and Rogaway submitted [XCBCa, XCBCb], and XCBC is itself an upgrade of the basic Cipher Block Chaining-Message Authentication Code (CBC-MAC). The lore is that XCBC fixed the security problems of CBC-MAC, and OMAC1 shrank the key size of XCBC. Iconic glow-up arc πŸ”₯.

AES-CMAC gives you way stronger data integrity than a checksum or an error-detecting code. A checksum or error-detecting code only catches accidental changes to the data. CMAC is designed to catch intentional, unauthorized changes too, as well as the accidental ones πŸ‘€.

AES-CMAC is aiming for a similar security goal to HMAC [RFC-HMAC]. The difference is the foundation: AES-CMAC is built on the symmetric key block cipher AES, while HMAC is built on a hash function like SHA-1. So AES-CMAC is a good fit for information systems where AES is easier to get than a hash function πŸ’–.

This memo specifies the authentication algorithm based on CMAC with AES-128. The new algorithm is named AES-CMAC.

2. Specification of AES-CMAC πŸ¦‹

2.1. Basic Definitions πŸ’…

Here's the table of basic definitions you need to understand how AES-CMAC is specified:

x || y          Concatenation.
                x || y is the string x concatenated with the string
                y.
                0000 || 1111 is 00001111.

x XOR y         Exclusive-OR operation.
                For two equal length strings, x and y,
                x XOR y is their bit-wise exclusive-OR.

ceil(x)         Ceiling function.
                The smallest integer no smaller than x.
                ceil(3.5) is 4.  ceil(5) is 5.

x << 1          Left-shift of the string x by 1 bit.
                The most significant bit disappears, and a zero
                comes into the least significant bit.
                10010001 << 1 is 00100010.

0^n             The string that consists of n zero-bits.
                0^3 means 000 in binary format.
                10^4 means 10000 in binary format.
                10^i means 1 followed by i-times repeated
                zeros.

MSB(x)          The most-significant bit of the string x.
                MSB(10010000) means 1.

padding(x)      10^i padded output of input x.
                It is described in detail in section 2.4.

Key             128-bit (16-octet) long key for AES-128.
                Denoted by K.

First subkey    128-bit (16-octet) long first subkey,
                derived through the subkey
                generation algorithm from the key K.
                Denoted by K1.

Second subkey   128-bit (16-octet) long second subkey,
                derived through the subkey
                generation algorithm from the key K.
                Denoted by K2.

Message         A message to be authenticated.
                Denoted by M.
                The message can be null, which means that the length
                of M is 0.

Message length  The length of the message M in octets.
                Denoted by len.
                The minimum value of the length can be 0.  The
                maximum value of the length is not specified in
                this document.

AES-128(K,M)    AES-128(K,M) is the 128-bit ciphertext of AES-128
                for a 128-bit key, K, and a 128-bit message, M.

MAC             A 128-bit string that is the output of AES-CMAC.
                Denoted by T.
                Validating the MAC provides assurance of the
                integrity and authenticity of the message from
                the source.

MAC length      By default, the length of the output of AES-CMAC is
                128 bits.  It is possible to truncate the MAC.
                The result of the truncation should be taken in most
                significant bits first order.  The MAC length must be
                specified before the communication starts, and
                it must not be changed during the lifetime of the
                key.

2.2. Overview 🌸

AES-CMAC uses the Advanced Encryption Standard [NIST-AES] as its building block. To generate a MAC, AES-CMAC takes a secret key, a message of variable length, and the length of that message in octets as inputs, and it returns a fixed-bit string called a MAC ✨.

The core of AES-CMAC is the basic CBC-MAC. For a message M that needs to be authenticated, the CBC-MAC gets applied to M. CMAC has two cases of operation, and Figure 2.1 shows what the CBC-MAC does in each one. If the input message is a positive multiple of the block size (that's 128 bits), the last block shall be exclusive-OR'ed with K1 before processing. Otherwise, the last block shall be padded with 10^i (the notation is explained in section 2.1) and exclusive-OR'ed with K2. The result of that step becomes the input to the last encryption. The output of AES-CMAC gives data integrity for the whole input message, which is the whole point 🫢.

 +-----+     +-----+     +-----+     +-----+     +-----+     +---+----+
 | M_1 |     | M_2 |     | M_n |     | M_1 |     | M_2 |     |M_n|10^i|
 +-----+     +-----+     +-----+     +-----+     +-----+     +---+----+
    |           |           |   +--+    |           |           |   +--+
    |     +--->(+)    +--->(+)<-|K1|    |     +--->(+)    +--->(+)<-|K2|
    |     |     |     |     |   +--+    |     |     |     |     |   +--+
 +-----+  |  +-----+  |  +-----+     +-----+  |  +-----+  |  +-----+
 |AES_K|  |  |AES_K|  |  |AES_K|     |AES_K|  |  |AES_K|  |  |AES_K|
 +-----+  |  +-----+  |  +-----+     +-----+  |  +-----+  |  +-----+
    |     |     |     |     |           |     |     |     |     |
    +-----+     +-----+     |           +-----+     +-----+     |
                            |                                   |
                         +-----+                              +-----+
                         |  T  |                              |  T  |
                         +-----+                              +-----+

             (a) positive multiple block length         (b) otherwise

          Figure 2.1.  Illustration of the two cases of AES-CMAC

AES_K is AES-128 with key K. The message M gets split into blocks M_1,...,M_n, where M_i is the i-th message block. Each M_i is 128 bits for i = 1,...,n-1, and the last block, M_n, is less than or equal to 128 bits. K1 is the subkey for case (a), and K2 is the subkey for case (b). Both K1 and K2 come from the subkey generation algorithm in section 2.3 πŸŽ€.

2.3. Subkey Generation Algorithm ✨

okay so the subkey generation algorithm, Generate_Subkey(), takes a secret key K, which is literally just the AES-128 key πŸ”‘. It spits out two subkeys, K1 and K2, and we write that as (K1,K2) := Generate_Subkey(K) πŸ’–

Both subkeys get used in MAC generation AND MAC verification 🫢 K1 is for when the last block is exactly the block length, and K2 is for when the last block is shorter than the block length.

Here's the algorithm, Figure 2.2:

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                    Algorithm Generate_Subkey                      +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                                                                   +
+   Input    : K (128-bit key)                                      +
+   Output   : K1 (128-bit first subkey)                            +
+              K2 (128-bit second subkey)                           +
+-------------------------------------------------------------------+
+                                                                   +
+   Constants: const_Zero is 0x00000000000000000000000000000000     +
+              const_Rb   is 0x00000000000000000000000000000087     +
+   Variables: L          for output of AES-128 applied to 0^128    +
+                                                                   +
+   Step 1.  L := AES-128(K, const_Zero);                           +
+   Step 2.  if MSB(L) is equal to 0                                +
+            then    K1 := L << 1;                                  +
+            else    K1 := (L << 1) XOR const_Rb;                   +
+   Step 3.  if MSB(K1) is equal to 0                               +
+            then    K2 := K1 << 1;                                 +
+            else    K2 := (K1 << 1) XOR const_Rb;                  +
+   Step 4.  return K1, K2;                                         +
+                                                                   +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                Figure 2.2.  Algorithm Generate_Subkey

Breaking it down, bestie 🧚

  • Step 1: AES-128 with key K gets run on an all-zero input block 🌸
  • Step 2: K1 depends on the MSB of L. If that MSB is 0, K1 is just L left-shifted by 1 bit. Otherwise, K1 is the XOR of const_Rb and L left-shifted by 1 bit πŸ’…
  • Step 3: K2 follows the same vibe but with K1. If the MSB of K1 is 0, K2 is K1 left-shifted by 1 bit. Otherwise, K2 is the XOR of const_Rb and K1 left-shifted by 1 bit πŸ¦‹
  • Step 4: return (K1,K2) := Generate_Subkey(K) πŸŽ€

The math behind steps 2 and 3, including const_Rb, is explained in [OMAC1a]. ✨


2.4. MAC Generation Algorithm 🌈

the MAC generation algorithm, AES-CMAC(), takes three inputs: a secret key, a message, and the message length in octets. The secret key is K, which is again just the AES-128 key πŸ”‘ The message is M and its length in octets is len. The message M is written as a sequence of blocks M_i, where M_i is the i-th message block. So if M has n blocks, it looks like this:

  • M = M_1 || M_2 || ... || M_{n-1} || M_n

Every block M_i is 128 bits for i = 1,...,n-1, and the last block M_n is less than or equal to 128 bits πŸ’–

The output is a 128-bit string called a MAC, which is used to validate the input message. We write the MAC as T, so T := AES-CMAC(K,M,len). Validating the MAC gives you assurance of the integrity and authenticity of the message from the source 🫢

You can truncate the MAC, and this is the lowkey important part πŸ‘€ According to [NIST-CMAC], at least a 64-bit MAC should be used as protection against guessing attacks. The truncation should be taken in most significant bits first order πŸ”₯

The AES-128 block length is 128 bits (16 octets). If the message length is not a positive multiple of the block length, there's a special treatment: M gets padded with the bit-string 10^i so the last block is extended up to the block length πŸ“

For an input string x of r octets, where 0 <= r < 16, the padding function padding(x) works like this:

  • padding(x) = x || 10^i where i is 128-8*r-1

So padding(x) is x, plus a single '1', plus the minimum number of '0's needed to make the total length exactly 128 bits. Iconic ✨

Figure 2.3 describes the MAC generation algorithm:

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                   Algorithm AES-CMAC                              +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                                                                   +
+   Input    : K    ( 128-bit key )                                 +
+            : M    ( message to be authenticated )                 +
+            : len  ( length of the message in octets )             +
+   Output   : T    ( message authentication code )                 +
+                                                                   +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+   Constants: const_Zero is 0x00000000000000000000000000000000     +
+              const_Bsize is 16                                    +
+                                                                   +
+   Variables: K1, K2 for 128-bit subkeys                           +
+              M_i is the i-th block (i=1..ceil(len/const_Bsize))   +
+              M_last is the last block xor-ed with K1 or K2        +
+              n      for number of blocks to be processed          +
+              r      for number of octets of last block            +
+              flag   for denoting if last block is complete or not +
+                                                                   +
+   Step 1.  (K1,K2) := Generate_Subkey(K);                         +
+   Step 2.  n := ceil(len/const_Bsize);                            +
+   Step 3.  if n = 0                                               +
+            then                                                   +
+                 n := 1;                                           +
+                 flag := false;                                    +
+            else                                                   +
+                 if len mod const_Bsize is 0                       +
+                 then flag := true;                                +
+                 else flag := false;                               +
+                                                                   +
+   Step 4.  if flag is true                                        +
+            then M_last := M_n XOR K1;                             +
+            else M_last := padding(M_n) XOR K2;                    +
+   Step 5.  X := const_Zero;                                       +
+   Step 6.  for i := 1 to n-1 do                                   +
+                begin                                              +
+                  Y := X XOR M_i;                                  +
+                  X := AES-128(K,Y);                               +
+                end                                                +
+            Y := M_last XOR X;                                     +
+            T := AES-128(K,Y);                                     +
+   Step 7.  return T;                                              +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

                      Figure 2.3.  Algorithm AES-CMAC

Now the step-by-step tea β˜•

  • Step 1: K1 and K2 get derived from K through the subkey generation algorithm πŸ”‘
  • Step 2: we calculate the number of blocks, n. It's the smallest integer greater than or equal to len divided by the block length of 16 octets πŸ’…
  • Step 3: we check the input length. If it's 0 (null), the number of blocks to be processed shall be 1, and the flag shall be marked as not-complete-block (false). Otherwise, if the last block length is 128 bits, the flag is marked as complete-block (true). If not, the flag is marked as not-complete-block (false) 🫠
  • Step 4: M_last is M_n XORed with one of the subkeys. If the last block is complete (true), M_last is M_n XOR K1. Otherwise, M_last is padding(M_n) XOR K2 πŸ¦‹
  • Step 5: we initialize X 🌸
  • Step 6: the basic CBC-MAC runs over M_1,...,M_{n-1},M_last πŸ”₯
  • Step 7: the 128-bit MAC, T := AES-CMAC(K,M,len), gets returned πŸ‘‘

And if necessary, the MAC gets truncated before it's returned. ✨

2.5. MAC Verification Algorithm ✨

okay bestie, so verifying a MAC is literally just... doing the MAC generation again and seeing if it matches πŸ’… we reuse the generation algorithm from section 2.4 (no notes, it's the same vibe) πŸ¦‹

the verify function, Verify_MAC(), takes four inputs: a secret key, a message, the length of the message in octets, and the received MAC. these are called K, M, len, and T' respectively πŸŽ€

the output is either INVALID or VALID. that's it, that's the whole menu πŸ’€

Figure 2.4 is the algorithm, and it's giving very clean energy 🌸

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                      Algorithm Verify_MAC                         +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+                                                                   +
+   Input    : K    ( 128-bit Key )                                 +
+            : M    ( message to be verified )                      +
+            : len  ( length of the message in octets )             +
+            : T'   ( the received MAC to be verified )             +
+   Output   : INVALID or VALID                                     +
+                                                                   +
+-------------------------------------------------------------------+
+                                                                   +
+   Step 1.  T* := AES-CMAC(K,M,len);                               +
+   Step 2.  if T* is equal to T'                                   +
+            then                                                   +
+                 return VALID;                                     +
+            else                                                   +
+                 return INVALID;                                   +
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Figure 2.4. Algorithm Verify_MAC

so step 1 is: make T* from K, M, and len using the generation algorithm 🧚

step 2 is the glow-up moment: compare T* with T'. if they match, return VALID 🫢 if they don't, return INVALID 😭

if the output is INVALID, the message is definitely not authentic 🚫 like, it did not come from a source that ran the generation process on that message to make the purported MAC. no vibes, just facts πŸ’œ

if the output is VALID, the design of AES-CMAC gives you assurance that the message is authentic and therefore wasn't corrupted in transit 🌈 BUT, and this is important bestie, that assurance is not absolute. same as for ANY MAC algorithm πŸ™ˆ


3. Security Considerations πŸ”₯

okay this section is SERIOUS, so pay attention bestie πŸ‘‘

AES-CMAC is built on the strong cryptographic algorithm AES πŸ’ͺ however (and this is true for every crypto algorithm ever), a big part of its strength lives in the secret key K, plus the implementation being correct in every participating system πŸ”

if the secret key gets compromised or shared inappropriately, AES-CMAC guarantees neither authentication nor integrity of the message. at all. zero. nada. πŸ’€

the secret key SHALL be generated in a way that meets the pseudo randomness requirement of RFC 4086 [RFC4086], and it SHOULD be kept safe πŸ¦‹

if and only if AES-CMAC is used properly does it provide the authentication and integrity that meet the best current practice of message authentication πŸ‘‘πŸŒΈ


4. Test Vectors πŸ§ͺ

these test vectors are the same as the ones in [NIST-CMAC] πŸ’– and they're also the output of the test program in Appendix A ✨

--------------------------------------------------
Subkey Generation
K              2b7e1516 28aed2a6 abf71588 09cf4f3c
AES-128(key,0) 7df76b0c 1ab899b3 3e42f047 b91b546f
K1             fbeed618 35713366 7c85e08f 7236a8de
K2             f7ddac30 6ae266cc f90bc11e e46d513b
--------------------------------------------------

--------------------------------------------------
Example 1: len = 0
M              <empty string>
AES-CMAC       bb1d6929 e9593728 7fa37d12 9b756746
--------------------------------------------------

Example 2: len = 16
M              6bc1bee2 2e409f96 e93d7e11 7393172a
AES-CMAC       070a16b4 6b4d4144 f79bdd9d d04a287c
--------------------------------------------------

Example 3: len = 40
M              6bc1bee2 2e409f96 e93d7e11 7393172a
               ae2d8a57 1e03ac9c 9eb76fac 45af8e51
               30c81c46 a35ce411
AES-CMAC       dfa66747 de9ae630 30ca3261 1497c827
--------------------------------------------------

Example 4: len = 64
M              6bc1bee2 2e409f96 e93d7e11 7393172a
               ae2d8a57 1e03ac9c 9eb76fac 45af8e51
               30c81c46 a35ce411 e5fbc119 1a0a52ef
               f69f2445 df4f9b17 ad2b417b e66c3710
AES-CMAC       51f0bebf 7e3b9d92 fc497417 79363cfe
--------------------------------------------------

5. Acknowledgement 🫢

portions of the text here are borrowed from [NIST-CMAC] πŸ“š big thanks to the OMAC1 authors, the SP 800-38B author, and Russ Housley for his useful comments and guidance, which got folded in πŸ’– we also thank Alfred Hoenes for lots of useful comments 🌷 this memo was prepared while Tetsu Iwata was at Ibaraki University, Japan πŸ—Ύ

we acknowledge support from these grants: Collaborative Technology Alliance (CTA) from US Army Research Laboratory, DAAD19-01-2-0011; Presidential Award from Army Research Office, W911NF-05-1-0491; NSF CAREER ANI-0093187 πŸŽ€ results do not reflect any position of the funding agencies πŸ™


6. References πŸ“–

6.1. Normative References πŸ’œ

[NIST-CMAC] NIST, Special Publication 800-38B, "Recommendation for
            Block Cipher Modes of Operation: The CMAC Mode for
            Authentication", May 2005.

[NIST-AES]  NIST, FIPS 197, "Advanced Encryption Standard (AES)",
            November 2001.
            http://csrc.nist.gov/publications/fips/fips197/fips-
            197.pdf

[RFC4086]   Eastlake, D., 3rd, Schiller, J., and S. Crocker,
            "Randomness Requirements for Security", BCP 106, RFC
            4086, June 2005.

6.2. Informative References 🌈

[RFC-HMAC]  Krawczyk, H., Bellare, M., and R. Canetti, "HMAC:
            Keyed-Hashing for Message Authentication", RFC 2104,
            February 1997.

[OMAC1a]    Tetsu Iwata and Kaoru Kurosawa, "OMAC: One-Key CBC MAC",
            Fast Software Encryption, FSE 2003, LNCS 2887, pp. 129-
            153, Springer-Verlag, 2003.

[OMAC1b]    Tetsu Iwata and Kaoru Kurosawa, "OMAC: One-Key CBC MAC",
            Submission to NIST, December 2002.  Available from the
            NIST modes of operation web site at
            http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/
            omac/omac-spec.pdf

[XCBCa]     John Black and Phillip Rogaway, "A Suggestion for
            Handling Arbitrary-Length Messages with the CBC MAC",
            NIST Second Modes of Operation Workshop, August 2001.
            Available from the NIST modes of operation web site at
            http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/
            xcbc-mac/xcbc-mac-spec.pdf

[XCBCb]     John Black and Phillip Rogaway, "CBC MACs for Arbitrary-
            Length Messages: The Three-Key Constructions", Journal of
            Cryptology, Vol. 18, No. 2, pp. 111-132, Springer-Verlag,
            Spring 2005.

Appendix A. Test Code ✨

okay so this is the C source that spits out the test vectors from earlier in the memo πŸ§ͺ it's there to check that the algorithm is correct, and it's NOT meant for commercial products πŸ™…β€β™€οΈ so keep it in your lab bestie πŸ’…

/****************************************************************/
/* AES-CMAC with AES-128 bit                                    */
/* CMAC     Algorithm described in SP800-38B                    */
/* Author: Junhyuk Song (junhyuk.song@samsung.com)              */
/*         Jicheol Lee  (jicheol.lee@samsung.com)               */
/****************************************************************/

#include <stdio.h>

/* For CMAC Calculation */
unsigned char const_Rb[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87
};
unsigned char const_Zero[16] = {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

/* Basic Functions */

void xor_128(unsigned char *a, unsigned char *b, unsigned char *out)
{
    int i;
    for (i=0;i<16; i++)
    {
        out[i] = a[i] ^ b[i];
    }
}

void print_hex(char *str, unsigned char *buf, int len)
{
    int     i;

    for ( i=0; i<len; i++ ) {
        if ( (i % 16) == 0 && i != 0 ) printf(str);
        printf("%02x", buf[i]);
        if ( (i % 4) == 3 ) printf(" ");
        if ( (i % 16) == 15 ) printf("\n");
    }
    if ( (i % 16) != 0 ) printf("\n");
}
void print128(unsigned char *bytes)
{
    int         j;
    for (j=0; j<16;j++) {
        printf("%02x",bytes[j]);
        if ( (j%4) == 3 ) printf(" ");
    }
}

void print96(unsigned char *bytes)
{
    int         j;
    for (j=0; j<12;j++) {
        printf("%02x",bytes[j]);
        if ( (j%4) == 3 ) printf(" ");
    }
}

/* AES-CMAC Generation Function */

void leftshift_onebit(unsigned char *input,unsigned char *output)
{
    int         i;
    unsigned char overflow = 0;

    for ( i=15; i>=0; i-- ) {
        output[i] = input[i] << 1;
        output[i] |= overflow;
        overflow = (input[i] & 0x80)?1:0;
    }
    return;
}

void generate_subkey(unsigned char *key, unsigned char *K1, unsigned
                     char *K2)
{
    unsigned char L[16];
    unsigned char Z[16];
    unsigned char tmp[16];
    int i;

    for ( i=0; i<16; i++ ) Z[i] = 0;

    AES_128(key,Z,L);

    if ( (L[0] & 0x80) == 0 ) { /* If MSB(L) = 0, then K1 = L << 1 */
        leftshift_onebit(L,K1);
    } else {    /* Else K1 = ( L << 1 ) (+) Rb */

        leftshift_onebit(L,tmp);
        xor_128(tmp,const_Rb,K1);
    }

    if ( (K1[0] & 0x80) == 0 ) {
        leftshift_onebit(K1,K2);
    } else {
        leftshift_onebit(K1,tmp);
        xor_128(tmp,const_Rb,K2);
    }
    return;
}

void padding ( unsigned char *lastb, unsigned char *pad, int length )
{
    int         j;

    /* original last block */
    for ( j=0; j<16; j++ ) {
        if ( j < length ) {
            pad[j] = lastb[j];
        } else if ( j == length ) {
            pad[j] = 0x80;
        } else {
            pad[j] = 0x00;
        }
    }
}

void AES_CMAC ( unsigned char *key, unsigned char *input, int length,
                unsigned char *mac )
{
    unsigned char       X[16],Y[16], M_last[16], padded[16];
    unsigned char       K1[16], K2[16];
    int         n, i, flag;
    generate_subkey(key,K1,K2);

    n = (length+15) / 16;       /* n is number of rounds */

    if ( n == 0 ) {
        n = 1;
        flag = 0;
    } else {
        if ( (length%16) == 0 ) { /* last block is a complete block */
            flag = 1;
        } else { /* last block is not complete block */
            flag = 0;
        }

    }

    if ( flag ) { /* last block is complete block */
        xor_128(&input[16*(n-1)],K1,M_last);
    } else {
        padding(&input[16*(n-1)],padded,length%16);
        xor_128(padded,K2,M_last);
    }

    for ( i=0; i<16; i++ ) X[i] = 0;
    for ( i=0; i<n-1; i++ ) {
        xor_128(X,&input[16*i],Y); /* Y := Mi (+) X  */
        AES_128(key,Y,X);      /* X := AES-128(KEY, Y); */
    }

    xor_128(X,M_last,Y);
    AES_128(key,Y,X);

    for ( i=0; i<16; i++ ) {
        mac[i] = X[i];
    }
}

int main()
{
    unsigned char L[16], K1[16], K2[16], T[16], TT[12];
    unsigned char M[64] = {
        0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
        0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
        0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
        0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
        0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
        0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
        0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
        0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
    };
    unsigned char key[16] = {
        0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
        0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
    };

    printf("--------------------------------------------------\n");
    printf("K              "); print128(key); printf("\n");

    printf("\nSubkey Generation\n");
    AES_128(key,const_Zero,L);
    printf("AES_128(key,0) "); print128(L); printf("\n");
    generate_subkey(key,K1,K2);
    printf("K1             "); print128(K1); printf("\n");
    printf("K2             "); print128(K2); printf("\n");

    printf("\nExample 1: len = 0\n");
    printf("M              "); printf("<empty string>\n");

    AES_CMAC(key,M,0,T);
    printf("AES_CMAC       "); print128(T); printf("\n");

    printf("\nExample 2: len = 16\n");
    printf("M              "); print_hex("                ",M,16);
    AES_CMAC(key,M,16,T);
    printf("AES_CMAC       "); print128(T); printf("\n");
    printf("\nExample 3: len = 40\n");
    printf("M              "); print_hex("               ",M,40);
    AES_CMAC(key,M,40,T);
    printf("AES_CMAC       "); print128(T); printf("\n");

    printf("\nExample 4: len = 64\n");
    printf("M              "); print_hex("               ",M,64);
    AES_CMAC(key,M,64,T);
    printf("AES_CMAC       "); print128(T); printf("\n");

    printf("--------------------------------------------------\n");

    return 0;
}

Authors' Addresses πŸŽ€

Junhyuk Song 🌸 University of Washington Samsung Electronics Phone: (206) 853-5843 EMail: songlee@ee.washington.edu, junhyuk.song@samsung.com

Jicheol Lee 🌸 Samsung Electronics Phone: +82-31-279-3605 EMail: jicheol.lee@samsung.com

Radha Poovendran 🌸 Network Security Lab University of Washington Phone: (206) 221-6512 EMail: radha@ee.washington.edu

Tetsu Iwata 🌸 Nagoya University EMail: iwata@cse.nagoya-u.ac.jp


Copyright (C) The Internet Society (2006).

This document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights.

This document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.

Intellectual Property πŸ”₯

The IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights. Information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79.

Copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr.

The IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. Please address the information to the IETF at ietf-ipr@ietf.org.

Acknowledgement 🫢

Funding for the RFC Editor function is provided by the IETF Administrative Support Activity (IASA). πŸ’œ

πŸ“¦ where this page comes from