繁体   English   中英

使用 AES 算法在 javascript 中加密并在 C# 中解密

[英]Encrypt in javascript and decrypt in C# with AES algorithm

我尝试使用来自AES 的AES 库以角度加密

我使用来自 AES 的CryptoJS.AES.encrypt()方法对字符串进行了加密。

这是我的代码:

  var txtloginKod = 'Some String...';             
  var key = CryptoJS.enc.Utf8.parse('8080808080808080');
  var iv = CryptoJS.enc.Utf8.parse('8080808080808080');
  var  encryptedlogin = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(txtloginKod), key,
  {
      keySize: 128 / 8,
      iv: iv,
      mode: CryptoJS.mode.CBC,
      padding: CryptoJS.pad.Pkcs7
  });

CryptoJS.AES.encrypt()方法向我的encryptedlogin变量返回一个对象。

我不知道如何在 C# 中将此对象发送到我的 WCF Web 服务器

当我尝试发送整个对象(并定义 Web 服务方法以期望获取 C# 对象)时,出现以下错误:

“将循环结构转换为 JSON”

我也需要将加密的 JSON 对象发送到 .Net CORE API 2.0 并在互联网上搜索以查找是否有任何帮助。 我知道现在你已经解决了这个问题,但为了帮助任何感兴趣的人,我提供了我的解决方案来帮助他们。

使用我在 stackoverflow 上找到的示例代码,我设法实现了该解决方案。 棘手的一点是关键,IV 的长度必须为 16,代码才能工作。

public static encrypt(model: any) {
        const key = CryptoJS.enc.Utf8.parse('TestMyOwnKeyForI');
        const iv = CryptoJS.enc.Utf8.parse('TestMyOwnIV1ForI');
        // padding and truncating
        const encryptedMessage = CryptoJS.AES.encrypt(JSON.stringify(model), key, {            
            keySize: 128 / 8,
            iv: iv,
            mode: CryptoJS.mode.CBC,
            padding: CryptoJS.pad.Pkcs7
        }).toString();

        return encryptedMessage;
}

在 CORE 中,我实现了我的客户模型绑定提供程序,如下所示:

public class DecryptModelBinderProvider : IModelBinderProvider
    {
        public IModelBinder GetBinder(ModelBinderProviderContext context)
        {
            if (context.Metadata.ModelType == typeof(MyModel))
                return new DecryptModelBinder();

            return null;
        }
    }

然后我自己的decryptmodelbinder如下:

public class DecryptModelBinder : IModelBinder
    {
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            if (bindingContext == null)
                throw new ArgumentNullException(nameof(bindingContext));
            using (var sr = new StreamReader(bindingContext.HttpContext.Request.Body))
            {
                string valueFromBody = sr.ReadToEnd();

                if (valueFromBody != null && valueFromBody.Length > 0)
                {
                    var decrypted = Encryption.DecryptString(valueFromBody, "TestMyOwnKeyForI");

                    var model = JsonConvert.DeserializeObject(decrypted, bindingContext.ModelType);

                    bindingContext.Result = ModelBindingResult.Success(model);
                    bindingContext.Model = model;        
                }

            }

            return Task.CompletedTask;
        }
    }

使用 Dot net core 和 Type Script。

npm instal crypto-js

//Inside imports of your TS file include 
import * as CryptoJS from 'crypto-js';

// Declare this key and iv values in declaration
private key = CryptoJS.enc.Utf8.parse('4512631236589784');
private iv = CryptoJS.enc.Utf8.parse('4512631236589784');

