diff --git a/src/neo/Cryptography/Helper.cs b/src/neo/Cryptography/Helper.cs index e1b062e74c..6fccfcf81b 100644 --- a/src/neo/Cryptography/Helper.cs +++ b/src/neo/Cryptography/Helper.cs @@ -10,6 +10,7 @@ using Neo.IO; using Neo.Network.P2P.Payloads; +using Neo.Wallets; using System; using System.Buffers.Binary; using System.Collections.Generic; @@ -18,6 +19,8 @@ using System.Security; using System.Security.Cryptography; using System.Text; +using static Neo.Helper; +using ECPoint = Neo.Cryptography.ECC.ECPoint; namespace Neo.Cryptography { @@ -119,6 +122,54 @@ public static byte[] Sha256(this Span value) return Sha256((ReadOnlySpan)value); } + public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] nonce, byte[] associatedData = null) + { + if (nonce.Length != 12) throw new ArgumentOutOfRangeException(nameof(nonce)); + var cipherBytes = new byte[plainData.Length]; + var tag = new byte[16]; + using var cipher = new AesGcm(key); + cipher.Encrypt(nonce, plainData, cipherBytes, tag, associatedData); + return Concat(nonce, cipherBytes, tag); + } + + public static byte[] AES256Decrypt(this byte[] encryptedData, byte[] key, byte[] associatedData = null) + { + ReadOnlySpan encrypted = encryptedData; + var nonce = encrypted[..12]; + var cipherBytes = encrypted[12..^16]; + var tag = encrypted[^16..]; + var decryptedData = new byte[cipherBytes.Length]; + using var cipher = new AesGcm(key); + cipher.Decrypt(nonce, cipherBytes, tag, decryptedData, associatedData); + return decryptedData; + } + + public static byte[] ECDHDeriveKey(KeyPair local, ECPoint remote) + { + ReadOnlySpan pubkey_local = local.PublicKey.EncodePoint(false); + ReadOnlySpan pubkey_remote = remote.EncodePoint(false); + using ECDiffieHellman ecdh1 = ECDiffieHellman.Create(new ECParameters + { + Curve = ECCurve.NamedCurves.nistP256, + D = local.PrivateKey, + Q = new System.Security.Cryptography.ECPoint + { + X = pubkey_local[1..][..32].ToArray(), + Y = pubkey_local[1..][32..].ToArray() + } + }); + using ECDiffieHellman ecdh2 = ECDiffieHellman.Create(new ECParameters + { + Curve = ECCurve.NamedCurves.nistP256, + Q = new System.Security.Cryptography.ECPoint + { + X = pubkey_remote[1..][..32].ToArray(), + Y = pubkey_remote[1..][32..].ToArray() + } + }); + return ecdh1.DeriveKeyMaterial(ecdh2.PublicKey).Sha256();//z = r * P = r* k * G + } + internal static bool Test(this BloomFilter filter, Transaction tx) { if (filter.Check(tx.Hash.ToArray())) return true; diff --git a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index cd32a5dbfc..eebe1c9802 100644 --- a/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -4,7 +4,10 @@ using Neo.IO; using Neo.Network.P2P.Payloads; using Neo.SmartContract; +using Neo.Wallets; +using Neo.Wallets.NEP6; using System; +using System.Linq; using System.Security; using System.Text; @@ -48,6 +51,48 @@ public void TestRIPEMD160() resultStr.Should().Be("98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f"); } + [TestMethod] + public void TestAESEncryptAndDecrypt() + { + NEP6Wallet wallet = new NEP6Wallet("", ProtocolSettings.Default); + wallet.Unlock("1"); + wallet.CreateAccount(); + WalletAccount account = wallet.GetAccounts().ToArray()[0]; + KeyPair key = account.GetKey(); + Random random = new Random(); + byte[] nonce = new byte[12]; + random.NextBytes(nonce); + var cypher = Neo.Cryptography.Helper.AES256Encrypt(Encoding.UTF8.GetBytes("hello world"), key.PrivateKey, nonce); + var m = Neo.Cryptography.Helper.AES256Decrypt(cypher, key.PrivateKey); + var message2 = Encoding.UTF8.GetString(m); + Assert.AreEqual("hello world", message2); + } + + [TestMethod] + public void TestEcdhEncryptAndDecrypt() + { + NEP6Wallet wallet = new NEP6Wallet("", ProtocolSettings.Default); + wallet.Unlock("1"); + wallet.CreateAccount(); + wallet.CreateAccount(); + WalletAccount account1 = wallet.GetAccounts().ToArray()[0]; + KeyPair key1 = account1.GetKey(); + WalletAccount account2 = wallet.GetAccounts().ToArray()[1]; + KeyPair key2 = account2.GetKey(); + Console.WriteLine($"Account:{1},privatekey:{key1.PrivateKey.ToHexString()},publicKey:{key1.PublicKey.ToArray().ToHexString()}"); + Console.WriteLine($"Account:{2},privatekey:{key2.PrivateKey.ToHexString()},publicKey:{key2.PublicKey.ToArray().ToHexString()}"); + var secret1 = Neo.Cryptography.Helper.ECDHDeriveKey(key1, key2.PublicKey); + var secret2 = Neo.Cryptography.Helper.ECDHDeriveKey(key2, key1.PublicKey); + Assert.AreEqual(secret1.ToHexString(), secret2.ToHexString()); + var message = Encoding.ASCII.GetBytes("hello world"); + Random random = new Random(); + byte[] nonce = new byte[12]; + random.NextBytes(nonce); + var cypher = message.AES256Encrypt(secret1, nonce); + cypher.AES256Decrypt(secret2); + Assert.AreEqual("hello world", Encoding.ASCII.GetString(cypher.AES256Decrypt(secret2))); + } + [TestMethod] public void TestTest() {