3

What is the point of the “AES Key Wrap” algorithm prescribed for use with CMS-like contexts in IETF RFC 3394?

Just look at the algorithm (tacked on to the end of this post), informally, it smells a lot like a "home-brew" cryptosystem. And it's only used in a few, limited contexts.

Checking the document for any design rationale, I saw at the bottom this note:

Most of the text in this document is taken from AES-WRAP. The authors of that document are responsible for the development of the AES key wrap algorithm.

I already checked the upstream document, too, for rationale. The closest thing I could find is the following excerpt; its authors didn't cite anything except the raw definitions of "the AES codebook".

It is sufficient to approximate an ideal pseudorandom permutation to the degree that exploitation of undesirable phenomena is as unlikely as guessing the AES engine key. This key wrap algorithm needs to provide ample security to protect keys in the context of a prudently designed key management architecture.

Are there any reasons (other than legacy system compatibility) to use "AES-WRAP" as a key-encryption algorithm, rather than a general-purpose mode like GCM?


def aes_wrap(kek, key_towrap, iv=b'\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6'):
    "https://datatracker.ietf.org/doc/html/rfc3394.html#section-2.2.1"
    if len(key_towrap) % 8 != 0:
        raise NotImplementedError("IETF RFC 5649")
    n = len(key_towrap)//8
    A = iv
    R = bytearray(key_towrap)
    c = AES.new(kek, AES.MODE_ECB)
    ctr = 0
    for j in range(6):
        for i in range(n):
            ctr += 1
            B = c.encrypt(A + R[i*8:i*8+8])
            A = bxor(B[:8], ctr.to_bytes(8, 'big'))
            R[i*8:i*8+8] = B[8:]
    return A + R

def aes_unwrap(kek, wrapped_key, iv=b'\xa6\xa6\xa6\xa6\xa6\xa6\xa6\xa6'):
    "https://datatracker.ietf.org/doc/html/rfc3394.html#section-2.2.2"
    n = len(wrapped_key)//8 - 1
    if len(wrapped_key) % 8 != 0:
        raise NotImplementedError("IETF RFC 5649")
    R = bytearray(wrapped_key[8:])
    A = bytes(wrapped_key[:8])
    c = AES.new(kek, AES.MODE_ECB)
    ctr = 6*n
    for j in reversed(range(6)):
        for i in reversed(range(n)):
            B = c.decrypt(bxor(A, ctr.to_bytes(8, 'big')) + R[i*8:i*8+8])
            A = B[:8]
            R[i*8:i*8+8] = B[8:]
            ctr -= 1
    if A != iv:
        raise ValueError("integrity check failed")
    return bytes(R)


from operator import xor as _xor
from itertools import starmap as _starmap
def bxor(a, b):
    return a.__class__(_starmap(_xor, zip(a, b, strict=True)))
2
  • 1
    Please note that, despite the nominal similarity of the verbiage of the titles, this is obviously not a duplicate of #80966. That question is asking the rationale behind the very concept of KEKs, as an encryption architecture layer, especially in the context of JSON Web Tokens. I am asking, in the context of KEKs, the rationale behind the weird-ass one-off algorithm described in IETF RFC 3394. The questions are barely even tangentially related. May 11 at 19:19
  • One problem with GCM is that it depends on the quality of a random number generator. For key wrapping you'd try and use a SIV mode so that the scheme also depends on the input bits. Note the Q/A on cryptography with regards to AESKW & AES-SIV. I've offered a bounty to see if a more detailed answer can be given. Aug 4 at 13:00

1 Answer 1

4

NIST SP-800-38F has a couple statements that try to explain why:

  • The Overview in section 3.1 has this (emphasis mine):

KW, KWP, and TKW were designed to protect the confidentiality and the authenticity/integrity of cryptographic keys. Each provides an option for protecting keys in a manner that is distinct from the methods that protect general data. Segregating keys from general data can provide an extra layer of protection.

But the entire argument is immediately watered down by the following two paragraphs:

Nevertheless, there is no requirement to protect cryptographic keys with a distinct cryptographic method. Previously approved authenticated-encryption modes—as well as combinations of an approved encryption mode with an approved authentication method—are approved for the protection of cryptographic keys, in addition to general data.

Similarly, KW, KWP, and TKW are each approved for the protection of general data, as well as cryptographic keys.

In the last paragraph of the section they do discuss some of its strengths:

KW, KWP, and TKW are each robust in the sense that each bit of output can be expected to depend in a nontrivial fashion on each bit of input, even when the length of the input data is greater than one block. This property is achieved at the cost of a considerably lower throughput rate, compared to other authenticated-encryption modes, but the tradeoff may be appropriate for some key management applications. For example, a robust method may be desired when the length of the keys to be protected is greater than the block size of the underlying block cipher, or when the value of the protected data is very high.

One thing the key wrapping algorithm does is specifies an authenticated mode of operation, which means the algorithm must return FAIL if the data is corrupt. That way you can't proceed with an invalid key.

This is described as a comparative advantage over other encryption methods in appendix B.2, Comparison of Functionality with Other Authentication Methods:

By contrast, for KW, KWP, and TKW, there are no separate authentication tags: instead, the information that is necessary to verify the authenticity of the data is embedded in all of the ciphertext bits. Consequently, for these three algorithms, the authenticity of the data cannot be verified without invoking the authenticated-decryption function.

That means that by using the AES-WRAP method, you cannot skip the authentication step. Which is worth a little something.

1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .