This commit is contained in:
Jeremy Barton 2025-07-30 22:32:32 +08:00 committed by GitHub
commit 91e623adef
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 213 additions and 1 deletions

View File

@ -258,6 +258,9 @@ internal static partial class Interop
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes128Ccm")]
internal static partial IntPtr EvpAes128Ccm();
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes128WrapPad")]
internal static partial IntPtr EvpAes128WrapPad();
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes192Ecb")]
internal static partial IntPtr EvpAes192Ecb();
@ -276,6 +279,9 @@ internal static partial class Interop
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes192Ccm")]
internal static partial IntPtr EvpAes192Ccm();
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes192WrapPad")]
internal static partial IntPtr EvpAes192WrapPad();
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes256Ecb")]
internal static partial IntPtr EvpAes256Ecb();
@ -294,6 +300,9 @@ internal static partial class Interop
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes256Ccm")]
internal static partial IntPtr EvpAes256Ccm();
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpAes256WrapPad")]
internal static partial IntPtr EvpAes256WrapPad();
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpDesCbc")]
internal static partial IntPtr EvpDesCbc();

View File

@ -1237,7 +1237,7 @@
Link="Common\System\Security\Cryptography\SlhDsaImplementation.NotSupported.cs" />
<Compile Include="$(CommonPath)System\Security\Cryptography\SP800108HmacCounterKdfImplementationManaged.cs"
Link="Common\System\Security\Cryptography\SP800108HmacCounterKdfImplementationManaged.cs" />
<Compile Include="System\Security\Cryptography\AesImplementation.OpenSsl.cs" />
<Compile Include="System\Security\Cryptography\AesImplementation.Android.cs" />
<Compile Include="System\Security\Cryptography\AesCcm.Android.cs" />
<Compile Include="System\Security\Cryptography\AesGcm.Android.cs" />
<Compile Include="System\Security\Cryptography\AsnFormatter.Managed.cs" />

View File

@ -0,0 +1,63 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Security.Cryptography
{
internal sealed partial class AesImplementation
{
private static UniversalCryptoTransform CreateTransformCore(
CipherMode cipherMode,
PaddingMode paddingMode,
ReadOnlySpan<byte> key,
byte[]? iv,
int blockSize,
int paddingSize,
int feedback,
bool encrypting)
{
// The algorithm pointer is a static pointer, so not having any cleanup code is correct.
IntPtr algorithm = GetAlgorithm(key.Length * 8, feedback * 8, cipherMode);
BasicSymmetricCipher cipher = new OpenSslCipher(algorithm, cipherMode, blockSize, paddingSize, key, iv, encrypting);
return UniversalCryptoTransform.Create(paddingMode, cipher, encrypting);
}
private static OpenSslCipherLite CreateLiteCipher(
CipherMode cipherMode,
ReadOnlySpan<byte> key,
ReadOnlySpan<byte> iv,
int blockSize,
int paddingSize,
int feedback,
bool encrypting)
{
IntPtr algorithm = GetAlgorithm(key.Length * 8, feedback * 8, cipherMode);
return new OpenSslCipherLite(algorithm, blockSize, paddingSize, key, iv, encrypting);
}
private static IntPtr GetAlgorithm(int keySize, int feedback, CipherMode cipherMode) =>
(keySize, cipherMode) switch
{
// Neither OpenSSL nor Cng Aes support CTS mode.
(128, CipherMode.CBC) => Interop.Crypto.EvpAes128Cbc(),
(128, CipherMode.ECB) => Interop.Crypto.EvpAes128Ecb(),
(128, CipherMode.CFB) when feedback == 8 => Interop.Crypto.EvpAes128Cfb8(),
(128, CipherMode.CFB) when feedback == 128 => Interop.Crypto.EvpAes128Cfb128(),
(192, CipherMode.CBC) => Interop.Crypto.EvpAes192Cbc(),
(192, CipherMode.ECB) => Interop.Crypto.EvpAes192Ecb(),
(192, CipherMode.CFB) when feedback == 8 => Interop.Crypto.EvpAes192Cfb8(),
(192, CipherMode.CFB) when feedback == 128 => Interop.Crypto.EvpAes192Cfb128(),
(256, CipherMode.CBC) => Interop.Crypto.EvpAes256Cbc(),
(256, CipherMode.ECB) => Interop.Crypto.EvpAes256Ecb(),
(256, CipherMode.CFB) when feedback == 8 => Interop.Crypto.EvpAes256Cfb8(),
(256, CipherMode.CFB) when feedback == 128 => Interop.Crypto.EvpAes256Cfb128(),
_ => throw (keySize == 128 || keySize == 192 || keySize == 256 ? (Exception)
new NotSupportedException() :
new CryptographicException(SR.Cryptography_InvalidKeySize)),
};
}
}

