From 80c652f0c5079a9c7d8605e7d431dacaa4dadea3 Mon Sep 17 00:00:00 2001 From: Wi1l-B0t <201105916+Wi1l-B0t@users.noreply.github.com> Date: Thu, 11 Sep 2025 08:22:12 +0800 Subject: [PATCH] Fix: avoid using obsolete AesGcm --- src/Neo/Cryptography/Helper.cs | 30 +++++++------ .../Cryptography/UT_Cryptography_Helper.cs | 45 +++++++++++-------- 2 files changed, 43 insertions(+), 32 deletions(-) diff --git a/src/Neo/Cryptography/Helper.cs b/src/Neo/Cryptography/Helper.cs index 63d138ba36..5b3595785a 100644 --- a/src/Neo/Cryptography/Helper.cs +++ b/src/Neo/Cryptography/Helper.cs @@ -32,6 +32,9 @@ public static class Helper { private static readonly bool s_isOSX = RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + private const int AesNonceSizeBytes = 12; + private const int AesTagSizeBytes = 16; + /// /// Computes the hash value for the specified byte array using the ripemd160 algorithm. /// @@ -229,14 +232,14 @@ public static byte[] Keccak256(this Span value) public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] nonce, byte[] associatedData = null) { - if (nonce.Length != 12) throw new ArgumentOutOfRangeException(nameof(nonce), "`nonce` must be 12 bytes"); - var tag = new byte[16]; + if (nonce.Length != AesNonceSizeBytes) + throw new ArgumentOutOfRangeException(nameof(nonce), $"`nonce` must be {AesNonceSizeBytes} bytes"); + + var tag = new byte[AesTagSizeBytes]; var cipherBytes = new byte[plainData.Length]; if (!s_isOSX) { -#pragma warning disable SYSLIB0053 // Type or member is obsolete - using var cipher = new AesGcm(key); -#pragma warning restore SYSLIB0053 // Type or member is obsolete + using var cipher = new AesGcm(key, AesTagSizeBytes); cipher.Encrypt(nonce, plainData, cipherBytes, tag, associatedData); } else @@ -244,7 +247,7 @@ public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] non var cipher = new GcmBlockCipher(new AesEngine()); var parameters = new AeadParameters( new KeyParameter(key), - 128, //128 = 16 * 8 => (tag size * 8) + AesTagSizeBytes * 8, // 128 = 16 * 8 => (tag size * 8) nonce, associatedData); cipher.Init(true, parameters); @@ -257,16 +260,17 @@ public static byte[] AES256Encrypt(this byte[] plainData, byte[] key, byte[] non public static byte[] AES256Decrypt(this byte[] encryptedData, byte[] key, byte[] associatedData = null) { + if (encryptedData.Length < AesNonceSizeBytes + AesTagSizeBytes) + throw new ArgumentException($"The encryptedData.Length must be greater than {AesNonceSizeBytes} + {AesTagSizeBytes}"); + ReadOnlySpan encrypted = encryptedData; - var nonce = encrypted[..12]; - var cipherBytes = encrypted[12..^16]; - var tag = encrypted[^16..]; + var nonce = encrypted[..AesNonceSizeBytes]; + var cipherBytes = encrypted[AesNonceSizeBytes..^AesTagSizeBytes]; + var tag = encrypted[^AesTagSizeBytes..]; var decryptedData = new byte[cipherBytes.Length]; if (!s_isOSX) { -#pragma warning disable SYSLIB0053 // Type or member is obsolete - using var cipher = new AesGcm(key); -#pragma warning restore SYSLIB0053 // Type or member is obsolete + using var cipher = new AesGcm(key, AesTagSizeBytes); cipher.Decrypt(nonce, cipherBytes, tag, decryptedData, associatedData); } else @@ -274,7 +278,7 @@ public static byte[] AES256Decrypt(this byte[] encryptedData, byte[] key, byte[] var cipher = new GcmBlockCipher(new AesEngine()); var parameters = new AeadParameters( new KeyParameter(key), - 128, //128 = 16 * 8 => (tag size * 8) + AesTagSizeBytes * 8, // 128 = 16 * 8 => (tag size * 8) nonce.ToArray(), associatedData); cipher.Init(false, parameters); diff --git a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs index 142131b0e1..bf13c41172 100644 --- a/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs +++ b/tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs @@ -30,18 +30,17 @@ public class UT_Cryptography_Helper public void TestBase58CheckDecode() { string input = "3vQB7B6MrGQZaxCuFg4oh"; - byte[] result = input.Base58CheckDecode(); + var result = input.Base58CheckDecode(); byte[] helloWorld = { 104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100 }; CollectionAssert.AreEqual(helloWorld, result); input = "3v"; - Action action = () => input.Base58CheckDecode(); + var action = () => input.Base58CheckDecode(); Assert.ThrowsExactly(action); input = "3vQB7B6MrGQZaxCuFg4og"; action = () => input.Base58CheckDecode(); Assert.ThrowsExactly(action); - Assert.ThrowsExactly(() => _ = string.Empty.Base58CheckDecode()); } @@ -90,20 +89,22 @@ public void TestKeccak256() public void TestRIPEMD160() { ReadOnlySpan value = Encoding.ASCII.GetBytes("hello world"); - byte[] result = value.RIPEMD160(); + var result = value.RIPEMD160(); Assert.AreEqual("98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f", result.ToHexString()); } [TestMethod] public void TestAESEncryptAndDecrypt() { - NEP6Wallet wallet = new NEP6Wallet("", "1", TestProtocolSettings.Default); + var wallet = new NEP6Wallet("", "1", TestProtocolSettings.Default); wallet.CreateAccount(); - WalletAccount account = wallet.GetAccounts().ToArray()[0]; - KeyPair key = account.GetKey(); - Random random = new Random(); - byte[] nonce = new byte[12]; + + var account = wallet.GetAccounts().ToArray()[0]; + var key = account.GetKey(); + var random = new Random(); + var nonce = new byte[12]; random.NextBytes(nonce); + var cypher = Helper.AES256Encrypt(Encoding.UTF8.GetBytes("hello world"), key.PrivateKey, nonce); var m = Helper.AES256Decrypt(cypher, key.PrivateKey); var message2 = Encoding.UTF8.GetString(m); @@ -113,25 +114,32 @@ public void TestAESEncryptAndDecrypt() [TestMethod] public void TestEcdhEncryptAndDecrypt() { - NEP6Wallet wallet = new NEP6Wallet("", "1", ProtocolSettings.Default); + var wallet = new NEP6Wallet("", "1", ProtocolSettings.Default); wallet.CreateAccount(); wallet.CreateAccount(); - WalletAccount account1 = wallet.GetAccounts().ToArray()[0]; - KeyPair key1 = account1.GetKey(); - WalletAccount account2 = wallet.GetAccounts().ToArray()[1]; - KeyPair key2 = account2.GetKey(); + + var account1 = wallet.GetAccounts().ToArray()[0]; + var key1 = account1.GetKey(); + var account2 = wallet.GetAccounts().ToArray()[1]; + var 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 = Helper.ECDHDeriveKey(key1, key2.PublicKey); var secret2 = 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]; + var random = new Random(); + var 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))); + + Assert.ThrowsExactly(() => Helper.AES256Decrypt(new byte[11], key1.PrivateKey)); + Assert.ThrowsExactly(() => Helper.AES256Decrypt(new byte[11 + 16], key1.PrivateKey)); } [TestMethod] @@ -139,9 +147,8 @@ public void TestTest() { int m = 7, n = 10; uint nTweak = 123456; - BloomFilter filter = new(m, n, nTweak); - - Transaction tx = new() + var filter = new BloomFilter(m, n, nTweak); + var tx = new Transaction() { Script = TestUtils.GetByteArray(32, 0x42), SystemFee = 4200000000,