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,