View File

@ -1,6 +1,10 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
namespace System.Security.Cryptography
{
internal sealed partial class AesImplementation
@ -35,6 +39,75 @@ namespace System.Security.Cryptography
return new OpenSslCipherLite(algorithm, blockSize, paddingSize, key, iv, encrypting);
}
protected override void EncryptKeyWrapPaddedCore(ReadOnlySpan<byte> source, Span<byte> destination)
{
int written = KeyWrap(source, destination, enc: 1);
Debug.Assert(written == destination.Length);
}
protected override int DecryptKeyWrapPaddedCore(ReadOnlySpan<byte> source, Span<byte> destination)
{
return KeyWrap(source, destination, enc: 0);
}
private int KeyWrap(ReadOnlySpan<byte> source, Span<byte> destination, int enc)
{
Debug.Assert(enc is 0 or 1);
SafeEvpCipherCtxHandle ctx = GetKey().UseKey(
state: enc,
static (enc, key) =>
{
int keySizeInBits = key.Length * 8;
IntPtr algorithm = GetKeyWrapAlgorithm(keySizeInBits);
SafeEvpCipherCtxHandle ctx = Interop.Crypto.EvpCipherCreate(
algorithm,
ref MemoryMarshal.GetReference(key),
key.Length * 8,
ref MemoryMarshal.GetReference(ReadOnlySpan<byte>.Empty),
enc);
if (ctx.IsInvalid)
{
ctx.Dispose();
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
return ctx;
});
int written;
using (ctx)
{
bool ret = Interop.Crypto.EvpCipherUpdate(
ctx,
destination,
out written,
source);
if (!ret)
{
throw Interop.Crypto.CreateOpenSslCryptographicException();
}
Debug.Assert(written > 0);
// Experimentation and code insepection show that EVP_CipherFinal_ex is not needed here,
// the work is done in EVP_CipherUpdate.
// Since AES-KW(P) involves multiple passes over the data, where the end of each pass
// stores a tag/checksum back in the beginning of the buffer, it makes sense that only
// one of Update or Final could write data, and they chose to go with Update.
//
// As the call to Final does not yield more data, and we're about to dispose the context,
// don't bother making the call.
}
return written;
}
private static IntPtr GetAlgorithm(int keySize, int feedback, CipherMode cipherMode) =>
(keySize, cipherMode) switch
{
@ -59,5 +132,14 @@ namespace System.Security.Cryptography
new NotSupportedException() :
new CryptographicException(SR.Cryptography_InvalidKeySize)),
};
private static IntPtr GetKeyWrapAlgorithm(int keySize) =>
keySize switch
{
128 => Interop.Crypto.EvpAes128WrapPad(),
192 => Interop.Crypto.EvpAes192WrapPad(),
256 => Interop.Crypto.EvpAes256WrapPad(),
_ => throw new CryptographicException(SR.Cryptography_InvalidKeySize),
};
}
}

View File

@ -100,18 +100,21 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_EvpAes128Cfb8)
DllImportEntry(CryptoNative_EvpAes128Ecb)
DllImportEntry(CryptoNative_EvpAes128Gcm)
DllImportEntry(CryptoNative_EvpAes128WrapPad)
DllImportEntry(CryptoNative_EvpAes192Cbc)
DllImportEntry(CryptoNative_EvpAes192Ccm)
DllImportEntry(CryptoNative_EvpAes192Cfb128)
DllImportEntry(CryptoNative_EvpAes192Cfb8)
DllImportEntry(CryptoNative_EvpAes192Ecb)
DllImportEntry(CryptoNative_EvpAes192Gcm)
DllImportEntry(CryptoNative_EvpAes192WrapPad)
DllImportEntry(CryptoNative_EvpAes256Cbc)
DllImportEntry(CryptoNative_EvpAes256Ccm)
DllImportEntry(CryptoNative_EvpAes256Cfb128)
DllImportEntry(CryptoNative_EvpAes256Cfb8)
DllImportEntry(CryptoNative_EvpAes256Ecb)
DllImportEntry(CryptoNative_EvpAes256Gcm)
DllImportEntry(CryptoNative_EvpAes256WrapPad)
DllImportEntry(CryptoNative_EvpChaCha20Poly1305)
DllImportEntry(CryptoNative_EvpCipherCreate2)
DllImportEntry(CryptoNative_EvpCipherCreatePartial)

