-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Use OpenSSL 3's KBKDF for SP800-108 if it is available (#106893)
- Loading branch information
Showing
13 changed files
with
591 additions
and
1 deletion.
There are no files selected for viewing
57 changes: 57 additions & 0 deletions
57
src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.Kdf.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
using Microsoft.Win32.SafeHandles; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Crypto | ||
{ | ||
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpKdfFree")] | ||
internal static partial void EvpKdfFree(IntPtr kdf); | ||
|
||
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_KbkdfHmacOneShot", StringMarshalling = StringMarshalling.Utf8)] | ||
private static unsafe partial int CryptoNative_KbkdfHmacOneShot( | ||
SafeEvpKdfHandle kdf, | ||
ReadOnlySpan<byte> key, | ||
int keyLength, | ||
string algorithm, | ||
ReadOnlySpan<byte> label, | ||
int labelLength, | ||
ReadOnlySpan<byte> context, | ||
int contextLength, | ||
Span<byte> destination, | ||
int destinationLength); | ||
|
||
internal static void KbkdfHmacOneShot( | ||
SafeEvpKdfHandle kdf, | ||
ReadOnlySpan<byte> key, | ||
string algorithm, | ||
ReadOnlySpan<byte> label, | ||
ReadOnlySpan<byte> context, | ||
Span<byte> destination) | ||
{ | ||
const int Success = 1; | ||
int ret = CryptoNative_KbkdfHmacOneShot( | ||
kdf, | ||
key, | ||
key.Length, | ||
algorithm, | ||
label, | ||
label.Length, | ||
context, | ||
context.Length, | ||
destination, | ||
destination.Length); | ||
|
||
if (ret != Success) | ||
{ | ||
Debug.Assert(ret == 0); | ||
throw CreateOpenSslCryptographicException(); | ||
} | ||
} | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
...raries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.EVP.KdfAlgs.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// 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 System.Security.Cryptography; | ||
using Microsoft.Win32.SafeHandles; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class Crypto | ||
{ | ||
internal static partial class EvpKdfAlgs | ||
{ | ||
private const string KbkdfAlgorithmName = "KBKDF"; | ||
|
||
internal static SafeEvpKdfHandle? Kbkdf { get; } | ||
|
||
static EvpKdfAlgs() | ||
{ | ||
CryptoInitializer.Initialize(); | ||
|
||
// Do not use property initializers for these because we need to ensure CryptoInitializer.Initialize | ||
// is called first. Property initializers happen before cctors, so instead set the property after the | ||
// initializer is run. | ||
Kbkdf = EvpKdfFetch(KbkdfAlgorithmName); | ||
} | ||
|
||
[LibraryImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_EvpKdfFetch", StringMarshalling = StringMarshalling.Utf8)] | ||
private static partial SafeEvpKdfHandle CryptoNative_EvpKdfFetch(string algorithm, out int haveFeature); | ||
|
||
private static SafeEvpKdfHandle? EvpKdfFetch(string algorithm) | ||
{ | ||
SafeEvpKdfHandle kdf = CryptoNative_EvpKdfFetch(algorithm, out int haveFeature); | ||
|
||
if (haveFeature == 0) | ||
{ | ||
Debug.Assert(kdf.IsInvalid); | ||
kdf.Dispose(); | ||
return null; | ||
} | ||
|
||
if (kdf.IsInvalid) | ||
{ | ||
kdf.Dispose(); | ||
throw CreateOpenSslCryptographicException(); | ||
} | ||
|
||
return kdf; | ||
} | ||
} | ||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/libraries/Common/src/Microsoft/Win32/SafeHandles/SafeEvpKdfHandle.Unix.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Security; | ||
using System.Runtime.InteropServices; | ||
|
||
namespace Microsoft.Win32.SafeHandles | ||
{ | ||
internal sealed class SafeEvpKdfHandle : SafeHandle | ||
{ | ||
public SafeEvpKdfHandle() : base(0, ownsHandle: true) | ||
{ | ||
} | ||
|
||
protected override bool ReleaseHandle() | ||
{ | ||
Interop.Crypto.EvpKdfFree(handle); | ||
handle = 0; | ||
return true; | ||
} | ||
|
||
public override bool IsInvalid => handle == 0; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
79 changes: 79 additions & 0 deletions
79
....Security.Cryptography/src/System/Security/Cryptography/SP800108HmacCounterKdf.OpenSsl.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. | ||
|
||
namespace System.Security.Cryptography | ||
{ | ||
public sealed partial class SP800108HmacCounterKdf : IDisposable | ||
{ | ||
private static readonly bool s_hasOpenSslImplementation = Interop.Crypto.EvpKdfAlgs.Kbkdf is not null; | ||
|
||
private static partial SP800108HmacCounterKdfImplementationBase CreateImplementation( | ||
ReadOnlySpan<byte> key, | ||
HashAlgorithmName hashAlgorithm) | ||
{ | ||
if (s_hasOpenSslImplementation) | ||
{ | ||
return new SP800108HmacCounterKdfImplementationOpenSsl(key, hashAlgorithm); | ||
} | ||
else | ||
{ | ||
return new SP800108HmacCounterKdfImplementationManaged(key, hashAlgorithm); | ||
} | ||
} | ||
|
||
private static partial byte[] DeriveBytesCore( | ||
byte[] key, | ||
HashAlgorithmName hashAlgorithm, | ||
byte[] label, | ||
byte[] context, | ||
int derivedKeyLengthInBytes) | ||
{ | ||
byte[] result = new byte[derivedKeyLengthInBytes]; | ||
|
||
if (s_hasOpenSslImplementation) | ||
{ | ||
SP800108HmacCounterKdfImplementationOpenSsl.DeriveBytesOneShot(key, hashAlgorithm, label, context, result); | ||
} | ||
else | ||
{ | ||
SP800108HmacCounterKdfImplementationManaged.DeriveBytesOneShot(key, hashAlgorithm, label, context, result); | ||
} | ||
|
||
return result; | ||
} | ||
|
||
private static partial void DeriveBytesCore( | ||
ReadOnlySpan<byte> key, | ||
HashAlgorithmName hashAlgorithm, | ||
ReadOnlySpan<byte> label, | ||
ReadOnlySpan<byte> context, | ||
Span<byte> destination) | ||
{ | ||
if (s_hasOpenSslImplementation) | ||
{ | ||
SP800108HmacCounterKdfImplementationOpenSsl.DeriveBytesOneShot(key, hashAlgorithm, label, context, destination); | ||
} | ||
else | ||
{ | ||
SP800108HmacCounterKdfImplementationManaged.DeriveBytesOneShot(key, hashAlgorithm, label, context, destination); | ||
} | ||
} | ||
|
||
private static partial void DeriveBytesCore( | ||
ReadOnlySpan<byte> key, | ||
HashAlgorithmName hashAlgorithm, | ||
ReadOnlySpan<char> label, | ||
ReadOnlySpan<char> context, | ||
Span<byte> destination) | ||
{ | ||
if (s_hasOpenSslImplementation) | ||
{ | ||
SP800108HmacCounterKdfImplementationOpenSsl.DeriveBytesOneShot(key, hashAlgorithm, label, context, destination); | ||
} | ||
else | ||
{ | ||
SP800108HmacCounterKdfImplementationManaged.DeriveBytesOneShot(key, hashAlgorithm, label, context, destination); | ||
} | ||
} | ||
} | ||
} |
114 changes: 114 additions & 0 deletions
114
...ptography/src/System/Security/Cryptography/SP800108HmacCounterKdfImplementationOpenSsl.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// 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 Microsoft.Win32.SafeHandles; | ||
|
||
namespace System.Security.Cryptography | ||
{ | ||
internal sealed class SP800108HmacCounterKdfImplementationOpenSsl : SP800108HmacCounterKdfImplementationBase | ||
{ | ||
private const int CharToBytesStackBufferSize = 256; | ||
|
||
private readonly HashAlgorithmName _hashAlgorithm; | ||
private readonly FixedMemoryKeyBox _keyBox; | ||
|
||
internal unsafe SP800108HmacCounterKdfImplementationOpenSsl(ReadOnlySpan<byte> key, HashAlgorithmName hashAlgorithm) | ||
{ | ||
_hashAlgorithm = hashAlgorithm; | ||
_keyBox = new FixedMemoryKeyBox(key); | ||
} | ||
|
||
public override void Dispose() | ||
{ | ||
_keyBox.Dispose(); | ||
} | ||
|
||
internal override unsafe void DeriveBytes(ReadOnlySpan<byte> label, ReadOnlySpan<byte> context, Span<byte> destination) | ||
{ | ||
Debug.Assert(Interop.Crypto.EvpKdfAlgs.Kbkdf is { IsInvalid: false }); | ||
|
||
if (destination.IsEmpty) | ||
{ | ||
return; | ||
} | ||
|
||
bool acquired = false; | ||
|
||
try | ||
{ | ||
_keyBox.DangerousAddRef(ref acquired); | ||
Interop.Crypto.KbkdfHmacOneShot( | ||
Interop.Crypto.EvpKdfAlgs.Kbkdf, | ||
_keyBox.DangerousKeySpan, | ||
_hashAlgorithm.Name!, | ||
label, | ||
context, | ||
destination); | ||
} | ||
finally | ||
{ | ||
if (acquired) | ||
{ | ||
_keyBox.DangerousRelease(); | ||
} | ||
} | ||
} | ||
|
||
internal override void DeriveBytes(byte[] label, byte[] context, Span<byte> destination) | ||
{ | ||
DeriveBytes(new ReadOnlySpan<byte>(label), new ReadOnlySpan<byte>(context), destination); | ||
} | ||
|
||
internal override void DeriveBytes(ReadOnlySpan<char> label, ReadOnlySpan<char> context, Span<byte> destination) | ||
{ | ||
using (Utf8DataEncoding labelData = new Utf8DataEncoding(label, stackalloc byte[CharToBytesStackBufferSize])) | ||
using (Utf8DataEncoding contextData = new Utf8DataEncoding(context, stackalloc byte[CharToBytesStackBufferSize])) | ||
{ | ||
DeriveBytes(labelData.Utf8Bytes, contextData.Utf8Bytes, destination); | ||
} | ||
} | ||
|
||
internal static void DeriveBytesOneShot( | ||
ReadOnlySpan<byte> key, | ||
HashAlgorithmName hashAlgorithm, | ||
ReadOnlySpan<byte> label, | ||
ReadOnlySpan<byte> context, | ||
Span<byte> destination) | ||
{ | ||
Debug.Assert(Interop.Crypto.EvpKdfAlgs.Kbkdf is { IsInvalid: false }); | ||
|
||
if (destination.IsEmpty) | ||
{ | ||
return; | ||
} | ||
|
||
Interop.Crypto.KbkdfHmacOneShot( | ||
Interop.Crypto.EvpKdfAlgs.Kbkdf, | ||
key, | ||
hashAlgorithm.Name!, | ||
label, | ||
context, | ||
destination); | ||
} | ||
|
||
internal static void DeriveBytesOneShot( | ||
ReadOnlySpan<byte> key, | ||
HashAlgorithmName hashAlgorithm, | ||
ReadOnlySpan<char> label, | ||
ReadOnlySpan<char> context, | ||
Span<byte> destination) | ||
{ | ||
if (destination.Length == 0) | ||
{ | ||
return; | ||
} | ||
|
||
using (Utf8DataEncoding labelData = new Utf8DataEncoding(label, stackalloc byte[CharToBytesStackBufferSize])) | ||
using (Utf8DataEncoding contextData = new Utf8DataEncoding(context, stackalloc byte[CharToBytesStackBufferSize])) | ||
{ | ||
DeriveBytesOneShot(key, hashAlgorithm, labelData.Utf8Bytes, contextData.Utf8Bytes, destination); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.