Skip to content

Add RFC5649 KeyWrap #108332

@blowdart

Description

@blowdart

Background

There are two different RFCs producing algorithms known as "AES Key Wrap", RFC 3394 ("Advanced Encryption Standard (AES) Key Wrap Algorithm"), and RFC 5649 ("Advanced Encryption Standard (AES) Key Wrap with Padding Algorithm").

These two RFCs produce mutually unintelligible values, and have different domains of input:

  • 3394 requires an input to be a multiple of 64 bits (8 bytes), greater than zero.
  • 5649 requires only that the input be non-empty.

OpenSSL offers both of these algorithms, calling them

  • 3394: CRYPTO_128_wrap / CRYPTO_128_unwrap
  • 5649: CRYPTO_128_wrap_pad / CRYPTO_128_wrap_unpad

Note that OpenSSL does not include "AES" in the name at all, just requiring that it be a padding algorithm based on 128-bit-block encryption (of which AES happens to be the only popular algorithm).

API Proposal

namespace System.Security.Cryptography
{
    public partial class Aes
    {
        // Alternate names:
        //   ExtendedKeyUnwrap
        //   PaddedKeyUnwrap
        //   UnwrapKeyPadded
        //   UnwrapPaddedKey
        //   (etc)
        public byte[] DecryptKeyWrapPadded(byte[] ciphertext);
        public byte[] DecryptKeyWrapPadded(System.ReadOnlySpan<byte> ciphertext);
        public int DecryptKeyWrapPadded(System.ReadOnlySpan<byte> ciphertext, System.Span<byte> destination);
        protected virtual int DecryptKeyWrapPaddedCore(System.ReadOnlySpan<byte> source, System.Span<byte> destination);
        public bool TryDecryptKeyWrapPadded(System.ReadOnlySpan<byte> ciphertext, System.Span<byte> destination, out int bytesWritten);

        public static int GetKeyWrapPaddedLength(int plaintextLengthInBytes);

        public byte[] EncryptKeyWrapPadded(byte[] plaintext);
        public byte[] EncryptKeyWrapPadded(System.ReadOnlySpan<byte> plaintext);
        public void EncryptKeyWrapPadded(System.ReadOnlySpan<byte> plaintext, System.Span<byte> destination);
        protected virtual void EncryptKeyWrapPaddedCore(System.ReadOnlySpan<byte> source, System.Span<byte> destination);
    }
}

Naming

RFC 5649's title uses the name "Key Wrap with Padding", which suggests KeyWrapPadded/KeyUnwrapPadded. But, in the body of the RFC, it uses a different name:

  1. Specification of the AES Key Wrap with Padding Algorithm
    ...
    4.1. Extended Key Wrapping Process
    ...
    4.2. Extended Key Unwrapping Process

These names lead to a more flowing "ExtendedKeyWrap" and "ExtendedKeyUnwrap", which are the names proposed.

Other alternatives are KeyWrapRfc5649/KeyUnwrapRfc5649, or similar "include the RFC number".

Usage

byte[] wrapped = wrappingKey.EncryptKeyWrapPadded(toWrap);
Assert.Equal(wrapped.Length, Aes.GetKeyWrapPaddedLength(toWrap));
byte[] unwrapped = wrappingKey.DecryptKeyWrapPadded(wrapped);
Assert.SequenceEqual(wrapped, unwrapped);

Downlevel Concerns

If there's a need to expose this to NET8 (or even NetFramework), it can be done via a polyfill extension method in Microsoft.Bcl.Cryptography. The extension method would forward to the instance method (NET10+), or a non-extensible copy of the algorithm within M.B.C.

Such "backport" is not planned at this time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions