diff --git a/wrapper/CSharp/wolfSSL_CSharp/wolfCrypt.cs b/wrapper/CSharp/wolfSSL_CSharp/wolfCrypt.cs index 6ca1aa25e2..98f45b7a3d 100755 --- a/wrapper/CSharp/wolfSSL_CSharp/wolfCrypt.cs +++ b/wrapper/CSharp/wolfSSL_CSharp/wolfCrypt.cs @@ -219,6 +219,42 @@ public class wolfcrypt /******************************** * HASH */ + [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)] + private extern static IntPtr wc_HashNew(IntPtr heap, int devId); + [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)] + private extern static int wc_HashInit(IntPtr hash, wc_HashType type); + [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)] + private extern static int wc_HashUpdate(IntPtr hash, wc_HashType type, IntPtr data, uint dataSz); + [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)] + private extern static int wc_HashFinal(IntPtr hash, wc_HashType type, IntPtr output); + [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)] + private extern static int wc_HashFree(IntPtr hash, wc_HashType type); + [DllImport(wolfssl_dll, CallingConvention = CallingConvention.Cdecl)] + private extern static int wc_HashGetDigestSize(wc_HashType hash_type); + + /* HASH type enum values */ + public enum wc_HashType + { + WC_HASH_TYPE_NONE = 15, + WC_HASH_TYPE_MD2 = 16, + WC_HASH_TYPE_MD4 = 17, + WC_HASH_TYPE_MD5 = 0, + WC_HASH_TYPE_SHA = 1, /* SHA-1 (not old SHA-0) */ + WC_HASH_TYPE_SHA224 = 8, + WC_HASH_TYPE_SHA256 = 2, + WC_HASH_TYPE_SHA384 = 5, + WC_HASH_TYPE_SHA512 = 4, + WC_HASH_TYPE_MD5_SHA = 18, + WC_HASH_TYPE_SHA3_224 = 10, + WC_HASH_TYPE_SHA3_256 = 11, + WC_HASH_TYPE_SHA3_384 = 12, + WC_HASH_TYPE_SHA3_512 = 13, + WC_HASH_TYPE_BLAKE2B = 14, + WC_HASH_TYPE_BLAKE2S = 19, + WC_HASH_TYPE_MAX = WC_HASH_TYPE_BLAKE2S, + } + + /* Specifically need SHA2-256, SHA2-384 and SHA3: */ /* wc_HashInit, wc_HashUpdate, wc_HashFinal, wc_HashFree */ @@ -2080,6 +2116,172 @@ public static void AesGcmFree(IntPtr aes) /* END AES-GCM */ + /*********************************************************************** + * HASH + **********************************************************************/ + + /// + /// Allocate and set up a new hash context with proper error handling + /// + /// Pointer to the heap for memory allocation (use IntPtr.Zero if not applicable) + /// Device ID (if applicable, otherwise use INVALID_DEVID) + /// Allocated hash context pointer or IntPtr.Zero on failure + public static IntPtr HashNew(IntPtr heap, int devId) + { + IntPtr hash = IntPtr.Zero; + + try + { + hash = wc_HashNew(heap, devId); + if (hash == IntPtr.Zero) + { + throw new Exception("Failed to allocate new hash context."); + } + } + catch (Exception e) + { + log(ERROR_LOG, "HashNew Exception: " + e.ToString()); + } + return hash; + } + + /// + /// Initialize the hash context for a specific hash type with proper error handling + /// + /// Hash context pointer + /// 0 on success, otherwise an error code + public static int InitHash(IntPtr hash, wc_HashType hashType) + { + int ret = -1; + try + { + if (hash == IntPtr.Zero) throw new Exception("Hash context is null."); + ret = wc_HashInit(hash, hashType); + if (ret != 0) + { + throw new Exception($"Failed to initialize hash context. Error code: {ret}"); + } + } + catch (Exception e) + { + log(ERROR_LOG, "InitHash Exception: " + e.ToString()); + if (hash != IntPtr.Zero) + { + wc_HashFree(hash, hashType); + } + } + return ret; + } + + /// + /// Update the hash with data + /// + /// Hash context pointer + /// Byte array of the data to hash + /// 0 on success, otherwise an error code + public static int HashUpdate(IntPtr hash, wc_HashType hashType, byte[] data) + { + int ret = -1; + IntPtr dataPtr = IntPtr.Zero; + + try + { + if (hash == IntPtr.Zero) throw new Exception("Hash context is null."); + if (data == null || data.Length == 0) throw new Exception("Invalid data array."); + + dataPtr = Marshal.AllocHGlobal(data.Length); + Marshal.Copy(data, 0, dataPtr, data.Length); + + ret = wc_HashUpdate(hash, hashType, dataPtr, (uint)data.Length); + if (ret != 0) + { + throw new Exception($"Failed to update hash. Error code: {ret}"); + } + } + catch (Exception e) + { + log(ERROR_LOG, "HashUpdate Exception: " + e.ToString()); + } + finally + { + if (dataPtr != IntPtr.Zero) Marshal.FreeHGlobal(dataPtr); + } + + return ret; + } + + /// + /// Finalize the hash and output the result + /// + /// Hash context pointer + /// Byte array where the hash output will be stored + /// 0 on success, otherwise an error code + public static int HashFinal(IntPtr hash, wc_HashType hashType, out byte[] output) + { + int ret = -1; + IntPtr outputPtr = IntPtr.Zero; + int hashSize = wc_HashGetDigestSize(hashType); + output = new byte[hashSize]; + + try + { + if (hash == IntPtr.Zero) throw new Exception("Hash context is null."); + if (hashSize <= 0) throw new Exception("Invalid hash size."); + + outputPtr = Marshal.AllocHGlobal(hashSize); + + ret = wc_HashFinal(hash, hashType, outputPtr); + if (ret != 0) + { + throw new Exception($"Failed to finalize hash. Error code: {ret}"); + } + + Marshal.Copy(outputPtr, output, 0, hashSize); + } + catch (Exception e) + { + log(ERROR_LOG, "HashFinal Exception: " + e.ToString()); + output = null; + } + finally + { + if (outputPtr != IntPtr.Zero) Marshal.FreeHGlobal(outputPtr); + } + + return ret; + } + + + /// + /// Free the allocated hash context with proper error handling + /// + /// Hash context pointer to be freed + /// 0 on success, otherwise an error code + public static int HashFree(IntPtr hash, wc_HashType hashType) + { + int ret = -1; + try + { + if (hash == IntPtr.Zero) + { + throw new Exception("Hash context is null, cannot free."); + } + + ret = wc_HashFree(hash, hashType); + if (ret != 0) + { + throw new Exception($"Failed to free hash context. Error code: {ret}"); + } + } + catch (Exception e) + { + log(ERROR_LOG, "HashFree Exception: " + e.ToString()); + } + return ret; + } + /* END HASH */ + + /*********************************************************************** * Logging / Other **********************************************************************/