View File

@ -453,18 +453,21 @@ extern bool g_libSslUses32BitTime;
REQUIRED_FUNCTION(EVP_aes_128_cfb8) \
REQUIRED_FUNCTION(EVP_aes_128_ecb) \
REQUIRED_FUNCTION(EVP_aes_128_gcm) \
REQUIRED_FUNCTION(EVP_aes_128_wrap_pad) \
REQUIRED_FUNCTION(EVP_aes_192_cbc) \
REQUIRED_FUNCTION(EVP_aes_192_ccm) \
REQUIRED_FUNCTION(EVP_aes_192_cfb128) \
REQUIRED_FUNCTION(EVP_aes_192_cfb8) \
REQUIRED_FUNCTION(EVP_aes_192_ecb) \
REQUIRED_FUNCTION(EVP_aes_192_gcm) \
REQUIRED_FUNCTION(EVP_aes_192_wrap_pad) \
REQUIRED_FUNCTION(EVP_aes_256_cbc) \
REQUIRED_FUNCTION(EVP_aes_256_ccm) \
REQUIRED_FUNCTION(EVP_aes_256_cfb128) \
REQUIRED_FUNCTION(EVP_aes_256_cfb8) \
REQUIRED_FUNCTION(EVP_aes_256_ecb) \
REQUIRED_FUNCTION(EVP_aes_256_gcm) \
REQUIRED_FUNCTION(EVP_aes_256_wrap_pad) \
LIGHTUP_FUNCTION(EVP_chacha20_poly1305) \
LEGACY_FUNCTION(EVP_CIPHER_CTX_cleanup) \
REQUIRED_FUNCTION(EVP_CIPHER_CTX_ctrl) \
@ -472,6 +475,7 @@ extern bool g_libSslUses32BitTime;
LEGACY_FUNCTION(EVP_CIPHER_CTX_init) \
FALLBACK_FUNCTION(EVP_CIPHER_CTX_new) \
FALLBACK_FUNCTION(EVP_CIPHER_CTX_reset) \
REQUIRED_FUNCTION(EVP_CIPHER_CTX_set_flags) \
REQUIRED_FUNCTION(EVP_CIPHER_CTX_set_key_length) \
REQUIRED_FUNCTION(EVP_CIPHER_CTX_set_padding) \
RENAMED_FUNCTION(EVP_CIPHER_get_nid, EVP_CIPHER_nid) \
@ -1025,18 +1029,21 @@ extern TYPEOF(OPENSSL_gmtime)* OPENSSL_gmtime_ptr;
#define EVP_aes_128_ecb EVP_aes_128_ecb_ptr
#define EVP_aes_128_gcm EVP_aes_128_gcm_ptr
#define EVP_aes_128_ccm EVP_aes_128_ccm_ptr
#define EVP_aes_128_wrap_pad EVP_aes_128_wrap_pad_ptr
#define EVP_aes_192_cbc EVP_aes_192_cbc_ptr
#define EVP_aes_192_cfb8 EVP_aes_192_cfb8_ptr
#define EVP_aes_192_cfb128 EVP_aes_192_cfb128_ptr
#define EVP_aes_192_ecb EVP_aes_192_ecb_ptr
#define EVP_aes_192_gcm EVP_aes_192_gcm_ptr
#define EVP_aes_192_ccm EVP_aes_192_ccm_ptr
#define EVP_aes_192_wrap_pad EVP_aes_192_wrap_pad_ptr
#define EVP_aes_256_cbc EVP_aes_256_cbc_ptr
#define EVP_aes_256_cfb8 EVP_aes_256_cfb8_ptr
#define EVP_aes_256_cfb128 EVP_aes_256_cfb128_ptr
#define EVP_aes_256_ecb EVP_aes_256_ecb_ptr
#define EVP_aes_256_gcm EVP_aes_256_gcm_ptr
#define EVP_aes_256_ccm EVP_aes_256_ccm_ptr
#define EVP_aes_256_wrap_pad EVP_aes_256_wrap_pad_ptr
#define EVP_chacha20_poly1305 EVP_chacha20_poly1305_ptr
#define EVP_CIPHER_CTX_cleanup EVP_CIPHER_CTX_cleanup_ptr
#define EVP_CIPHER_CTX_ctrl EVP_CIPHER_CTX_ctrl_ptr
@ -1044,6 +1051,7 @@ extern TYPEOF(OPENSSL_gmtime)* OPENSSL_gmtime_ptr;
#define EVP_CIPHER_CTX_init EVP_CIPHER_CTX_init_ptr
#define EVP_CIPHER_CTX_new EVP_CIPHER_CTX_new_ptr
#define EVP_CIPHER_CTX_reset EVP_CIPHER_CTX_reset_ptr
#define EVP_CIPHER_CTX_set_flags EVP_CIPHER_CTX_set_flags_ptr
#define EVP_CIPHER_CTX_set_key_length EVP_CIPHER_CTX_set_key_length_ptr
#define EVP_CIPHER_CTX_set_padding EVP_CIPHER_CTX_set_padding_ptr
#define EVP_CIPHER_get_nid EVP_CIPHER_get_nid_ptr