// Methods for the encrypt and decrypt Using AES
encryptUsingAES256() {
    var encrypted = CryptoJS.AES.encrypt(CryptoJS.enc.Utf8.parse(JSON.stringify("Your Json Object data or string")), this.key, {
        keySize: 128 / 8,
        iv: this.iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    console.log('Encrypted :' + encrypted);
    this.decryptUsingAES256(encrypted);
    return encrypted;
}

decryptUsingAES256(decString) {
    var decrypted = CryptoJS.AES.decrypt(decString, this.key, {
        keySize: 128 / 8,
        iv: this.iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    console.log('Decrypted : ' + decrypted);
    console.log('utf8 = ' + decrypted.toString(CryptoJS.enc.Utf8));

}

用于编码或解码的 C# 代码在这里。

public class encr {
    public static string DecryptStringAES(string cipherText) {
        var keybytes = Encoding.UTF8.GetBytes("4512631236589784");
        var iv = Encoding.UTF8.GetBytes("4512631236589784");

        var encrypted = Convert.FromBase64String(cipherText);
        var decriptedFromJavascript = DecryptStringFromBytes(encrypted, keybytes, iv);
        return decriptedFromJavascript;
    }
    private static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv) {
        // Check arguments.
        if (cipherText == null || cipherText.Length <= 0) {
            throw new ArgumentNullException("cipherText");
        }
        if (key == null || key.Length <= 0) {
            throw new ArgumentNullException("key");
        }
        if (iv == null || iv.Length <= 0) {
            throw new ArgumentNullException("key");
        }

        // Declare the string used to hold
        // the decrypted text.
        string plaintext = null;

        // Create an RijndaelManaged object
        // with the specified key and IV.
        using(var rijAlg = new RijndaelManaged()) {
            //Settings
            rijAlg.Mode = CipherMode.CBC;
            rijAlg.Padding = PaddingMode.PKCS7;
            rijAlg.FeedbackSize = 128;

            rijAlg.Key = key;
            rijAlg.IV = iv;

            // Create a decrytor to perform the stream transform.
            var decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);

            try {
                // Create the streams used for decryption.
                using(var msDecrypt = new MemoryStream(cipherText)) {
                    using(var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read)) {

                        using(var srDecrypt = new StreamReader(csDecrypt)) {
                            // Read the decrypted bytes from the decrypting stream
                            // and place them in a string.
                            plaintext = srDecrypt.ReadToEnd();

                        }

                    }
                }
            } catch {
                plaintext = "keyError";
            }
        }

        return plaintext;
    }

    public static string EncryptStringAES(string plainText) {
        var keybytes = Encoding.UTF8.GetBytes("4512631236589784");
        var iv = Encoding.UTF8.GetBytes("4512631236589784");

        var encryoFromJavascript = EncryptStringToBytes(plainText, keybytes, iv);
        return Convert.ToBase64String(encryoFromJavascript);
    }

    private static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv) {
        // Check arguments.
        if (plainText == null || plainText.Length <= 0) {
            throw new ArgumentNullException("plainText");
        }
        if (key == null || key.Length <= 0) {
            throw new ArgumentNullException("key");
        }
        if (iv == null || iv.Length <= 0) {
            throw new ArgumentNullException("key");
        }
        byte[] encrypted;
        // Create a RijndaelManaged object
        // with the specified key and IV.
        using(var rijAlg = new RijndaelManaged()) {
            rijAlg.Mode = CipherMode.CBC;
            rijAlg.Padding = PaddingMode.PKCS7;
            rijAlg.FeedbackSize = 128;

            rijAlg.Key = key;
            rijAlg.IV = iv;

            // Create a decrytor to perform the stream transform.
            var encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);

            // Create the streams used for encryption.
            using(var msEncrypt = new MemoryStream()) {
                using(var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write)) {
                    using(var swEncrypt = new StreamWriter(csEncrypt)) {
                        //Write all data to the stream.
                        swEncrypt.Write(plainText);
                    }
                    encrypted = msEncrypt.ToArray();
                }
            }
        }
        // Return the encrypted bytes from the memory stream.
        return encrypted;
    }
}

您需要自己序列化密文。 有很多方法可以做到。

如果密钥不是字符串,而是WordArray (如您的情况),那么简单的encryptedlogin.toString()将生成仅包含密文的 Base64 编码字符串。 请记住,您需要包含 enc-base64.js 源文件。

如果“密钥”(实际上是密码)是字符串,则应用与 OpenSSL 兼容的密钥派生。 在这种情况下, encryptedlogin.toString()将是一个 Base64 编码的字符串,其中包含“Salted__”字符串、8 字节随机盐和密文。

如果你只想得到密文,那么encryptedlogin.ciphertext.toString()会给你一个只包含密文的十六进制编码字符串, encryptedlogin.iv.toString()会给你一个十六进制编码的 IV。 您可以通过这种方式生成 Base64 编码的字符串encryptedlogin.ciphertext.toString(CryptoJS.enc.Base64)

请记住,必须为每个加密随机选择 IV,以提供语义安全性。 它不必是秘密的,因此您可以将其与密文一起发送。

在服务器端,您将解码值(Base64 或 Hex,取决于您在加密期间使用的内容)并将它们与 AesCryptoServiceProvider 类(或类似类)一起使用来解密密文。


请记住,您还需要验证您的密文以检测(恶意)操作。 这可以通过具有强 MAC(如 HMAC-SHA256)的 encrypt-then-MAC 方案来完成。

此外,如果密钥与密文一起传输或通过不安全的通道传输,那么这基本上只是数据混淆,并不能提供真正的安全性。 查看更多: Javascript 密码学被认为是有害的

使用返回对象中的 encryptedLogin.cipherText

请检查https://social.msdn.microsoft.com/Forums/vstudio/en-US/47800a60-4461-4f8e-a8d1-751fa62c7884/aes-encrypt-in-javascript-and-decrypt-in-c?forum=夏普将军

此外,您应该使用 CryptoJS v3.1.2 AES 实现来使用它。 你可以在这里下载: https : //storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/crypto-js/CryptoJS%20v3.1.2.zip

您可以在此处找到 Js 端代码:jsfiddle.net/aEKw5/22/

因此,使用上面的信息,您可以在 C# 端进行编码,并在 js 上对其进行解码。 反之亦然。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM