diff --git a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs index 5f3e88a1741860..64ccd6086146b9 100644 --- a/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs +++ b/src/libraries/Common/src/Interop/OSX/System.Security.Cryptography.Native.Apple/Interop.Digest.cs @@ -2,44 +2,56 @@ // 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_DigestFree")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static partial void DigestFree(IntPtr handle); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestCreate")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static partial SafeDigestCtxHandle DigestCreate(PAL_HashAlgorithm algorithm, out int cbDigest); internal static int DigestUpdate(SafeDigestCtxHandle ctx, ReadOnlySpan data) => DigestUpdate(ctx, ref MemoryMarshal.GetReference(data), data.Length); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestUpdate")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] private static partial int DigestUpdate(SafeDigestCtxHandle ctx, ref byte pbData, int cbData); internal static int DigestFinal(SafeDigestCtxHandle ctx, Span output) => DigestFinal(ctx, ref MemoryMarshal.GetReference(output), output.Length); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestFinal")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] private static partial int DigestFinal(SafeDigestCtxHandle ctx, ref byte pbOutput, int cbOutput); internal static int DigestCurrent(SafeDigestCtxHandle ctx, Span output) => DigestCurrent(ctx, ref MemoryMarshal.GetReference(output), output.Length); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestCurrent")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] private static partial int DigestCurrent(SafeDigestCtxHandle ctx, ref byte pbOutput, int cbOutput); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestOneShot")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static unsafe partial int DigestOneShot(PAL_HashAlgorithm algorithm, byte* pbData, int cbData, byte* pbOutput, int cbOutput, int* cbDigest); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestReset")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static partial int DigestReset(SafeDigestCtxHandle ctx); [LibraryImport(Libraries.AppleCryptoNative, EntryPoint = "AppleCryptoNative_DigestClone")] + [UnmanagedCallConv(CallConvs = [ typeof(CallConvSwift) ])] internal static partial SafeDigestCtxHandle DigestClone(SafeDigestCtxHandle 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 d3ef5a4bdd4ff8..2bc2b9be6056dc 100644 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt +++ b/src/native/libs/System.Security.Cryptography.Native.Apple/CMakeLists.txt @@ -6,7 +6,6 @@ set(NATIVE_LIBS_EXTRA) append_extra_cryptography_apple_libs(NATIVE_LIBS_EXTRA) set(NATIVECRYPTO_SOURCES - pal_digest.c pal_ecc.c pal_hmac.c pal_keyagree.c diff --git a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_digest.c b/src/native/libs/System.Security.Cryptography.Native.Apple/pal_digest.c deleted file mode 100644 index 4736f25360c421..00000000000000 --- a/src/native/libs/System.Security.Cryptography.Native.Apple/pal_digest.c +++ /dev/null @@ -1,252 +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_digest.h" - -#include -#include -#include - -struct digest_ctx_st -{ - PAL_HashAlgorithm algorithm; - // This 32-bit field is required for alignment, - // but it's also handy for remembering how big the final buffer is. - int32_t cbDigest; - union { - CC_MD5_CTX md5; - CC_SHA1_CTX sha1; - CC_SHA256_CTX sha256; - CC_SHA512_CTX sha384; - CC_SHA512_CTX sha512; - } d; -}; - -void AppleCryptoNative_DigestFree(DigestCtx* pDigest) -{ - if (pDigest != NULL) - { - free(pDigest); - } -} - -DigestCtx* AppleCryptoNative_DigestCreate(PAL_HashAlgorithm algorithm, int32_t* pcbDigest) -{ - if (pcbDigest == NULL) - return NULL; - - DigestCtx* digestCtx = (DigestCtx*)malloc(sizeof(DigestCtx)); - if (digestCtx == NULL) - return NULL; - - digestCtx->algorithm = algorithm; - - switch (algorithm) - { - case PAL_MD5: - *pcbDigest = CC_MD5_DIGEST_LENGTH; -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - CC_MD5_Init(&digestCtx->d.md5); -#pragma clang diagnostic pop - break; - case PAL_SHA1: - *pcbDigest = CC_SHA1_DIGEST_LENGTH; - CC_SHA1_Init(&digestCtx->d.sha1); - break; - case PAL_SHA256: - *pcbDigest = CC_SHA256_DIGEST_LENGTH; - CC_SHA256_Init(&digestCtx->d.sha256); - break; - case PAL_SHA384: - *pcbDigest = CC_SHA384_DIGEST_LENGTH; - CC_SHA384_Init(&digestCtx->d.sha384); - break; - case PAL_SHA512: - *pcbDigest = CC_SHA512_DIGEST_LENGTH; - CC_SHA512_Init(&digestCtx->d.sha512); - break; - default: - *pcbDigest = -1; - free(digestCtx); - return NULL; - } - - digestCtx->cbDigest = *pcbDigest; - return digestCtx; -} - -int32_t AppleCryptoNative_DigestUpdate(DigestCtx* ctx, uint8_t* pBuf, int32_t cbBuf) -{ - if (cbBuf == 0) - return 1; - if (ctx == NULL || pBuf == NULL) - return -1; - - CC_LONG bufSize = (CC_LONG)cbBuf; - - switch (ctx->algorithm) - { - case PAL_MD5: -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - return CC_MD5_Update(&ctx->d.md5, pBuf, bufSize); -#pragma clang diagnostic pop - case PAL_SHA1: - return CC_SHA1_Update(&ctx->d.sha1, pBuf, bufSize); - case PAL_SHA256: - return CC_SHA256_Update(&ctx->d.sha256, pBuf, bufSize); - case PAL_SHA384: - return CC_SHA384_Update(&ctx->d.sha384, pBuf, bufSize); - case PAL_SHA512: - return CC_SHA512_Update(&ctx->d.sha512, pBuf, bufSize); - default: - return -1; - } -} - -int32_t AppleCryptoNative_DigestFinal(DigestCtx* ctx, uint8_t* pOutput, int32_t cbOutput) -{ - if (ctx == NULL || pOutput == NULL || cbOutput < ctx->cbDigest) - return -1; - - int32_t ret = 0; - - switch (ctx->algorithm) - { - case PAL_MD5: -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - ret = CC_MD5_Final(pOutput, &ctx->d.md5); -#pragma clang diagnostic pop - break; - case PAL_SHA1: - ret = CC_SHA1_Final(pOutput, &ctx->d.sha1); - break; - case PAL_SHA256: - ret = CC_SHA256_Final(pOutput, &ctx->d.sha256); - break; - case PAL_SHA384: - ret = CC_SHA384_Final(pOutput, &ctx->d.sha384); - break; - case PAL_SHA512: - ret = CC_SHA512_Final(pOutput, &ctx->d.sha512); - break; - default: - ret = -1; - break; - } - - if (ret != 1) - { - return ret; - } - - return AppleCryptoNative_DigestReset(ctx); -} - -int32_t AppleCryptoNative_DigestCurrent(const DigestCtx* ctx, uint8_t* pOutput, int32_t cbOutput) -{ - if (ctx == NULL || pOutput == NULL || cbOutput < ctx->cbDigest) - return -1; - - DigestCtx dup = *ctx; - return AppleCryptoNative_DigestFinal(&dup, pOutput, cbOutput); -} - -int32_t AppleCryptoNative_DigestOneShot(PAL_HashAlgorithm algorithm, uint8_t* pBuf, int32_t cbBuf, uint8_t* pOutput, int32_t cbOutput, int32_t* pcbDigest) -{ - if (pOutput == NULL || cbOutput <= 0 || pcbDigest == NULL) - return -1; - - switch (algorithm) - { - case PAL_SHA1: - *pcbDigest = CC_SHA1_DIGEST_LENGTH; - if (cbOutput < CC_SHA1_DIGEST_LENGTH) - { - return -1; - } - CC_SHA1(pBuf, (CC_LONG)cbBuf, pOutput); - return 1; - case PAL_SHA256: - *pcbDigest = CC_SHA256_DIGEST_LENGTH; - if (cbOutput < CC_SHA256_DIGEST_LENGTH) - { - return -1; - } - CC_SHA256(pBuf, (CC_LONG)cbBuf, pOutput); - return 1; - case PAL_SHA384: - *pcbDigest = CC_SHA384_DIGEST_LENGTH; - if (cbOutput < CC_SHA384_DIGEST_LENGTH) - { - return -1; - } - CC_SHA384(pBuf, (CC_LONG)cbBuf, pOutput); - return 1; - case PAL_SHA512: - *pcbDigest = CC_SHA512_DIGEST_LENGTH; - if (cbOutput < CC_SHA512_DIGEST_LENGTH) - { - return -1; - } - CC_SHA512(pBuf, (CC_LONG)cbBuf, pOutput); - return 1; - case PAL_MD5: - *pcbDigest = CC_MD5_DIGEST_LENGTH; - if (cbOutput < CC_MD5_DIGEST_LENGTH) - { - return -1; - } -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - CC_MD5(pBuf, (CC_LONG)cbBuf, pOutput); -#pragma clang diagnostic pop - return 1; - default: - return -1; - } -} - -int32_t AppleCryptoNative_DigestReset(DigestCtx* ctx) -{ - if (ctx == NULL) - return -1; - - switch (ctx->algorithm) - { - case PAL_MD5: -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - return CC_MD5_Init(&ctx->d.md5); -#pragma clang diagnostic pop - case PAL_SHA1: - return CC_SHA1_Init(&ctx->d.sha1); - case PAL_SHA256: - return CC_SHA256_Init(&ctx->d.sha256); - case PAL_SHA384: - return CC_SHA384_Init(&ctx->d.sha384); - case PAL_SHA512: - return CC_SHA512_Init(&ctx->d.sha512); - default: - assert(false); - return -2; - } -} - -DigestCtx* AppleCryptoNative_DigestClone(const DigestCtx* ctx) -{ - if (ctx == NULL) - return NULL; - - DigestCtx* cloneCtx = (DigestCtx*)malloc(sizeof(DigestCtx)); // Must use same allocator as AppleCryptoNative_DigestCreate - - if (cloneCtx == NULL) - { - return NULL; - } - - memcpy(cloneCtx, ctx, sizeof(DigestCtx)); - return cloneCtx; -} 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 8e1c9fcdf3faf0..d02a36e34f04c7 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 @@ -21,60 +21,3 @@ enum typedef uint32_t PAL_HashAlgorithm; typedef struct digest_ctx_st DigestCtx; - -/* -Free the resources held by a DigestCtx -*/ -PALEXPORT void AppleCryptoNative_DigestFree(DigestCtx* pDigest); - -/* -Create a digest handle for the specified algorithm. - -Returns NULL when the algorithm is unknown, or pcbDigest is NULL; otherwise returns a pointer -to a digest context suitable for calling DigestUpdate and DigestFinal on and sets pcbDigest to -the size of the digest output. -*/ -PALEXPORT DigestCtx* AppleCryptoNative_DigestCreate(PAL_HashAlgorithm algorithm, int32_t* pcbDigest); - -/* -Apply cbBuf bytes of data from pBuf to the ongoing digest represented in ctx. - -Returns 1 on success, 0 on failure, any other value on invalid inputs/state. -*/ -PALEXPORT int32_t AppleCryptoNative_DigestUpdate(DigestCtx* ctx, uint8_t* pBuf, int32_t cbBuf); - -/* -Complete the digest in ctx, copying the results to pOutput, and reset ctx for a new digest. - -Returns 1 on success, 0 on failure, any other value on invalid inputs/state. -*/ -PALEXPORT int32_t AppleCryptoNative_DigestFinal(DigestCtx* ctx, uint8_t* pOutput, int32_t cbOutput); - -/* -Get the digest of the data already loaded into ctx, without resetting ctx. - -Returns 1 on success, 0 on failure, any other value on invalid inputs/state. -*/ -PALEXPORT int32_t AppleCryptoNative_DigestCurrent(const DigestCtx* ctx, uint8_t* pOutput, int32_t cbOutput); - -/* -Combines DigestCreate, DigestUpdate, and DigestFinal in to a single operation. - -Returns 1 on success, 0 on failure, any other value on invalid inputs/state. -*/ -PALEXPORT int32_t AppleCryptoNative_DigestOneShot(PAL_HashAlgorithm algorithm, uint8_t* pBuf, int32_t cbBuf, uint8_t* pOutput, int32_t cbOutput, int32_t* pcbDigest); - - -/* -Re-initializes a digest context to an initial state. - -Returns 1 on success, 0 on failure, any other value on invalid inputs/state. -*/ -PALEXPORT int32_t AppleCryptoNative_DigestReset(DigestCtx* ctx); - -/* -Clones the current digest context. - -Returns a handle to the new digest context, or NULL if the clone failed. -*/ -PALEXPORT DigestCtx* AppleCryptoNative_DigestClone(const DigestCtx* 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 40f9ac92b8db78..bb81f0bf8b617b 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 @@ -15,3 +15,12 @@ EXTERN_C void* AppleCryptoNative_IsAuthenticationFailure; EXTERN_C void* AppleCryptoNative_HKDFDeriveKey; EXTERN_C void* AppleCryptoNative_HKDFExpand; EXTERN_C void* AppleCryptoNative_HKDFExtract; + +EXTERN_C void* AppleCryptoNative_DigestFree; +EXTERN_C void* AppleCryptoNative_DigestCreate; +EXTERN_C void* AppleCryptoNative_DigestUpdate; +EXTERN_C void* AppleCryptoNative_DigestFinal; +EXTERN_C void* AppleCryptoNative_DigestCurrent; +EXTERN_C void* AppleCryptoNative_DigestOneShot; +EXTERN_C void* AppleCryptoNative_DigestReset; +EXTERN_C void* AppleCryptoNative_DigestClone; 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 0915b647c33f71..189a63f3638388 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 @@ -4,6 +4,14 @@ import CryptoKit import Foundation +@available(iOS 13, tvOS 13, *) +final class HashBox { + var value: any HashFunction + init(_ value: any HashFunction) { + self.value = value + } +} + protocol NonceProtocol { init(data: D) throws where D : DataProtocol } @@ -350,3 +358,204 @@ public func AppleCryptoNative_HKDFDeriveKey( return Int32(keyBytes.copyBytes(to: destination)) } } + +@_silgen_name("AppleCryptoNative_DigestOneShot") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestOneShot( + algorithm: Int32, + pbData: UnsafeMutableRawPointer?, + cbData: Int32, + pbOutput: UnsafeMutablePointer?, + cbOutput: Int32, + cbDigest: UnsafeMutablePointer?) -> Int32 { + + guard let cbDigest, let pbOutput, let hashAlgorithm = PAL_HashAlgorithm(rawValue: algorithm) else { + return -1 + } + + let data: Data + + if let ptr = pbData, cbData > 0 { + data = Data(bytesNoCopy: ptr, count: Int(cbData), deallocator: .none) + } else { + data = Data() + } + + let destination = UnsafeMutableRawBufferPointer(start: pbOutput, count: Int(cbOutput)) + + switch hashAlgorithm { + case .md5: + let written = Insecure.MD5.hash(data: data).withUnsafeBytes { digest in return digest.copyBytes(to: destination) } + cbDigest.pointee = Int32(Insecure.MD5.byteCount) + return written != Insecure.MD5.byteCount ? -1 : 1 + case .sha1: + let written = Insecure.SHA1.hash(data: data).withUnsafeBytes { digest in return digest.copyBytes(to: destination) } + cbDigest.pointee = Int32(Insecure.SHA1.byteCount) + return written != Insecure.SHA1.byteCount ? -1 : 1 + case .sha256: + let written = SHA256.hash(data: data).withUnsafeBytes { digest in return digest.copyBytes(to: destination) } + cbDigest.pointee = Int32(SHA256.byteCount) + return written != SHA256.byteCount ? -1 : 1 + case .sha384: + let written = SHA384.hash(data: data).withUnsafeBytes { digest in return digest.copyBytes(to: destination) } + cbDigest.pointee = Int32(SHA384.byteCount) + return written != SHA384.byteCount ? -1 : 1 + case .sha512: + let written = SHA512.hash(data: data).withUnsafeBytes { digest in return digest.copyBytes(to: destination) } + cbDigest.pointee = Int32(SHA512.byteCount) + return written != SHA512.byteCount ? -1 : 1 + default: + cbDigest.pointee = 0 + return -1 + } +} + +@_silgen_name("AppleCryptoNative_DigestCreate") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestCreate(algorithm: Int32, pcbDigest: UnsafeMutablePointer?) -> UnsafeMutableRawPointer? { + guard let pcbDigest, let hashAlgorithm = PAL_HashAlgorithm(rawValue: algorithm) else { + return nil + } + + switch hashAlgorithm { + case .md5: + pcbDigest.pointee = Int32(Insecure.MD5.byteCount) + let box = HashBox(Insecure.MD5()) + return Unmanaged.passRetained(box).toOpaque() + case .sha1: + pcbDigest.pointee = Int32(Insecure.SHA1.byteCount) + let box = HashBox(Insecure.SHA1()) + return Unmanaged.passRetained(box).toOpaque() + case .sha256: + pcbDigest.pointee = Int32(SHA256.byteCount) + let box = HashBox(SHA256()) + return Unmanaged.passRetained(box).toOpaque() + case .sha384: + pcbDigest.pointee = Int32(SHA384.byteCount) + let box = HashBox(SHA384()) + return Unmanaged.passRetained(box).toOpaque() + case .sha512: + pcbDigest.pointee = Int32(SHA512.byteCount) + let box = HashBox(SHA512()) + return Unmanaged.passRetained(box).toOpaque() + default: + pcbDigest.pointee = 0 + return nil + } +} + +@_silgen_name("AppleCryptoNative_DigestUpdate") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestUpdate(ctx: UnsafeMutableRawPointer?, pBuf: UnsafeMutableRawPointer?, cBuf: Int32) -> Int32 { + if cBuf == 0 { + return 1 + } + + guard let ctx, let pBuf, cBuf >= 0 else { + return -1 + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + let source = Data(bytesNoCopy: pBuf, count: Int(cBuf), deallocator: Data.Deallocator.none) + var hash = box.value + hash.update(data: source) + box.value = hash + return 1 +} + +@_silgen_name("AppleCryptoNative_DigestReset") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestReset(ctx: UnsafeMutableRawPointer?) -> Int32 { + guard let ctx else { + return -1 + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + + switch box.value { + case is Insecure.MD5: + box.value = Insecure.MD5() + return 1 + case is Insecure.SHA1: + box.value = Insecure.SHA1() + return 1 + case is SHA256: + box.value = SHA256() + return 1 + case is SHA384: + box.value = SHA384() + return 1 + case is SHA512: + box.value = SHA512() + return 1 + default: + return -2 + } +} + +@_silgen_name("AppleCryptoNative_DigestFinal") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestFinal(ctx: UnsafeMutableRawPointer?, pOutput: UnsafeMutablePointer?, cbOutput: Int32) -> Int32 { + guard let ctx, let pOutput else { + return -1 + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: Int(cbOutput)) + + let hash = box.value.finalize() + let copied = hash.withUnsafeBytes { digest in + return digest.copyBytes(to: destination) == digest.count + } + + if (!copied) { + return -1 + } + + return AppleCryptoNative_DigestReset(ctx: ctx) +} + +@_silgen_name("AppleCryptoNative_DigestFree") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestFree(ptr: UnsafeMutableRawPointer?) { + if let ptr { + Unmanaged.fromOpaque(ptr).release() + } +} + +@_silgen_name("AppleCryptoNative_DigestClone") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestClone(ctx: UnsafeMutableRawPointer?) -> UnsafeMutableRawPointer? { + guard let ctx else { + return nil + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + let digest = box.value + let clone = digest + let cloneBox = HashBox(clone) + return Unmanaged.passRetained(cloneBox).toOpaque() +} + +@_silgen_name("AppleCryptoNative_DigestCurrent") +@available(iOS 13, tvOS 13, *) +public func AppleCryptoNative_DigestCurrent(ctx: UnsafeMutableRawPointer?, pOutput: UnsafeMutablePointer?, cbOutput: Int32) -> Int32 { + guard let ctx, let pOutput else { + return -1 + } + + let box = Unmanaged.fromOpaque(ctx).takeUnretainedValue() + let destination = UnsafeMutableRawBufferPointer(start: pOutput, count: Int(cbOutput)) + let unboxed = box.value + let clone = unboxed + let hash = clone.finalize() + let copied = hash.withUnsafeBytes { digest in + return digest.copyBytes(to: destination) == digest.count + } + + if (!copied) { + return -1 + } + + return 1 +}