Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hmac one-shot #53487

Merged
merged 8 commits into from
Jun 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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;

Expand Down Expand Up @@ -29,5 +30,29 @@ internal static int HmacUpdate(SafeHmacCtxHandle ctx, ReadOnlySpan<byte> data, i

[DllImport(Libraries.AndroidCryptoNative, EntryPoint = "CryptoNative_HmacCurrent")]
internal static extern int HmacCurrent(SafeHmacCtxHandle ctx, ref byte data, ref int len);

[DllImport(Libraries.AndroidCryptoNative, EntryPoint = "CryptoNative_HmacOneShot")]
private static unsafe extern int HmacOneShot(IntPtr type, byte* key, int keySize, byte* source, int sourceSize, byte* md, ref int mdSize);

internal static unsafe int HmacOneShot(IntPtr type, ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
{
int size = destination.Length;
const int Success = 1;

fixed (byte* pKey = key)
fixed (byte* pSource = source)
fixed (byte* pDestination = destination)
{
int result = HmacOneShot(type, pKey, key.Length, pSource, source.Length, pDestination, ref size);

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

return size;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,17 @@ internal static int HmacCurrent(SafeHmacHandle ctx, ReadOnlySpan<byte> output) =

[DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacCurrent")]
private static extern int HmacCurrent(SafeHmacHandle ctx, ref byte pbOutput, int cbOutput);

[DllImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacOneShot")]
internal static unsafe extern int HmacOneShot(
PAL_HashAlgorithm algorithm,
byte* pKey,
int cbKey,
byte* pData,
int cbData,
byte* pOutput,
int cbOutput,
out int cbDigest);
bartonjs marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// 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;

Expand Down Expand Up @@ -29,5 +30,29 @@ internal static int HmacUpdate(SafeHmacCtxHandle ctx, ReadOnlySpan<byte> data, i

[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HmacCurrent")]
internal static extern int HmacCurrent(SafeHmacCtxHandle ctx, ref byte data, ref int len);

[DllImport(Libraries.CryptoNative, EntryPoint = "CryptoNative_HmacOneShot")]
private static unsafe extern int HmacOneShot(IntPtr type, byte* key, int keySize, byte* source, int sourceSize, byte* md, ref int mdSize);

internal static unsafe int HmacOneShot(IntPtr type, ReadOnlySpan<byte> key, ReadOnlySpan<byte> source, Span<byte> destination)
{
int size = destination.Length;
const int Success = 1;

fixed (byte* pKey = key)
fixed (byte* pSource = source)
fixed (byte* pDestination = destination)
{
int result = HmacOneShot(type, pKey, key.Length, pSource, source.Length, pDestination, ref size);

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

return size;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ public enum BCryptAlgPseudoHandle : uint
BCRYPT_SHA256_ALG_HANDLE = 0x00000041,
BCRYPT_SHA384_ALG_HANDLE = 0x00000051,
BCRYPT_SHA512_ALG_HANDLE = 0x00000061,
BCRYPT_HMAC_MD5_ALG_HANDLE = 0x00000091,
BCRYPT_HMAC_SHA1_ALG_HANDLE = 0x000000a1,
BCRYPT_HMAC_SHA256_ALG_HANDLE = 0x000000b1,
BCRYPT_HMAC_SHA384_ALG_HANDLE = 0x000000c1,
BCRYPT_HMAC_SHA512_ALG_HANDLE = 0x000000d1,
BCRYPT_PBKDF2_ALG_HANDLE = 0x00000331,
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ public static void CollectionEqual<T>(IEnumerable<T> expected, IEnumerable<T> ac
{
actualItemCountMapping[actualItem] = new ItemCount(1, 1);
}

actualCount++;
}

Expand Down Expand Up @@ -431,7 +431,7 @@ public static void CollectionEqual<T>(IEnumerable<T> expected, IEnumerable<T> ac
countInfo.Remain--;
}
}

/// <summary>
/// Validates that the actual span is equal to the expected span.
/// If this fails, determine where the differences are and create an exception with that information.
Expand Down Expand Up @@ -475,6 +475,19 @@ public static void SequenceEqual<T>(ReadOnlySpan<T> expected, ReadOnlySpan<T> ac
}
}

public static void FilledWith<T>(T expected, ReadOnlySpan<T> actual)
{
EqualityComparer<T> comparer = EqualityComparer<T>.Default;

for (int i = 0; i < actual.Length; i++)
{
if (!comparer.Equals(expected, actual[i]))
{
throw new XunitException($"Expected {expected?.ToString() ?? "null"} at position {i}");
}
}
}

public static void SequenceEqual<T>(Span<T> expected, Span<T> actual) where T : IEquatable<T> => SequenceEqual((ReadOnlySpan<T>)expected, (ReadOnlySpan<T>)actual);

public static void SequenceEqual<T>(T[] expected, T[] actual) where T : IEquatable<T> => SequenceEqual(expected.AsSpan(), actual.AsSpan());
Expand Down Expand Up @@ -556,7 +569,7 @@ public static E Throws<E, T>(string expectedParamName, Span<T> span, AssertThrow
Assert.Equal(expectedParamName, exception.ParamName);
return exception;
}

private class ItemCount
{
public int Original { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,3 +136,29 @@ void CryptoNative_HmacDestroy(jobject ctx)
{
ReleaseGRef(GetJNIEnv(), ctx);
}

int32_t CryptoNative_HmacOneShot(intptr_t type,
uint8_t* key,
int32_t keyLen,
uint8_t* source,
int32_t sourceLen,
uint8_t* md,
int32_t* mdSize)
{
jobject hmacCtx = CryptoNative_HmacCreate(key, keyLen, type);

if (hmacCtx == FAIL)
return FAIL;

int32_t ret = sourceLen == 0 ? SUCCESS : CryptoNative_HmacUpdate(hmacCtx, source, sourceLen);

if (ret != SUCCESS)
{
CryptoNative_HmacDestroy(hmacCtx);
return ret;
}

ret = CryptoNative_HmacFinal(hmacCtx, md, mdSize);
CryptoNative_HmacDestroy(hmacCtx);
return ret;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,10 @@ PALEXPORT int32_t CryptoNative_HmacUpdate(jobject ctx, uint8_t* data, int32_t le
PALEXPORT int32_t CryptoNative_HmacFinal(jobject ctx, uint8_t* md, int32_t* len);
PALEXPORT int32_t CryptoNative_HmacCurrent(jobject ctx, uint8_t* md, int32_t* len);
PALEXPORT void CryptoNative_HmacDestroy(jobject ctx);
PALEXPORT int32_t CryptoNative_HmacOneShot(intptr_t type,
uint8_t* key,
int32_t keyLen,
uint8_t* source,
int32_t sourceLen,
uint8_t* md,
int32_t* mdSize);
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ static const Entry s_cryptoAppleNative[] =
DllImportEntry(AppleCryptoNative_HmacUpdate)
DllImportEntry(AppleCryptoNative_HmacFinal)
DllImportEntry(AppleCryptoNative_HmacCurrent)
DllImportEntry(AppleCryptoNative_HmacOneShot)
DllImportEntry(AppleCryptoNative_SecKeychainItemCopyKeychain)
DllImportEntry(AppleCryptoNative_SecKeychainCreate)
DllImportEntry(AppleCryptoNative_SecKeychainDelete)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,32 @@ int32_t AppleCryptoNative_HmacCurrent(const HmacCtx* ctx, uint8_t* pbOutput)
{
if (ctx == NULL || pbOutput == NULL)
return 0;

HmacCtx dup = *ctx;
return AppleCryptoNative_HmacFinal(&dup, pbOutput);
}

int32_t AppleCryptoNative_HmacOneShot(PAL_HashAlgorithm algorithm,
const uint8_t* pKey,
int32_t cbKey,
const uint8_t* pBuf,
int32_t cbBuf,
uint8_t* pOutput,
int32_t cbOutput,
int32_t* pcbDigest)
{
if (pOutput == NULL || cbOutput <= 0 || pcbDigest == NULL)
return -1;

CCHmacAlgorithm ccAlgorithm = PalAlgorithmToAppleAlgorithm(algorithm);
*pcbDigest = GetHmacOutputSize(algorithm);

if (ccAlgorithm == UINT_MAX)
return -1;

if (cbOutput < *pcbDigest)
return -1;

CCHmac(ccAlgorithm, pKey, cbKey, pBuf, cbBuf, pOutput);
return 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,17 @@ Computes the HMAC of the accumulated data in ctx without resetting the state.
Returns 1 on success, 0 on error.
*/
PALEXPORT int32_t AppleCryptoNative_HmacCurrent(const HmacCtx* ctx, uint8_t* pbOutput);

/*
Computes the HMAC of data with a key in to the pOutput buffer in one step.

Return 1 on success, 0 on error, and negative values for invalid input.
*/
PALEXPORT int32_t AppleCryptoNative_HmacOneShot(PAL_HashAlgorithm algorithm,
const uint8_t* pKey,
int32_t cbKey,
const uint8_t* pBuf,
int32_t cbBuf,
uint8_t* pOutput,
int32_t cbOutput,
int32_t* pcbDigest);
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ static const Entry s_cryptoNative[] =
DllImportEntry(CryptoNative_HmacCurrent)
DllImportEntry(CryptoNative_HmacDestroy)
DllImportEntry(CryptoNative_HmacFinal)
DllImportEntry(CryptoNative_HmacOneShot)
DllImportEntry(CryptoNative_HmacReset)
DllImportEntry(CryptoNative_HmacUpdate)
DllImportEntry(CryptoNative_LookupFriendlyNameByOid)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,7 @@ const EVP_CIPHER* EVP_chacha20_poly1305(void);
REQUIRED_FUNCTION(EVP_sha512) \
REQUIRED_FUNCTION(EXTENDED_KEY_USAGE_free) \
REQUIRED_FUNCTION(GENERAL_NAMES_free) \
REQUIRED_FUNCTION(HMAC) \
LEGACY_FUNCTION(HMAC_CTX_cleanup) \
REQUIRED_FUNCTION(HMAC_CTX_copy) \
FALLBACK_FUNCTION(HMAC_CTX_free) \
Expand Down Expand Up @@ -796,6 +797,7 @@ FOR_ALL_OPENSSL_FUNCTIONS
#define EVP_sha512 EVP_sha512_ptr
#define EXTENDED_KEY_USAGE_free EXTENDED_KEY_USAGE_free_ptr
#define GENERAL_NAMES_free GENERAL_NAMES_free_ptr
#define HMAC HMAC_ptr
#define HMAC_CTX_cleanup HMAC_CTX_cleanup_ptr
#define HMAC_CTX_copy HMAC_CTX_copy_ptr
#define HMAC_CTX_free HMAC_CTX_free_ptr
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,36 @@ int32_t CryptoNative_HmacCurrent(const HMAC_CTX* ctx, uint8_t* md, int32_t* len)

return 0;
}

int32_t CryptoNative_HmacOneShot(const EVP_MD* type,
const uint8_t* key,
int32_t keySize,
const uint8_t* source,
int32_t sourceSize,
uint8_t* md,
int32_t* mdSize)
{
assert(mdSize != NULL && type != NULL && md != NULL && mdSize != NULL);
assert(keySize >= 0 && *mdSize >= 0);
assert(key != NULL || keySize == 0);
assert(source != NULL || sourceSize == 0);

uint8_t empty = 0;

if (key == NULL)
{
if (keySize != 0)
{
return -1;
}

key = &empty;
}

unsigned int unsignedSource = Int32ToUint32(sourceSize);
unsigned int unsignedSize = Int32ToUint32(*mdSize);
unsigned char* result = HMAC(type, key, keySize, source, unsignedSource, md, &unsignedSize);
*mdSize = Uint32ToInt32(unsignedSize);

return result == NULL ? 0 : 1;
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,15 @@ PALEXPORT int32_t CryptoNative_HmacFinal(HMAC_CTX* ctx, uint8_t* md, int32_t* le
* Returns 1 for success or 0 for failure.
*/
PALEXPORT int32_t CryptoNative_HmacCurrent(const HMAC_CTX* ctx, uint8_t* md, int32_t* len);

/**
* Computes the HMAC of data using a key in a single operation.
* Returns -1 on invalid input, 0 on failure, and 1 on success.
*/
PALEXPORT int32_t CryptoNative_HmacOneShot(const EVP_MD* type,
const uint8_t* key,
int32_t keySize,
const uint8_t* source,
int32_t sourceSize,
uint8_t* md,
int32_t* mdSize);
Original file line number Diff line number Diff line change
Expand Up @@ -469,8 +469,12 @@ public HMACMD5(byte[] key) { }
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
public static byte[] HashData(byte[] key, byte[] source) { throw null; }
public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
Expand All @@ -484,8 +488,12 @@ public HMACSHA1(byte[] key, bool useManagedSha1) { }
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
public static byte[] HashData(byte[] key, byte[] source) { throw null; }
public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
Expand All @@ -497,8 +505,12 @@ public HMACSHA256(byte[] key) { }
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
public static byte[] HashData(byte[] key, byte[] source) { throw null; }
public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
Expand All @@ -511,8 +523,12 @@ public HMACSHA384(byte[] key) { }
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
public static byte[] HashData(byte[] key, byte[] source) { throw null; }
public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
Expand All @@ -525,8 +541,12 @@ public HMACSHA512(byte[] key) { }
protected override void Dispose(bool disposing) { }
protected override void HashCore(byte[] rgb, int ib, int cb) { }
protected override void HashCore(System.ReadOnlySpan<byte> source) { }
public static byte[] HashData(byte[] key, byte[] source) { throw null; }
public static byte[] HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source) { throw null; }
public static int HashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination) { throw null; }
protected override byte[] HashFinal() { throw null; }
public override void Initialize() { }
public static bool TryHashData(System.ReadOnlySpan<byte> key, System.ReadOnlySpan<byte> source, System.Span<byte> destination, out int bytesWritten) { throw null; }
protected override bool TryHashFinal(System.Span<byte> destination, out int bytesWritten) { throw null; }
}
public sealed partial class IncrementalHash : System.IDisposable
Expand Down
Loading