-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Description
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:
- 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.