Skip to content

Commit

Permalink
Use OpenSSL 3's HKDF if it is available
Browse files Browse the repository at this point in the history
  • Loading branch information
vcsjones committed Aug 26, 2024
1 parent 2a6fab0 commit 56435ad
Show file tree
Hide file tree
Showing 14 changed files with 633 additions and 151 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,41 @@ internal static partial class Crypto
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpKdfFree")]
internal static partial void EvpKdfFree(IntPtr kdf);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HkdfDeriveKey", StringMarshalling = StringMarshalling.Utf8)]
private static partial int CryptoNative_HkdfDeriveKey(
SafeEvpKdfHandle kdf,
ReadOnlySpan<byte> ikm,
int ikmLength,
string algorithm,
ReadOnlySpan<byte> salt,
int saltLength,
ReadOnlySpan<byte> info,
int infoLength,
Span<byte> destination,
int destinationLength);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HkdfExpand", StringMarshalling = StringMarshalling.Utf8)]
private static partial int CryptoNative_HkdfExpand(
SafeEvpKdfHandle kdf,
ReadOnlySpan<byte> prk,
int prkLength,
string algorithm,
ReadOnlySpan<byte> info,
int infoLength,
Span<byte> destination,
int destinationLength);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HkdfExtract", StringMarshalling = StringMarshalling.Utf8)]
private static partial int CryptoNative_HkdfExtract(
SafeEvpKdfHandle kdf,
ReadOnlySpan<byte> ikm,
int ikmLength,
string algorithm,
ReadOnlySpan<byte> salt,
int saltLength,
Span<byte> destination,
int destinationLength);

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_KbkdfHmacOneShot", StringMarshalling = StringMarshalling.Utf8)]
private static unsafe partial int CryptoNative_KbkdfHmacOneShot(
SafeEvpKdfHandle kdf,
Expand All @@ -26,6 +61,84 @@ private static unsafe partial int CryptoNative_KbkdfHmacOneShot(
Span<byte> destination,
int destinationLength);

internal static void HkdfDeriveKey(
SafeEvpKdfHandle kdf,
ReadOnlySpan<byte> ikm,
string algorithm,
ReadOnlySpan<byte> salt,
ReadOnlySpan<byte> info,
Span<byte> destination)
{
const int Success = 1;
int ret = CryptoNative_HkdfDeriveKey(
kdf,
ikm,
ikm.Length,
algorithm,
salt,
salt.Length,
info,
info.Length,
destination,
destination.Length);

if (ret != Success)
{
Debug.Assert(ret == 0);
throw CreateOpenSslCryptographicException();
}
}

internal static void HkdfExpand(
SafeEvpKdfHandle kdf,
ReadOnlySpan<byte> prk,
string algorithm,
ReadOnlySpan<byte> info,
Span<byte> destination)
{
const int Success = 1;
int ret = CryptoNative_HkdfExpand(
kdf,
prk,
prk.Length,
algorithm,
info,
info.Length,
destination,
destination.Length);

if (ret != Success)
{
Debug.Assert(ret == 0);
throw CreateOpenSslCryptographicException();
}
}

internal static void HkdfExtract(
SafeEvpKdfHandle kdf,
ReadOnlySpan<byte> ikm,
string algorithm,
ReadOnlySpan<byte> salt,
Span<byte> destination)
{
const int Success = 1;
int ret = CryptoNative_HkdfExtract(
kdf,
ikm,
ikm.Length,
algorithm,
salt,
salt.Length,
destination,
destination.Length);

if (ret != Success)
{
Debug.Assert(ret == 0);
throw CreateOpenSslCryptographicException();
}
}

internal static void KbkdfHmacOneShot(
SafeEvpKdfHandle kdf,
ReadOnlySpan<byte> key,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@ internal static partial class Crypto
internal static partial class EvpKdfAlgs
{
private const string KbkdfAlgorithmName = "KBKDF";
private const string HkdfAlgorithmName = "HKDF";

internal static SafeEvpKdfHandle? Kbkdf { get; }
internal static SafeEvpKdfHandle? Hkdf { get; }

static EvpKdfAlgs()
{
Expand All @@ -24,6 +26,7 @@ static EvpKdfAlgs()
// is called first. Property initializers happen before cctors, so instead set the property after the
// initializer is run.
Kbkdf = EvpKdfFetch(KbkdfAlgorithmName);
Hkdf = EvpKdfFetch(HkdfAlgorithmName);
}

[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpKdfFetch", StringMarshalling = StringMarshalling.Utf8)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -418,6 +418,7 @@
<Compile Include="System\Security\Cryptography\HashProvider.cs" />
<Compile Include="System\Security\Cryptography\Helpers.cs" />
<Compile Include="System\Security\Cryptography\HKDF.cs" />
<Compile Include="System\Security\Cryptography\HKDFManagedImplementation.cs" />
<Compile Include="System\Security\Cryptography\HMAC.cs" />
<Compile Include="System\Security\Cryptography\HMACCommon.cs" />
<Compile Include="System\Security\Cryptography\HMACMD5.cs" />
Expand Down Expand Up @@ -668,6 +669,7 @@
<Compile Include="System\Security\Cryptography\ECDiffieHellman.Create.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\ECDsa.Create.NotSupported.cs" />
<Compile Include="System\Security\Cryptography\HashProviderDispenser.Browser.cs" />
<Compile Include="System\Security\Cryptography\HKDF.Managed.cs" />
<Compile Include="System\Security\Cryptography\HMACHashProvider.Browser.Managed.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Browser.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Kmac.Unsupported.cs" />
Expand Down Expand Up @@ -864,6 +866,7 @@
<Compile Include="System\Security\Cryptography\ECDiffieHellmanWrapper.cs" />
<Compile Include="System\Security\Cryptography\HashProviderDispenser.Unix.cs" />
<Compile Include="System\Security\Cryptography\HashProviderDispenser.OpenSsl.cs" />
<Compile Include="System\Security\Cryptography\HKDF.OpenSsl.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Unix.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.OpenSsl.cs" />
<Compile Include="System\Security\Cryptography\OidLookup.OpenSsl.cs" />
Expand Down Expand Up @@ -1024,6 +1027,7 @@
<Compile Include="System\Security\Cryptography\ECDsa.Create.Android.cs" />
<Compile Include="System\Security\Cryptography\HashProviderDispenser.Unix.cs" />
<Compile Include="System\Security\Cryptography\HashProviderDispenser.Android.cs" />
<Compile Include="System\Security\Cryptography\HKDF.Managed.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Unix.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Kmac.Unsupported.cs" />
<Compile Include="System\Security\Cryptography\OidLookup.NoFallback.cs" />
Expand Down Expand Up @@ -1154,6 +1158,7 @@
<Compile Include="System\Security\Cryptography\ECDsa.Create.SecurityTransforms.cs" />
<Compile Include="System\Security\Cryptography\HashAlgorithmNames.Apple.cs" />
<Compile Include="System\Security\Cryptography\HashProviderDispenser.Apple.cs" />
<Compile Include="System\Security\Cryptography\HKDF.Managed.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Apple.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Kmac.Unsupported.cs" />
<Compile Include="System\Security\Cryptography\OidLookup.NoFallback.cs" />
Expand Down Expand Up @@ -1745,6 +1750,7 @@
<Compile Include="System\Security\Cryptography\ECDiffieHellmanWrapper.cs" />
<Compile Include="System\Security\Cryptography\HashProviderCng.cs" />
<Compile Include="System\Security\Cryptography\HashProviderDispenser.Windows.cs" />
<Compile Include="System\Security\Cryptography\HKDF.Managed.cs" />
<Compile Include="System\Security\Cryptography\ICngSymmetricAlgorithm.cs" />
<Compile Include="System\Security\Cryptography\KeyPropertyName.cs" />
<Compile Include="System\Security\Cryptography\LiteHash.Windows.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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
{
public static partial class HKDF
{
private static void Extract(
HashAlgorithmName hashAlgorithmName,
int hashLength,
ReadOnlySpan<byte> ikm,
ReadOnlySpan<byte> salt,
Span<byte> prk)
{
HKDFManagedImplementation.Extract(hashAlgorithmName, hashLength, ikm, salt, prk);
}

private static void Expand(
HashAlgorithmName hashAlgorithmName,
int hashLength,
ReadOnlySpan<byte> prk,
Span<byte> output,
ReadOnlySpan<byte> info)
{
HKDFManagedImplementation.Expand(hashAlgorithmName, hashLength, prk, output, info);
}

private static void DeriveKeyCore(
HashAlgorithmName hashAlgorithmName,
int hashLength,
ReadOnlySpan<byte> ikm,
Span<byte> output,
ReadOnlySpan<byte> salt,
ReadOnlySpan<byte> info)
{
HKDFManagedImplementation.DeriveKey(hashAlgorithmName, hashLength, ikm, output, salt, info);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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;

namespace System.Security.Cryptography
{
public static partial class HKDF
{
private static readonly bool s_hasOpenSslImplementation = Interop.Crypto.EvpKdfAlgs.Hkdf is not null;

private static void Extract(
HashAlgorithmName hashAlgorithmName,
int hashLength,
ReadOnlySpan<byte> ikm,
ReadOnlySpan<byte> salt,
Span<byte> prk)
{
if (s_hasOpenSslImplementation)
{
Debug.Assert(Interop.Crypto.EvpKdfAlgs.Hkdf is not null);
Debug.Assert(hashAlgorithmName.Name is not null);

Interop.Crypto.HkdfExtract(Interop.Crypto.EvpKdfAlgs.Hkdf, ikm, hashAlgorithmName.Name, salt, prk);
}
else
{
HKDFManagedImplementation.Extract(hashAlgorithmName, hashLength, ikm, salt, prk);
}
}

private static void Expand(
HashAlgorithmName hashAlgorithmName,
int hashLength,
ReadOnlySpan<byte> prk,
Span<byte> output,
ReadOnlySpan<byte> info)
{
if (s_hasOpenSslImplementation)
{
Debug.Assert(Interop.Crypto.EvpKdfAlgs.Hkdf is not null);
Debug.Assert(hashAlgorithmName.Name is not null);

Interop.Crypto.HkdfExpand(Interop.Crypto.EvpKdfAlgs.Hkdf, prk, hashAlgorithmName.Name, info, output);
}
else
{
HKDFManagedImplementation.Expand(hashAlgorithmName, hashLength, prk, output, info);
}
}

private static void DeriveKeyCore(
HashAlgorithmName hashAlgorithmName,
int hashLength,
ReadOnlySpan<byte> ikm,
Span<byte> output,
ReadOnlySpan<byte> salt,
ReadOnlySpan<byte> info)
{
if (s_hasOpenSslImplementation)
{
Debug.Assert(Interop.Crypto.EvpKdfAlgs.Hkdf is not null);
Debug.Assert(hashAlgorithmName.Name is not null);

Interop.Crypto.HkdfDeriveKey(
Interop.Crypto.EvpKdfAlgs.Hkdf,
ikm,
hashAlgorithmName.Name,
salt,
info,
output);
}
else
{
HKDFManagedImplementation.DeriveKey(hashAlgorithmName, hashLength, ikm, output, salt, info);
}
}
}
}
Loading

0 comments on commit 56435ad

Please sign in to comment.