C#.NET AES与JavaScript的互操作性

发布于 2025-02-04 06:39:03 字数 2088 浏览 2 评论 0原文

我一直在尝试以互操作方式通过AES和C#加密和解密字符串。我的客户端应用程序是一个节点服务器,与供应商的API通信在DOT Net中。

供应商使用这些方法来加密和解密字符串:

public static string Encrypt(string data, string key)
{
  string IV = key.Substring(0, 16);
  byte[] iv = Encoding.UTF8.GetBytes(IV);
  byte[] array;
  using(Aes aes = Aes.Create())
  {
    aes.Key = Encoding.UTF8.GetBytes(key);
    aes.IV = iv;
    ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
    using(MemoryStream memoryStream = new MemoryStream())
    {
      using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
      {
        using(StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
        {
          streamWriter.Write(data);
        }
        array = memoryStream.ToArray();
      }
    }
  }
  return Convert.ToBase64String(array);
}



public static string Decrypt(string data, string key)
{
  string IV = key.Substring(0, 16);
  byte[] iv = Encoding.UTF8.GetBytes(IV);
  byte[] buffer = Convert.FromBase64String(data);
  using(Aes aes = Aes.Create())
  {
    aes.Key = Encoding.UTF8.GetBytes(key);
    aes.IV = iv;
    ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
    using(MemoryStream memoryStream = new MemoryStream(buffer))
    {
      using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
      {
        using(StreamReader streamReader = new StreamReader((Stream)cryptoStream))
        {
          return streamReader.ReadToEnd();
        }
      }
    }
  }
}

我尝试了crypto-js解密字符串,但我无法使其可行:

const encryptedText = CryptoJS.enc.Base64.parse(base64Value)
const encrypted2 = encryptedText.toString(CryptoJS.enc.Base64);
const decrypt2 = CryptoJS.AES.decrypt(encrypted2, key, {
 mode: CryptoJS.mode.ECB,
 padding: CryptoJS.pad.Pkcs7
});

console.log(decrypt2.toString(CryptoJS.enc.Utf8)) // (also tried various other encodings, Utf16, Utf16LE and others)

I've been trying to encrypt and decrypt strings in by AES and C# in an interoperable way. My client application is a Node server that communicates with vendor's API is in dot NET.

The vendor uses these methods for encrypting and decrypting the strings:

public static string Encrypt(string data, string key)
{
  string IV = key.Substring(0, 16);
  byte[] iv = Encoding.UTF8.GetBytes(IV);
  byte[] array;
  using(Aes aes = Aes.Create())
  {
    aes.Key = Encoding.UTF8.GetBytes(key);
    aes.IV = iv;
    ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
    using(MemoryStream memoryStream = new MemoryStream())
    {
      using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
      {
        using(StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
        {
          streamWriter.Write(data);
        }
        array = memoryStream.ToArray();
      }
    }
  }
  return Convert.ToBase64String(array);
}



public static string Decrypt(string data, string key)
{
  string IV = key.Substring(0, 16);
  byte[] iv = Encoding.UTF8.GetBytes(IV);
  byte[] buffer = Convert.FromBase64String(data);
  using(Aes aes = Aes.Create())
  {
    aes.Key = Encoding.UTF8.GetBytes(key);
    aes.IV = iv;
    ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
    using(MemoryStream memoryStream = new MemoryStream(buffer))
    {
      using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
      {
        using(StreamReader streamReader = new StreamReader((Stream)cryptoStream))
        {
          return streamReader.ReadToEnd();
        }
      }
    }
  }
}

I tried for example crypto-js for decrypting the strings, but I cannot make it work:

const encryptedText = CryptoJS.enc.Base64.parse(base64Value)
const encrypted2 = encryptedText.toString(CryptoJS.enc.Base64);
const decrypt2 = CryptoJS.AES.decrypt(encrypted2, key, {
 mode: CryptoJS.mode.ECB,
 padding: CryptoJS.pad.Pkcs7
});

console.log(decrypt2.toString(CryptoJS.enc.Utf8)) // (also tried various other encodings, Utf16, Utf16LE and others)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

此生挚爱伱 2025-02-11 06:39:03

以下Node.js代码应与您的.NET代码正确使用。

我们使用算法AES-256-CBC来匹配C#示例中使用的模式。

const crypto = require("crypto");
const Algorithm = "aes-256-cbc";

function encrypt(plainText, key, iv, outputEncoding = "base64") {
    const cipher = crypto.createCipheriv(Algorithm, key, iv);
    const output = Buffer.concat([cipher.update(plainText), cipher.final()]).toString(outputEncoding);
    return output.replace('+', '-').replace('/', '_').replace('=', '');
}

function decrypt(cipherText, key, iv, outputEncoding = "utf8") {
    cipherText = Buffer.from(cipherText, "base64");
    const cipher = crypto.createDecipheriv(Algorithm, key, iv);
    return Buffer.concat([cipher.update(cipherText), cipher.final()]).toString(outputEncoding);
}

const KEY = 'KFmnMAPzP!g@6Dy5HD?JSgYC9obE&m@m';
const IV = KEY.slice(0,16);

// Taking the output from our C# sample...
const encrypted = 'SORoNS48u0KniiANU3Y9Mw==';
console.log("Encrypted (base64):", encrypted);
const decrypted = decrypt(encrypted, KEY, IV)
console.log("Decrypted:", decrypted);

等效c#代码如下:

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
                    
public class Program
{
    public static void Main()
    {
        var str = Encrypt("test", "KFmnMAPzP!g@6Dy5HD?JSgYC9obE&m@m");
        Console.WriteLine("Encrypted: " + str);
        Console.WriteLine("Decrypted: " + Decrypt(str, "KFmnMAPzP!g@6Dy5HD?JSgYC9obE&m@m"));
    }
    
    public static string Encrypt(string data, string key)
    {
      string IV = key.Substring(0, 16);
      byte[] iv = Encoding.UTF8.GetBytes(IV);
      byte[] array;
      using(Aes aes = Aes.Create())
      {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;
        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
        using(MemoryStream memoryStream = new MemoryStream())
        {
          using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
          {
            using(StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
            {
              streamWriter.Write(data);
            }
            array = memoryStream.ToArray();
          }
        }
      }
      return Convert.ToBase64String(array);
    }



    public static string Decrypt(string data, string key)
    {
      string IV = key.Substring(0, 16);
      byte[] iv = Encoding.UTF8.GetBytes(IV);
      byte[] buffer = Convert.FromBase64String(data);
      using(Aes aes = Aes.Create())
      {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;
        ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
        using(MemoryStream memoryStream = new MemoryStream(buffer))
        {
          using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
          {
            using(StreamReader streamReader = new StreamReader((Stream)cryptoStream))
            {
              return streamReader.ReadToEnd();
            }
          }
        }
      }
    }
}

C#代码的输出是:

 Encrypted: SORoNS48u0KniiANU3Y9Mw==
 Decrypted: test

Node.js代码,然后解密此(使用相同的密钥和IV):

 Encrypted (base64): SORoNS48u0KniiANU3Y9Mw=
 Decrypted: test

The following Node.js code should work correctly with your .NET code.

We're using the algorithm aes-256-cbc to match the mode used in the C# example.

const crypto = require("crypto");
const Algorithm = "aes-256-cbc";

function encrypt(plainText, key, iv, outputEncoding = "base64") {
    const cipher = crypto.createCipheriv(Algorithm, key, iv);
    const output = Buffer.concat([cipher.update(plainText), cipher.final()]).toString(outputEncoding);
    return output.replace('+', '-').replace('/', '_').replace('=', '');
}

function decrypt(cipherText, key, iv, outputEncoding = "utf8") {
    cipherText = Buffer.from(cipherText, "base64");
    const cipher = crypto.createDecipheriv(Algorithm, key, iv);
    return Buffer.concat([cipher.update(cipherText), cipher.final()]).toString(outputEncoding);
}

const KEY = 'KFmnMAPzP!g@6Dy5HD?JSgYC9obE&m@m';
const IV = KEY.slice(0,16);

// Taking the output from our C# sample...
const encrypted = 'SORoNS48u0KniiANU3Y9Mw==';
console.log("Encrypted (base64):", encrypted);
const decrypted = decrypt(encrypted, KEY, IV)
console.log("Decrypted:", decrypted);

The equivalent C# code is below:

using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
                    
public class Program
{
    public static void Main()
    {
        var str = Encrypt("test", "KFmnMAPzP!g@6Dy5HD?JSgYC9obE&m@m");
        Console.WriteLine("Encrypted: " + str);
        Console.WriteLine("Decrypted: " + Decrypt(str, "KFmnMAPzP!g@6Dy5HD?JSgYC9obE&m@m"));
    }
    
    public static string Encrypt(string data, string key)
    {
      string IV = key.Substring(0, 16);
      byte[] iv = Encoding.UTF8.GetBytes(IV);
      byte[] array;
      using(Aes aes = Aes.Create())
      {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;
        ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
        using(MemoryStream memoryStream = new MemoryStream())
        {
          using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
          {
            using(StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
            {
              streamWriter.Write(data);
            }
            array = memoryStream.ToArray();
          }
        }
      }
      return Convert.ToBase64String(array);
    }



    public static string Decrypt(string data, string key)
    {
      string IV = key.Substring(0, 16);
      byte[] iv = Encoding.UTF8.GetBytes(IV);
      byte[] buffer = Convert.FromBase64String(data);
      using(Aes aes = Aes.Create())
      {
        aes.Key = Encoding.UTF8.GetBytes(key);
        aes.IV = iv;
        ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
        using(MemoryStream memoryStream = new MemoryStream(buffer))
        {
          using(CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
          {
            using(StreamReader streamReader = new StreamReader((Stream)cryptoStream))
            {
              return streamReader.ReadToEnd();
            }
          }
        }
      }
    }
}

The output for the C# code is:

 Encrypted: SORoNS48u0KniiANU3Y9Mw==
 Decrypted: test

The Node.js code then decrypts this (using the same key and IV):

 Encrypted (base64): SORoNS48u0KniiANU3Y9Mw=
 Decrypted: test
屋顶上的小猫咪 2025-02-11 06:39:03

由于您使用的是nodejs,因此使用nodejs的加密模块而不是加密j(请参阅其他答案)。当然,Cryptojs也是可能的。然后必须考虑以下内容:

在JavaScript代码中,必须使用CBC模式,并且必须以WordArray cryptojs.aes.decrypt()()将键和IV传递给键和IV。 。可以传递base64编码的密文,隐式将其转换为cipherparams对象。

默认情况下,CryptoJS应用CBC和PKCS#7填充,因此不需要明确指定这些填充物(当然可以)。

以下示例中的密文是使用C#代码生成的,可以使用以下cryptojs代码进行解密:

const ciphertext = 'yKiV9TBw3eNt2QvK1kdXaw=='; 
const keyStr = "01234567890123456789012345678901"; // 32 bytes -> AES-256
const key = CryptoJS.enc.Utf8.parse(keyStr);
const IV = CryptoJS.enc.Utf8.parse(keyStr.substr(0, 16));
const decrypted = CryptoJS.AES.decrypt(ciphertext, key, {iv: IV}); // apply default: CBC and PKCS#7 padding

console.log(decrypted.toString(CryptoJS.enc.Utf8)); // Hello world!
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

关于安全:
将键(或其中的一部分)与IV一起使用是不安全的。相反,应为每个加密生成一个随机静脉输液。这不是秘密,并与密文一起通过,通常是串联的。
此外,从文本中生成键也会降低安全性(即使使用正确的尺寸,值范围也会降低)。如果涉及文本/密码,则更安全的是使用可靠的密钥推导函数,例如PBKDF2。

Since you are using NodeJS, it makes sense to use the crypto module of NodeJS instead of CryptoJS (see the other answer). CryptoJS is of course also possible. Then the following must be considered:

In the JavaScript code, CBC mode has to be used, and key and IV must be passed as WordArray to CryptoJS.AES.decrypt(). The ciphertext can be passed Base64 encoded, CryptoJS implicitly converts this to a CipherParams object.

CryptoJS applies CBC and PKCS#7 padding by default, so these do not need to be explicitly specified (but may of course).

The ciphertext in the following example was generated with the C# code and can be decrypted with the following CryptoJS code:

const ciphertext = 'yKiV9TBw3eNt2QvK1kdXaw=='; 
const keyStr = "01234567890123456789012345678901"; // 32 bytes -> AES-256
const key = CryptoJS.enc.Utf8.parse(keyStr);
const IV = CryptoJS.enc.Utf8.parse(keyStr.substr(0, 16));
const decrypted = CryptoJS.AES.decrypt(ciphertext, key, {iv: IV}); // apply default: CBC and PKCS#7 padding

console.log(decrypted.toString(CryptoJS.enc.Utf8)); // Hello world!
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

Regarding security:
It's insecure to use the key (or a part of it) as IV. Instead, a random IV should be generated for each encryption. This is not secret and is passed together with the ciphertext, in general concatenated.
Also the generation of the key from a text reduces security (even with correct size the value range is reduced). More secure would be to use a reliable key derivation function like PBKDF2 if a text/passphrase is involved.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文