diff --git a/System.Security.Cryptography/HMACSHA512.cs b/System.Security.Cryptography/HMACSHA512.cs
new file mode 100644
index 0000000..a0668db
--- /dev/null
+++ b/System.Security.Cryptography/HMACSHA512.cs
@@ -0,0 +1,166 @@
+//
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+
+using System.Runtime.CompilerServices;
+
+namespace System.Security.Cryptography
+{
+ ///
+ /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA512 hash function.
+ ///
+ public class HMACSHA512 : IDisposable
+ {
+ private const int BlockSize = 128;
+
+ private bool _disposed;
+ private byte[] _keyValue = null;
+ private byte[] _hashValue;
+
+ ///
+ /// Gets the value of the computed hash code.
+ ///
+ /// The current value of the computed hash code.
+ /// The object has already been disposed.
+ public byte[] Hash
+ {
+ get
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException();
+ }
+
+ return (byte[])_hashValue.Clone();
+ }
+ }
+
+ ///
+ /// Gets or sets the key to use in the HMAC calculation.
+ ///
+ /// The key to use in the HMAC calculation.
+ ///
+ ///
+ /// This property is the key for the keyed hash algorithm.
+ ///
+ ///
+ /// A Hash-based Message Authentication Code (HMAC) can be used to determine whether a message sent over an insecure channel has been tampered with, provided that the sender and receiver share a secret key. The sender computes the hash value for the original data and sends both the original data and the HMAC as a single message. The receiver recomputes the hash value on the received message and checks that the computed hash value matches the transmitted hash value.
+ ///
+ ///
+ public byte[] Key
+ {
+ get
+ {
+ return (byte[])_keyValue.Clone();
+ }
+
+ set
+ {
+ _keyValue = (byte[])value.Clone() ?? throw new ArgumentNullException();
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the HMACSHA512 class with a randomly generated key.
+ ///
+ ///
+ ///
+ /// is a type of keyed hash algorithm that is constructed from the SHA-512 hash function and used as a Hash-based Message Authentication Code (HMAC). The HMAC process mixes a secret key with the message data, hashes the result with the hash function, mixes that hash value with the secret key again, and then applies the hash function a second time. The output hash is 512 bits in length.
+ ///
+ ///
+ /// This constructor uses a 128-byte, randomly generated key.
+ ///
+ ///
+ public HMACSHA512()
+ {
+ // Generate a random key with 128 bytes
+ Random generator = new();
+ _keyValue = new byte[BlockSize];
+ generator.NextBytes(_keyValue);
+ }
+
+ ///
+ /// Initializes a new instance of the class with the specified key data.
+ ///
+ /// The secret key for HMAC computation. The key can be any length. However, the recommended size is 128 bytes. If the key is more than 128 bytes long, it is hashed (using SHA-512) to derive a 64-byte key.
+ /// The parameter is .
+ ///
+ /// is a type of keyed hash algorithm that is constructed from the SHA-512 hash function and used as a Hash-based Message Authentication Code (HMAC). The HMAC process mixes a secret key with the message data, hashes the result with the hash function, mixes that hash value with the secret key again, and then applies the hash function a second time. The output hash is 512 bits in length.
+ ///
+ public HMACSHA512(byte[] key)
+ {
+ _keyValue = key ?? throw new ArgumentNullException();
+ }
+
+ ///
+ /// Computes the hash value for the specified byte array.
+ ///
+ /// The input to compute the hash code for.
+ /// The computed hash code.
+ /// The object has already been disposed.
+ /// is .
+ public byte[] ComputeHash(byte[] buffer)
+ {
+ if (_disposed)
+ {
+ throw new ObjectDisposedException();
+ }
+
+ // Developer note: "buffer" parameter is checked for null by HashCore()
+
+ _hashValue = HashCore(_keyValue, buffer);
+
+ return (byte[])_hashValue.Clone();
+ }
+
+ ///
+ /// Computes the HMAC of data using the SHA512 algorithm.
+ ///
+ /// The HMAC key.
+ /// The data to HMAC.
+ /// The HMAC of the data.
+ ///
+ /// or is .
+ ///
+ public static byte[] HashData(
+ byte[] key,
+ byte[] source)
+ {
+ // Developer note: "key" and "source" parameters are checked for null by HashCore()
+
+ return HashCore(key, source);
+ }
+
+ ///
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ ///
+ protected void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ if (_keyValue != null)
+ {
+ Array.Clear(_keyValue, 0, _keyValue.Length);
+ }
+
+ _keyValue = null;
+
+ // Although we don't have any resources to dispose at this level,
+ // we need to continue to throw ObjectDisposedExceptions from CalculateHash
+ // for compatibility with the .NET Framework.
+ _disposed = true;
+ }
+
+ return;
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ extern private static byte[] HashCore(byte[] key, byte[] source);
+ }
+}
diff --git a/System.Security.Cryptography/Properties/AssemblyInfo.cs b/System.Security.Cryptography/Properties/AssemblyInfo.cs
index da8f1d4..8d3acb3 100644
--- a/System.Security.Cryptography/Properties/AssemblyInfo.cs
+++ b/System.Security.Cryptography/Properties/AssemblyInfo.cs
@@ -16,5 +16,5 @@
////////////////////////////////////////////////////////////////
// update this whenever the native assembly signature changes //
-[assembly: AssemblyNativeVersion("100.0.0.3")]
+[assembly: AssemblyNativeVersion("100.0.0.4")]
////////////////////////////////////////////////////////////////
diff --git a/System.Security.Cryptography/System.Security.Cryptography.nfproj b/System.Security.Cryptography/System.Security.Cryptography.nfproj
index 33bc655..bc62771 100644
--- a/System.Security.Cryptography/System.Security.Cryptography.nfproj
+++ b/System.Security.Cryptography/System.Security.Cryptography.nfproj
@@ -1,4 +1,4 @@
-
+
@@ -46,6 +46,7 @@
+
@@ -71,4 +72,4 @@
-
\ No newline at end of file
+
diff --git a/Tests/System.Security.CryptographyTests/HmacSha512Tests.cs b/Tests/System.Security.CryptographyTests/HmacSha512Tests.cs
new file mode 100644
index 0000000..ce51fee
--- /dev/null
+++ b/Tests/System.Security.CryptographyTests/HmacSha512Tests.cs
@@ -0,0 +1,105 @@
+//
+// Copyright (c) .NET Foundation and Contributors
+// Portions Copyright (c) Microsoft Corporation. All rights reserved.
+// See LICENSE file in the project root for full license information.
+//
+
+using nanoFramework.TestFramework;
+using System.Collections;
+using System.Security.Cryptography;
+
+namespace System.Security.CryptographyTests
+{
+ [TestClass]
+ public class HmacSha512Tests
+ {
+ // RFC 4231 test vectors for HMAC-SHA-512
+ static ArrayList keys = new ArrayList()
+ {
+ // Test case 1: 20-byte key
+ new byte[] { 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b },
+ // Test case 2: "Jefe"
+ new byte[] { 0x4a, 0x65, 0x66, 0x65 },
+ // Test case 3: 20-byte key of 0xaa
+ new byte[] { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa },
+ // Test case 4: 25-byte key
+ new byte[] { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 },
+ // Test case 6: 131-byte key (larger than block size)
+ new byte[] { 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa }
+ };
+
+ static ArrayList sources = new ArrayList()
+ {
+ // Test case 1: "Hi There"
+ new byte[] { 0x48, 0x69, 0x20, 0x54, 0x68, 0x65, 0x72, 0x65 },
+ // Test case 2: "what do ya want for nothing?"
+ new byte[] { 0x77, 0x68, 0x61, 0x74, 0x20, 0x64, 0x6f, 0x20, 0x79, 0x61, 0x20, 0x77, 0x61, 0x6e, 0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x3f },
+ // Test case 3: 50 bytes of 0xdd
+ new byte[] { 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd },
+ // Test case 4: 50 bytes of 0xcd
+ new byte[] { 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd },
+ // Test case 6: "Test Using Larger Than Block-Size Key - Hash Key First"
+ new byte[] { 0x54, 0x65, 0x73, 0x74, 0x20, 0x55, 0x73, 0x69, 0x6e, 0x67, 0x20, 0x4c, 0x61, 0x72, 0x67, 0x65, 0x72, 0x20, 0x54, 0x68, 0x61, 0x6e, 0x20, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x2d, 0x53, 0x69, 0x7a, 0x65, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x2d, 0x20, 0x48, 0x61, 0x73, 0x68, 0x20, 0x4b, 0x65, 0x79, 0x20, 0x46, 0x69, 0x72, 0x73, 0x74 },
+ };
+
+ // RFC 4231 expected HMAC-SHA-512 outputs
+ static ArrayList expectedHashes = new ArrayList()
+ {
+ // Test case 1
+ new byte[] { 0x87, 0xaa, 0x7c, 0xde, 0xa5, 0xef, 0x61, 0x9d, 0x4f, 0xf0, 0xb4, 0x24, 0x1a, 0x1d, 0x6c, 0xb0, 0x23, 0x79, 0xf4, 0xe2, 0xce, 0x4e, 0xc2, 0x78, 0x7a, 0xd0, 0xb3, 0x05, 0x45, 0xe1, 0x7c, 0xde, 0xda, 0xa8, 0x33, 0xb7, 0xd6, 0xb8, 0xa7, 0x02, 0x03, 0x8b, 0x27, 0x4e, 0xae, 0xa3, 0xf4, 0xe4, 0xbe, 0x9d, 0x91, 0x4e, 0xeb, 0x61, 0xf1, 0x70, 0x2e, 0x69, 0x6c, 0x20, 0x3a, 0x12, 0x68, 0x54 },
+ // Test case 2
+ new byte[] { 0x16, 0x4b, 0x7a, 0x7b, 0xfc, 0xf8, 0x19, 0xe2, 0xe3, 0x95, 0xfb, 0xe7, 0x3b, 0x56, 0xe0, 0xa3, 0x87, 0xbd, 0x64, 0x22, 0x2e, 0x83, 0x1f, 0xd6, 0x10, 0x27, 0x0c, 0xd7, 0xea, 0x25, 0x05, 0x54, 0x97, 0x58, 0xbf, 0x75, 0xc0, 0x5a, 0x99, 0x4a, 0x6d, 0x03, 0x4f, 0x65, 0xf8, 0xf0, 0xe6, 0xfd, 0xca, 0xea, 0xb1, 0xa3, 0x4d, 0x4a, 0x6b, 0x4b, 0x63, 0x6e, 0x07, 0x0a, 0x38, 0xbc, 0xe7, 0x37 },
+ // Test case 3
+ new byte[] { 0xfa, 0x73, 0xb0, 0x08, 0x9d, 0x56, 0xa2, 0x84, 0xef, 0xb0, 0xf0, 0x75, 0x6c, 0x89, 0x0b, 0xe9, 0xb1, 0xb5, 0xdb, 0xdd, 0x8e, 0xe8, 0x1a, 0x36, 0x55, 0xf8, 0x3e, 0x33, 0xb2, 0x27, 0x9d, 0x39, 0xbf, 0x3e, 0x84, 0x82, 0x79, 0xa7, 0x22, 0xc8, 0x06, 0xb4, 0x85, 0xa4, 0x7e, 0x67, 0xc8, 0x07, 0xb9, 0x46, 0xa3, 0x37, 0xbe, 0xe8, 0x94, 0x26, 0x74, 0x27, 0x88, 0x59, 0xe1, 0x32, 0x92, 0xfb },
+ // Test case 4
+ new byte[] { 0xb0, 0xba, 0x46, 0x56, 0x37, 0x45, 0x8c, 0x69, 0x90, 0xe5, 0xa8, 0xc5, 0xf6, 0x1d, 0x4a, 0xf7, 0xe5, 0x76, 0xd9, 0x7f, 0xf9, 0x4b, 0x87, 0x2d, 0xe7, 0x6f, 0x80, 0x50, 0x36, 0x1e, 0xe3, 0xdb, 0xa9, 0x1c, 0xa5, 0xc1, 0x1a, 0xa2, 0x5e, 0xb4, 0xd6, 0x79, 0x27, 0x5c, 0xc5, 0x78, 0x80, 0x63, 0xa5, 0xf1, 0x97, 0x41, 0x12, 0x0c, 0x4f, 0x2d, 0xe2, 0xad, 0xeb, 0xeb, 0x10, 0xa2, 0x98, 0xdd },
+ // Test case 6
+ new byte[] { 0x80, 0xb2, 0x42, 0x63, 0xc7, 0xc1, 0xa3, 0xeb, 0xb7, 0x14, 0x93, 0xc1, 0xdd, 0x7b, 0xe8, 0xb4, 0x9b, 0x46, 0xd1, 0xf4, 0x1b, 0x4a, 0xee, 0xc1, 0x12, 0x1b, 0x01, 0x37, 0x83, 0xf8, 0xf3, 0x52, 0x6b, 0x56, 0xd0, 0x37, 0xe0, 0x5f, 0x25, 0x98, 0xbd, 0x0f, 0xd2, 0x21, 0x5d, 0x6a, 0x1e, 0x52, 0x95, 0xe6, 0x4f, 0x73, 0xf6, 0x3f, 0x0a, 0xec, 0x8b, 0x91, 0x5a, 0x98, 0x5d, 0x78, 0x65, 0x98 },
+ };
+
+ [DataRow("RFC4231 Test case 1", 0, 0, 0)]
+ [DataRow("RFC4231 Test case 2", 1, 1, 1)]
+ [DataRow("RFC4231 Test case 3", 2, 2, 2)]
+ [DataRow("RFC4231 Test case 4", 3, 3, 3)]
+ [DataRow("RFC4231 Test case 6", 4, 4, 4)]
+ [TestMethod]
+ public void TestHMACSHA512Static(
+ string testCase,
+ int keyIndex,
+ int sourceIndex,
+ int hashIndex)
+ {
+ OutputHelper.WriteLine($"Test Case: {testCase}");
+
+ var hash = HMACSHA512.HashData(
+ (byte[])keys[keyIndex],
+ (byte[])sources[sourceIndex]);
+
+ CollectionAssert.AreEqual(
+ (byte[])expectedHashes[hashIndex],
+ hash);
+ }
+
+ [DataRow("RFC4231 Test case 1", 0, 0, 0)]
+ [DataRow("RFC4231 Test case 2", 1, 1, 1)]
+ [DataRow("RFC4231 Test case 3", 2, 2, 2)]
+ [DataRow("RFC4231 Test case 4", 3, 3, 3)]
+ [DataRow("RFC4231 Test case 6", 4, 4, 4)]
+ [TestMethod]
+ public void TestHMACSHA512Compute(
+ string testCase,
+ int keyIndex,
+ int sourceIndex,
+ int hashIndex)
+ {
+ OutputHelper.WriteLine($"Test Case: {testCase}");
+
+ HMACSHA512 hasher = new HMACSHA512((byte[])keys[keyIndex]);
+ hasher.ComputeHash((byte[])sources[sourceIndex]);
+
+ CollectionAssert.AreEqual(
+ (byte[])expectedHashes[hashIndex],
+ hasher.Hash);
+ }
+ }
+}
diff --git a/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj b/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj
index 97bbbd6..9fc9875 100644
--- a/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj
+++ b/Tests/System.Security.CryptographyTests/System.Security.CryptographyTests.nfproj
@@ -30,6 +30,7 @@
+
diff --git a/nanoFramework.System.Security.Cryptography.nuspec b/nanoFramework.System.Security.Cryptography.nuspec
index 8e0e609..f5342d5 100644
--- a/nanoFramework.System.Security.Cryptography.nuspec
+++ b/nanoFramework.System.Security.Cryptography.nuspec
@@ -19,15 +19,13 @@
This package requires a target with nanoFramework.System.Security.Cryptography v$nativeVersion$ (checksum $checksum$).
nanoFramework C# csharp netmf netnf
-
+
+
+
-
-
-
-
-
+