将JavaAES/GCM/NoPadding算法转换为C#

Convert Java AES/GCM/NoPadding algorithm to C#

我正在尝试转换此 java 代码:

package ffsd;

import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class GatewayEncryptUtil {
  public static String encrypt(String plainText, String key) throws Exception {
    return new String(Base64.getEncoder().encode(doCrypt(plainText.getBytes(), 1, key)));
  }
  
  public static byte[] doCrypt(byte[] inputText, int operation, String key) throws Exception {
    MessageDigest mDigest = MessageDigest.getInstance("SHA-512");
    byte[] secretKey = key.getBytes();
    byte[] digestSeed = mDigest.digest(secretKey);
    byte[] hashKey = Arrays.copyOf(digestSeed, 16);
    
    Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
    SecretKeySpec skspec = new SecretKeySpec(hashKey, "AES");
    String cipherKey = new String(secretKey);
    GCMParameterSpec gcmParams = new GCMParameterSpec(128, cipherKey.substring(0, 16).getBytes());
    cipher.init(operation, skspec, gcmParams);
    return cipher.doFinal(inputText);
  }
  
  public static void main(String[] args) {
    try {
      System.out.println(encrypt("Password", "1234567890123456"));
    } catch (Exception e) {
      e.printStackTrace();
    } 
  }
}

使用新的 AesGcm 到 C# .NET 5.0 class:

using System;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            string inputText = "Password";
            string msgId = "1234567890123456";

            byte[] hashKey;
            byte[] secretKey = Encoding.ASCII.GetBytes(msgId);

            using (var hasher = SHA512.Create())
            {
                byte[] digestSeed = hasher.ComputeHash(secretKey);
                hashKey = new byte[16];
                Array.Copy(digestSeed, hashKey, hashKey.Length);
            }

            using (var aesGcm = new AesGcm(hashKey))
            {
                byte[] nonce = new byte[AesGcm.NonceByteSizes.MaxSize];
                byte[] plainText = Encoding.ASCII.GetBytes(inputText);
                byte[] authTag = new byte[AesGcm.TagByteSizes.MaxSize];
                byte[] cipherText = new byte[plainText.Length];

                aesGcm.Encrypt(nonce, plainText, cipherText, authTag);
                string cipherTextBase64 = Convert.ToBase64String(cipherText);
                string authTagBase64 = Convert.ToBase64String(authTag);

                Console.WriteLine(cipherTextBase64);
                Console.WriteLine(authTagBase64);
            }
        }
    }
}

但我不知道 nonce 应该是什么。在任何地方的 java 代码中都看不到它。任何人都可以给我任何指示吗? java 代码的结果是:“gc1zTHlIPQusN5e+Rjq+veDoIYdU1nCQ” 我的显然是不完整的,没有接近。

IV和Nonce是同一个意思

这里的 IV 是 GCMParameterSpec 的第二个参数:

GCMParameterSpec gcmParams = new GCMParameterSpec(128, cipherKey.substring(0, 16).getBytes());

.NET 调用这个 Nonce。

我能够使用 BouncyCastle 将其转换为 C#:

using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.Security;
using System;
using System.Security.Cryptography;
using System.Text;

namespace ConsoleApp3
{
    class Program
    {
        static void Main(string[] args)
        {
            string inputText = "Password";
            string msgId = "1234567890123456";

            string value = Encrypt(inputText, msgId);
            Console.WriteLine(value);
        }

        public static string Encrypt(string plainText, string msgId)
        {
            const byte GcmTagSize = 16;

            byte[] hashKey;
            byte[] secretKey = Encoding.ASCII.GetBytes(msgId);

            using (var hasher = SHA512.Create())
            {
                byte[] digestSeed = hasher.ComputeHash(secretKey);
                hashKey = new byte[16];
                Array.Copy(digestSeed, hashKey, hashKey.Length);
            }

            var keyParameter = new KeyParameter(hashKey);
            var keyParameters = new AeadParameters(keyParameter, GcmTagSize * 8, secretKey);

            var cipher = CipherUtilities.GetCipher("AES/GCM/NoPadding");
            cipher.Init(true, keyParameters);

            var plainTextData = Encoding.ASCII.GetBytes(plainText);
            var cipherText = cipher.DoFinal(plainTextData);

            return Convert.ToBase64String(cipherText);
        }
    }
}