diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs index 7e8c2460b3e001..623bc02abae1f6 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Hmac.cs @@ -2,20 +2,27 @@ // The .NET Foundation licenses this file to you under the MIT license. using System; +using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.InteropServices.Swift; using System.Security.Cryptography.Apple; +#pragma warning disable CS3016 // Arrays as attribute arguments are not CLS Compliant + internal static partial class Interop { internal static partial class AppleCrypto { [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacFree")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static partial void HmacFree(IntPtr handle); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacCreate")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static partial SafeHmacHandle HmacCreate(PAL_HashAlgorithm algorithm, ref int cbDigest); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacInit")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] private static unsafe partial int HmacInit(SafeHmacHandle ctx, byte* pbKey, int cbKey); internal static unsafe int HmacInit(SafeHmacHandle ctx, ReadOnlySpan key) @@ -30,21 +37,25 @@ internal static int HmacUpdate(SafeHmacHandle ctx, ReadOnlySpan data) => HmacUpdate(ctx, ref MemoryMarshal.GetReference(data), data.Length); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacUpdate")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] private static partial int HmacUpdate(SafeHmacHandle ctx, ref byte pbData, int cbData); internal static int HmacFinal(SafeHmacHandle ctx, ReadOnlySpan output) => HmacFinal(ctx, ref MemoryMarshal.GetReference(output), output.Length); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacFinal")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] private static partial int HmacFinal(SafeHmacHandle ctx, ref byte pbOutput, int cbOutput); internal static int HmacCurrent(SafeHmacHandle ctx, ReadOnlySpan output) => HmacCurrent(ctx, ref MemoryMarshal.GetReference(output), output.Length); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacCurrent")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] private static partial int HmacCurrent(SafeHmacHandle ctx, ref byte pbOutput, int cbOutput); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacOneShot")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static unsafe partial int HmacOneShot( PAL_HashAlgorithm algorithm, byte* pKey, @@ -56,6 +67,7 @@ internal static unsafe partial int HmacOneShot( int* cbDigest); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_HmacClone")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static partial SafeHmacHandle HmacClone(SafeHmacHandle ctx); } } diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt index 2bc2b9be6056dc..66f67dcb84ca4d 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt @@ -7,7 +7,6 @@ append_extra_cryptography_apple_libs(NATIVE_LIBS_EXTRA) set(NATIVECRYPTO_SOURCES pal_ecc.c - pal_hmac.c pal_keyagree.c pal_keyderivation.c pal_random.c diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c b/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c index 1958ac1ca51f56..f8b64791ec365c 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/entrypoints.c @@ -6,7 +6,6 @@ // Include System.Security.Cryptography.Native.Apple headers #include "pal_digest.h" #include "pal_ecc.h" -#include "pal_hmac.h" #include "pal_keyagree.h" #include "pal_keychain_macos.h" #include "pal_keyderivation.h" diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_digest.h b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_digest.h index d02a36e34f04c7..a2d9d9e7cf585a 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_digest.h +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_digest.h @@ -20,4 +20,3 @@ enum }; typedef uint32_t PAL_HashAlgorithm; -typedef struct digest_ctx_st DigestCtx; diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_hmac.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_hmac.c deleted file mode 100644 index be951aa2d667b9..00000000000000 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_hmac.c +++ /dev/null @@ -1,163 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#include "pal_hmac.h" - -struct hmac_ctx_st -{ - CCHmacAlgorithm appleAlgId; - CCHmacContext hmac; -}; - -void AppleCryptoNative_HmacFree(HmacCtx* pHmac) -{ - if (pHmac != NULL) - { - free(pHmac); - } -} - -static CCHmacAlgorithm PalAlgorithmToAppleAlgorithm(PAL_HashAlgorithm algorithm) -{ - switch (algorithm) - { - case PAL_MD5: - return kCCHmacAlgMD5; - case PAL_SHA1: - return kCCHmacAlgSHA1; - case PAL_SHA256: - return kCCHmacAlgSHA256; - case PAL_SHA384: - return kCCHmacAlgSHA384; - case PAL_SHA512: - return kCCHmacAlgSHA512; - default: - // 0 is a defined value (SHA1) so "unknown" has to be something else - return UINT_MAX; - } -} - -static int32_t GetHmacOutputSize(PAL_HashAlgorithm algorithm) -{ - switch (algorithm) - { - case PAL_MD5: - return CC_MD5_DIGEST_LENGTH; - case PAL_SHA1: - return CC_SHA1_DIGEST_LENGTH; - case PAL_SHA256: - return CC_SHA256_DIGEST_LENGTH; - case PAL_SHA384: - return CC_SHA384_DIGEST_LENGTH; - case PAL_SHA512: - return CC_SHA512_DIGEST_LENGTH; - default: - return -1; - } -} - -HmacCtx* AppleCryptoNative_HmacCreate(PAL_HashAlgorithm algorithm, int32_t* pcbHmac) -{ - if (pcbHmac == NULL) - return NULL; - - CCHmacAlgorithm appleAlgId = PalAlgorithmToAppleAlgorithm(algorithm); - - if (appleAlgId == UINT_MAX) - { - *pcbHmac = -1; - return NULL; - } - - HmacCtx* hmacCtx = (HmacCtx*)malloc(sizeof(HmacCtx)); - if (hmacCtx == NULL) - return hmacCtx; - - hmacCtx->appleAlgId = appleAlgId; - *pcbHmac = GetHmacOutputSize(algorithm); - return hmacCtx; -} - -int32_t AppleCryptoNative_HmacInit(HmacCtx* ctx, uint8_t* pbKey, int32_t cbKey) -{ - if (ctx == NULL || cbKey < 0) - return 0; - if (cbKey != 0 && pbKey == NULL) - return 0; - - // No return value - CCHmacInit(&ctx->hmac, ctx->appleAlgId, pbKey, (size_t)cbKey); - return 1; -} - -int32_t AppleCryptoNative_HmacUpdate(HmacCtx* ctx, uint8_t* pbData, int32_t cbData) -{ - if (cbData == 0) - return 1; - if (ctx == NULL || pbData == NULL) - return 0; - - // No return value - CCHmacUpdate(&ctx->hmac, pbData, (size_t)cbData); - return 1; -} - -int32_t AppleCryptoNative_HmacFinal(HmacCtx* ctx, uint8_t* pbOutput) -{ - if (ctx == NULL || pbOutput == NULL) - return 0; - - // No return value - CCHmacFinal(&ctx->hmac, pbOutput); - return 1; -} - -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, (size_t)cbKey, pBuf, (size_t)cbBuf, pOutput); - return 1; -} - -HmacCtx* AppleCryptoNative_HmacClone(const HmacCtx* ctx) -{ - if (ctx == NULL) - return NULL; - - HmacCtx* cloneCtx = (HmacCtx*)malloc(sizeof(HmacCtx)); // Must use same allocator as AppleCryptoNative_HmacCreate - - if (cloneCtx == NULL) - { - return NULL; - } - - memcpy(cloneCtx, ctx, sizeof(HmacCtx)); - return cloneCtx; -} diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_hmac.h b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_hmac.h deleted file mode 100644 index 83094c6acc6002..00000000000000 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_hmac.h +++ /dev/null @@ -1,74 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -#pragma once - -#include "pal_digest.h" -#include "pal_types.h" -#include "pal_compiler.h" - -typedef struct hmac_ctx_st HmacCtx; - -/* -Free a HmacCtx created by AppleCryptoNative_HmacCreate -*/ -PALEXPORT void AppleCryptoNative_HmacFree(HmacCtx* pHmac); - -/* -Create an HmacCtx for the specified algorithm, receiving the hash output size in pcbHmac. - -If *pcbHmac is negative the algorithm is unknown or not supported. If a non-NULL value is returned -it should be freed via AppleCryptoNative_HmacFree regardless of a negative pbHmac value. - -Returns NULL on error, an unkeyed HmacCtx otherwise. -*/ -PALEXPORT HmacCtx* AppleCryptoNative_HmacCreate(PAL_HashAlgorithm algorithm, int32_t* pcbHmac); - -/* -Initialize an HMAC to the correct key and start state. - -Returns 1 on success, 0 on error. -*/ -PALEXPORT int32_t AppleCryptoNative_HmacInit(HmacCtx* ctx, uint8_t* pbKey, int32_t cbKey); - -/* -Add data into the HMAC - -Returns 1 on success, 0 on error. -*/ -PALEXPORT int32_t AppleCryptoNative_HmacUpdate(HmacCtx* ctx, uint8_t* pbData, int32_t cbData); - -/* -Complete the HMAC and copy the result into pbOutput. - -Returns 1 on success, 0 on error. -*/ -PALEXPORT int32_t AppleCryptoNative_HmacFinal(HmacCtx* ctx, uint8_t* pbOutput); - -/* -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); - -/* -Clones the current HMAC context. - -Returns a handle to the new HMAC context, or NULL if the clone failed. -*/ -PALEXPORT HmacCtx* AppleCryptoNative_HmacClone(const HmacCtx* ctx); diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.h b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.h index bb81f0bf8b617b..ef41cce4b1e82c 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.h +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.h @@ -24,3 +24,13 @@ EXTERN_C void* AppleCryptoNative_DigestCurrent; EXTERN_C void* AppleCryptoNative_DigestOneShot; EXTERN_C void* AppleCryptoNative_DigestReset; EXTERN_C void* AppleCryptoNative_DigestClone; + +EXTERN_C void* AppleCryptoNative_HmacFree; +EXTERN_C void* AppleCryptoNative_HmacCreate; +EXTERN_C void* AppleCryptoNative_HmacInit; +EXTERN_C void* AppleCryptoNative_HmacUpdate; +EXTERN_C void* AppleCryptoNative_HmacFinal; +EXTERN_C void* AppleCryptoNative_HmacCurrent; +EXTERN_C void* AppleCryptoNative_HmacOneShot; +EXTERN_C void* AppleCryptoNative_HmacClone; + diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift index 02b21a2160b54c..5c8c7c18c0f86b 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_swiftbindings.swift @@ -11,6 +11,20 @@ final class HashBox { } } +final class HmacBox { + let algorithm: PAL_HashAlgorithm + let length: Int + var key: SymmetricKey? + var hmac: Any? + + init(_ algorithm: PAL_HashAlgorithm, length: Int) { + self.algorithm = algorithm + self.length = length + self.hmac = nil + self.key = nil + } +} + protocol NonceProtocol { init(data: D) throws where D : DataProtocol } @@ -536,3 +550,289 @@ public func AppleCryptoNative_DigestCurrent(ctx: UnsafeMutableRawPointer?, pOutp return 1 } + +@_silgen_name("AppleCryptoNative_HmacCreate") +public func AppleCryptoNative_HmacCreate(algorithm: Int32, pcbHmac: UnsafeMutablePointer?) -> UnsafeMutableRawPointer? { + guard let pcbHmac, let hashAlgorithm = PAL_HashAlgorithm(rawValue: algorithm) else { + return nil + } + + switch hashAlgorithm { + case .md5: + pcbHmac.pointee = Int32(Insecure.MD5.byteCount) + let box = HmacBox(hashAlgorithm, length: Insecure.MD5.byteCount) + return Unmanaged.passRetained(box).toOpaque() + case .sha1: + let box = HmacBox(hashAlgorithm, length: Insecure.SHA1.byteCount) + pcbHmac.pointee = Int32(Insecure.SHA1.byteCount) + return Unmanaged.passRetained(box).toOpaque() + case .sha256: + let box = HmacBox(hashAlgorithm, length: SHA256.byteCount) + pcbHmac.pointee = Int32(SHA256.byteCount) + return Unmanaged.passRetained(box).toOpaque() + case .sha384: + let box = HmacBox(hashAlgorithm, length: SHA384.byteCount) + pcbHmac.pointee = Int32(SHA384.byteCount) + return Unmanaged.passRetained(box).toOpaque() + case .sha512: + let box = HmacBox(hashAlgorithm, length: SHA512.byteCount) + pcbHmac.pointee = Int32(SHA512.byteCount) + return Unmanaged.passRetained(box).toOpaque() + default: + pcbHmac.pointee = 0 + return nil + } +} + +@_silgen_name("AppleCryptoNative_HmacInit") +public func AppleCryptoNative_HmacInit(ctx: UnsafeMutableRawPointer?, pbKey: UnsafeMutableRawPointer?, cbKey: Int32) -> Int32 { + guard let ctx, let pbKey, cbKey >= 0 else { + return 0 + } + + let keyData = Data(bytesNoCopy: pbKey, count: Int(cbKey), deallocator: .none) + let key = SymmetricKey(data: keyData) + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + return HmacReset(box: box, key: key) +} + +@_silgen_name("AppleCryptoNative_HmacUpdate") +public func AppleCryptoNative_HmacUpdate(ctx: UnsafeMutableRawPointer?, pbData: UnsafeMutableRawPointer?, cbData: Int32) -> Int32 { + guard let ctx, let pbData, cbData >= 0 else { + return 0 + } + + if cbData == 0 { + return 1 + } + + let data = Data(bytesNoCopy: pbData, count: Int(cbData), deallocator: .none) + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + + switch box.algorithm { + case .md5: + var hmac = (box.hmac as! HMAC) + hmac.update(data: data) + box.hmac = hmac + return 1 + case .sha1: + var hmac = (box.hmac as! HMAC) + hmac.update(data: data) + box.hmac = hmac + return 1 + case .sha256: + var hmac = (box.hmac as! HMAC) + hmac.update(data: data) + box.hmac = hmac + return 1 + case .sha384: + var hmac = (box.hmac as! HMAC) + hmac.update(data: data) + box.hmac = hmac + return 1 + case .sha512: + var hmac = (box.hmac as! HMAC) + hmac.update(data: data) + box.hmac = hmac + return 1 + default: + return 0 + } +} + +@_silgen_name("AppleCryptoNative_HmacFinal") +public func AppleCryptoNative_HmacFinal(ctx: UnsafeMutableRawPointer?, pOutput: UnsafeMutablePointer?) -> Int32 { + guard let ctx, let pOutput else { + return -1 + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + + guard let key = box.key else { + return -2 + } + + let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: box.length) + let copied: Bool + + switch box.algorithm { + case .md5: + let mac = (box.hmac as! HMAC).finalize() + copied = mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } + break + case .sha1: + let mac = (box.hmac as! HMAC).finalize() + copied = mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } + break + case .sha256: + let mac = (box.hmac as! HMAC).finalize() + copied = mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } + break + case .sha384: + let mac = (box.hmac as! HMAC).finalize() + copied = mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } + break + case .sha512: + let mac = (box.hmac as! HMAC).finalize() + copied = mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } + break + default: + return 0 + } + + if !copied { + return 0 + } + + return HmacReset(box: box, key: key) +} + +@_silgen_name("AppleCryptoNative_HmacCurrent") +public func AppleCryptoNative_HmacCurrent(ctx: UnsafeMutableRawPointer?, pOutput: UnsafeMutablePointer?) -> Int32 { + guard let ctx, let pOutput else { + return -1 + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: box.length) + + switch box.algorithm { + case .md5: + let hmac = (box.hmac as! HMAC) + let mac = hmac.finalize() + return mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } ? 1 : 0 + case .sha1: + let hmac = (box.hmac as! HMAC) + let mac = hmac.finalize() + return mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } ? 1 : 0 + case .sha256: + let hmac = (box.hmac as! HMAC) + let mac = hmac.finalize() + return mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } ? 1 : 0 + case .sha384: + let hmac = (box.hmac as! HMAC) + let mac = hmac.finalize() + return mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } ? 1 : 0 + case .sha512: + let hmac = (box.hmac as! HMAC) + let mac = hmac.finalize() + return mac.withUnsafeBytes { $0.copyBytes(to: destination) == $0.count } ? 1 : 0 + default: + return 0 + } +} + +@_silgen_name("AppleCryptoNative_HmacFree") +public func AppleCryptoNative_HmacFree(ctx: UnsafeMutableRawPointer?) { + if let ctx { + Unmanaged.fromOpaque(ctx).release() + } +} + +@_silgen_name("AppleCryptoNative_HmacClone") +public func AppleCryptoNative_HmacClone(ctx: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? { + guard let ctx else { + return nil + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + let cloneBox = HmacBox(box.algorithm, length: box.length) + cloneBox.key = box.key + cloneBox.hmac = box.hmac + return Unmanaged.passRetained(cloneBox).toOpaque() +} + +@_silgen_name("AppleCryptoNative_HmacOneShot") +public func AppleCryptoNative_HmacOneShot( + algorithm: Int32, + pbKey: UnsafeMutableRawPointer?, + cbKey: Int32, + pbBuf: UnsafeMutableRawPointer?, + cbBuf: Int32, + pOutput: UnsafeMutablePointer?, + cbOutput: Int32, + pcbDigest: UnsafeMutablePointer? + ) -> Int32 { + guard let pcbDigest, let pOutput, cbKey >= 0, cbBuf >= 0 else { + return -1 + } + + guard let hashAlgorithm = PAL_HashAlgorithm(rawValue: algorithm) else { + return -1 + } + + let data: Data + let keyData: Data + + if let pbBuf, cbBuf > 0 { + data = Data(bytesNoCopy: pbBuf, count: Int(cbBuf), deallocator: .none) + } else { + data = Data() + } + + if let pbKey, cbKey > 0 { + keyData = Data(bytesNoCopy: pbKey, count: Int(cbKey), deallocator: .none) + } else { + keyData = Data() + } + + let key = SymmetricKey(data: keyData) + let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: Int(cbOutput)) + + switch hashAlgorithm { + case .md5: + pcbDigest.pointee = Int32(Insecure.MD5.byteCount) + return HMAC.authenticationCode(for: data, using: key).withUnsafeBytes { mac in + return mac.copyBytes(to: destination) == mac.count ? 1 : -1 + } + case .sha1: + pcbDigest.pointee = Int32(Insecure.SHA1.byteCount) + return HMAC.authenticationCode(for: data, using: key).withUnsafeBytes { mac in + return mac.copyBytes(to: destination) == mac.count ? 1 : -1 + } + case .sha256: + pcbDigest.pointee = Int32(SHA256.byteCount) + return HMAC.authenticationCode(for: data, using: key).withUnsafeBytes { mac in + return mac.copyBytes(to: destination) == mac.count ? 1 : -1 + } + case .sha384: + pcbDigest.pointee = Int32(SHA384.byteCount) + return HMAC.authenticationCode(for: data, using: key).withUnsafeBytes { mac in + return mac.copyBytes(to: destination) == mac.count ? 1 : -1 + } + case .sha512: + pcbDigest.pointee = Int32(SHA512.byteCount) + return HMAC.authenticationCode(for: data, using: key).withUnsafeBytes { mac in + return mac.copyBytes(to: destination) == mac.count ? 1 : -1 + } + default: + return -1 + } +} + +private func HmacReset(box: HmacBox, key: SymmetricKey) -> Int32 { + switch box.algorithm { + case .md5: + box.hmac = HMAC(key: key) + box.key = key + return 1 + case .sha1: + box.hmac = HMAC(key: key) + box.key = key + return 1 + case .sha256: + box.hmac = HMAC(key: key) + box.key = key + return 1 + case .sha384: + box.hmac = HMAC(key: key) + box.key = key + return 1 + case .sha512: + box.hmac = HMAC(key: key) + box.key = key + return 1 + default: + return 0 + } +}