View File

@ -8,6 +8,8 @@
#define SUCCESS 1
#define KEEP_CURRENT_DIRECTION -1
c_static_assert(EVP_CIPHER_CTX_FLAG_WRAP_ALLOW == 1);
EVP_CIPHER_CTX*
CryptoNative_EvpCipherCreate2(const EVP_CIPHER* type, uint8_t* key, int32_t keyLength, unsigned char* iv, int32_t enc)
{
@ -30,6 +32,9 @@ CryptoNative_EvpCipherCreate2(const EVP_CIPHER* type, uint8_t* key, int32_t keyL
return NULL;
}
// Required for OpenSSL 1.1 AES-KWP, no-op in OpenSSL 3.
EVP_CIPHER_CTX_set_flags(ctx, EVP_CIPHER_CTX_FLAG_WRAP_ALLOW);
// Perform partial initialization so we can set the key lengths
int ret = EVP_CipherInit_ex(ctx, type, NULL, NULL, NULL, 0);
if (!ret)
@ -275,6 +280,12 @@ const EVP_CIPHER* CryptoNative_EvpAes128Ccm(void)
return EVP_aes_128_ccm();
}
const EVP_CIPHER* CryptoNative_EvpAes128WrapPad(void)
{
// No error queue impact.
return EVP_aes_128_wrap_pad();
}
const EVP_CIPHER* CryptoNative_EvpAes192Ecb(void)
{
// No error queue impact.
@ -311,6 +322,12 @@ const EVP_CIPHER* CryptoNative_EvpAes192Ccm(void)
return EVP_aes_192_ccm();
}
const EVP_CIPHER* CryptoNative_EvpAes192WrapPad(void)
{
// No error queue impact.
return EVP_aes_192_wrap_pad();
}
const EVP_CIPHER* CryptoNative_EvpAes256Ecb(void)
{
// No error queue impact.
@ -347,6 +364,12 @@ const EVP_CIPHER* CryptoNative_EvpAes256Ccm(void)
return EVP_aes_256_ccm();
}
const EVP_CIPHER* CryptoNative_EvpAes256WrapPad(void)
{
// No error queue impact.
return EVP_aes_256_wrap_pad();
}
const EVP_CIPHER* CryptoNative_EvpDesEcb(void)
{
// No error queue impact.

View File

@ -158,6 +158,14 @@ Direct shim to EVP_aes_128_ccm.
*/
PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes128Ccm(void);
/*
Function:
EvpAes128WrapPad
Direct shim to EVP_aes_128_wrap_pad.
*/
PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes128WrapPad(void);
/*
Function:
EvpAes192Ecb
@ -206,6 +214,14 @@ Direct shim to EVP_aes_192_ccm.
*/
PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes192Ccm(void);
/*
Function:
EvpAes192WrapPad
Direct shim to EVP_aes_192_wrap_pad.
*/
PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes192WrapPad(void);
/*
Function:
EvpAes256Ecb
@ -254,6 +270,14 @@ Direct shim to EVP_aes_256_ccm.
*/
PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes256Ccm(void);
/*
Function:
EvpAes256WrapPad
Direct shim to EVP_aes_256_wrap_pad.
*/
PALEXPORT const EVP_CIPHER* CryptoNative_EvpAes256WrapPad(void);
/*
Function:
EvpDes3Ecb