Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions src/Neo/Cryptography/Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/// <summary>
/// Computes the hash value for the specified byte array using the ripemd160 algorithm.
/// </summary>
Expand Down Expand Up @@ -229,22 +232,22 @@ public static byte[] Keccak256(this Span<byte> 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
{
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);
Expand All @@ -257,24 +260,25 @@ 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<byte> 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
{
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);
Expand Down
45 changes: 26 additions & 19 deletions tests/Neo.UnitTests/Cryptography/UT_Cryptography_Helper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<FormatException>(action);

input = "3vQB7B6MrGQZaxCuFg4og";
action = () => input.Base58CheckDecode();
Assert.ThrowsExactly<FormatException>(action);

Assert.ThrowsExactly<FormatException>(() => _ = string.Empty.Base58CheckDecode());
}

Expand Down Expand Up @@ -90,20 +89,22 @@ public void TestKeccak256()
public void TestRIPEMD160()
{
ReadOnlySpan<byte> 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);
Expand All @@ -113,35 +114,41 @@ 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<ArgumentException>(() => Helper.AES256Decrypt(new byte[11], key1.PrivateKey));
Assert.ThrowsExactly<ArgumentException>(() => Helper.AES256Decrypt(new byte[11 + 16], key1.PrivateKey));
}

[TestMethod]
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,
Expand Down
Loading