首页 > 解决方案 > 使用 Sytem.Secuirty.Cryptography 的 C# AES-GCM 和 RSA 加密

问题描述

我正在用 c# 开发发布数据请求并使用 AES GCM 加密和 RSA 加密。与使用 Node.js / Python 进行加密的 C# 代码相比,我们发现 C# AES GCM 加密在方法中没有标记值。例如,加密后如何在 C# 中返回以下数据。

return {
key: aesKey,
cipher_text: encrypted,
tag,
iv
}

在使用 JsEncrypt 的 Python 和 Node.js 中,forge.js.... 和实现工作正常。但是,现在在 C# 中开发相同的客户端,找不到我可以直接使用的此类库。

但是,我在 C# AesGcm 和 AesManaged 中找到了两个用于 AES 加密的类。但我认为 AesManages 仅适用于 AES 而不是 GCM 加密。因此,我在下面的示例中使用 AesGcm 类,但不确定。

代码执行以下步骤:

  1. 从 DSG 请求客户端证书。
  2. 从证书中提取公钥。
  3. 使用 AES 密钥加密 PII。
  4. 使用 RSA 公钥加密 AES 密钥。
  5. 将打包的密钥和 PII 有效负载发送到 DSG 标记化。
class Program
{
    static void Main(string[] args)
    {
        string _ApiKey = "--- YOUR API KEY ----";
        string _SecretKey = " ---- YOUR SECRET KEY --------";
        string jsonPlainText = "<JSON TExT>";

        #region Certificate

        string certificate = GetCertificate();

        Certificate rawSigningCert = JsonConvert.DescrializeObject<Certificate>(certificate);
        var certBytes = Encoding.UTF8.GetBytes(rawSigningCert.crt);

        // X509Certificate2
        var x509Certificate2 = new System.Security.Cryptography.X509Certificates.X509Certificate2(certBytes);
        byte[] publicKey = x509Certificate2.GetPublicKey();

        #endregion

        #region AES GCM Encryption

        byte[] aesGcmKey = new byte[16];
        RandomNumberGenerator.Fill(aesGcmKey);

        byte[] nonce = new byte[12];
        RandomNumberGenerator.Fill(nonce);

        byte[] tag = new byte[16];
        byte[] dataToEncrypt = Encoding.UTF8.GetBytes(jsonPlainText);

        byte[] cipherText = new byte[dataToEncrypt.Length];

        using (AesGcm aesGcm = new AesGcm(aesGcmKey))
        {
            aesGcm.Encrypt(nonce, dataToEncrypt, cipherText, tag);
        }

        string encryptedCipher = Convert.ToBase64String(cipherText);

        var keyString = Convert.ToBase64String(aesGcmKey);
        var iVString = Convert.ToBase64String(nonce);
        var tagString = Convert.ToBase64String(tag);

        string aesGcmEncryptionString = string.Format("{0}:{1}:{2}", keyString, iVString, tagString);

        #endregion

        #region RSA Encryption

        var rsa = new RSACryptoServiceProvider();
        RSAParameters RSAKeyInfo = rsa.ExportParameters(false);

        RSAKeyInfo.Modulus = publicKey;

        rsa.ImportParameters(RSAKeyInfo);

        byte[] encryptedSymmetricKey = RSAEncrypt(Encoding.UTF8.GetBytes(aesGcmEncryptionString), RSAKeyInfo, false);

        var enc_key = Convert.ToBase64String(encryptedSymmetricKey);
        var requestBodyObject = new { message = encryptedCipher, enckey = enc_key };

        string jsonRequestBody = JsonConvert.SerializeObject(requestBodyObject);

        #endregion

        #region Calculating Message Signature
        Random random = new Random();
        int ClientRequestId = random.Next(0, 99999999);
        var time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        var rawSignature = _ApiKey + ClientRequestId + time + jsonRequestBody;
        HMACSHA256 hashObject = new HMACSHA256(Encoding.UTF8.GetBytes(_SecretKey));
        var signature = hashObject.ComputeHash(Encoding.UTF8.GetBytes(rawSignature));
        var computedHmac = Convert.ToBase64String(signature);


        #endregion

        #region Make Request

        try
        {
            var client = new RestClient("< API URL>");
            client.Timeout = -1;
            var request = new RestRequest(Method.POST);
            request.AddHeader("contentType", "application/json");
            request.AddHeader("clientRequestId", ClientRequestId.ToString());
            request.AddHeader("apiKey", _ApiKey);
            request.AddHeader("timestamp", time.Tostring);
            request.AddHeader("messageSignature", computedHmac);
            request.AddJsonBody(jsonRequestBody);
            request.RequestFormat = DataFormat.Json;
            IRestResponse response = client.Execute(request);
            Console.WriteLine(response.Content);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }

        #endregion
    }

    static string GetCertificate()
    {
        string cer = string.Empty;
        // Code to get certicate .crt from the service.
        //"<GET CERTICATE HERE>";
        return cer;
    }

    static public byte[] RSAEncrpt(byte[] data, RSAParameters keyInfo, bool doOAEPPadding)
    {
        byte[] encryptedData;
        using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
        {
            rsa.ImportParameters(keyInfo);
            encryptedData = rsa.Encrypt(data, RSAEncryptionPadding.Pkcs1);
        }
        return encryptedData;
    }
}

class Certificate
{
    public string crt { get; set; }
}

当服务以不正确的消息签名响应时,我如何跟踪每个步骤。有什么方法可以验证和跟踪上述代码步骤?

帮助!提前致谢

标签: c#.netencryptionrsaaes-gcm

解决方案


推荐阅读