在C#上加密和在C#上解密

时间:2018-04-24 11:38:52

标签: c# angular encryption cryptography cryptojs

我有代码来加密Angular上的数据, 但我不知道如何在服务器端解密

distinct count

以角度加密为 var panno = CryptoJS.AES.encrypt("FEAPS8905Q", "myPassword").toString(); , 在使用Http.post方法发送加密后,我无法获取确切数据,而是获取U2FsdGVkX19mi5mXlJ14Lj0XcJBbqMPDzi/UeNXK4Cw=

我也使用了此引用Decrypting on C#,但我收到了一些数据,例如楀뢖᷈鍩ԏ건뫨샞일䜍钚䁞

壓섢⻫捼笺ﵑ戛ꔉ됒퍿誁累♟꘶콒ꚦ

3 个答案:

答案 0 :(得分:1)

在node.js中加密:

    var crypto = require('crypto');
var key = '00000000000000000000000000000000'; //replace with your key
var iv = '0000000000000000'; //replace with your IV
var cipher = crypto.createCipheriv('aes256', key, iv)
var crypted = cipher.update(authorizationKey, 'utf8', 'base64')
crypted += cipher.final('base64');
console.log(crypted);

解密c#

    string keyString = "00000000000000000000000000000000"; //replace with your key
string ivString = "0000000000000000"; //replace with your iv

byte[] key = Encoding.ASCII.GetBytes(keyString);
byte[] iv = Encoding.ASCII.GetBytes(ivString);

using (var rijndaelManaged =
        new RijndaelManaged { Key = key, IV = iv, Mode = CipherMode.CBC })
        {
            rijndaelManaged.BlockSize = 128;
            rijndaelManaged.KeySize = 256;
            using (var memoryStream =
                   new MemoryStream(Convert.FromBase64String(AuthorizationCode)))
            using (var cryptoStream =
                   new CryptoStream(memoryStream,
                       rijndaelManaged.CreateDecryptor(key, iv),
                       CryptoStreamMode.Read))
            {
                return new StreamReader(cryptoStream).ReadToEnd();
            }
        }

来源: https://gsferreira.com/archive/2015/02/how-to-encrypt-in-nodejs-and-decrypt-in-c-sharp/

为我工作!

答案 1 :(得分:0)

CryptoJS.AES.encrypt(text, password)使用派生算法隐式地从您的密码中导出加密密钥和iv,这对于C#来说是非本地的。而不是依赖于隐式推导 - 最好使用众所周知的算法(如PBKDF2)自己明确地做到这一点。

需要密钥派生,因为您的密码可以具有任意大小,但给定算法(AES)需要特定大小的密钥,例如256位。所以我们需要从任意长度的密码到固定大小的密钥(以不可逆转的方式)。

示例javascript代码:

function encrypt (msg, pass) {
  // random salt for derivation
  var keySize = 256;
  var salt = CryptoJS.lib.WordArray.random(16);
  // well known algorithm to generate key
  var key = CryptoJS.PBKDF2(pass, salt, {
      keySize: keySize/32,
      iterations: 100
    });
  // random IV
  var iv = CryptoJS.lib.WordArray.random(128/8);      
  // specify everything explicitly
  var encrypted = CryptoJS.AES.encrypt(msg, key, { 
    iv: iv, 
    padding: CryptoJS.pad.Pkcs7,
    mode: CryptoJS.mode.CBC        
  });
  // combine everything together in base64 string
  var result = CryptoJS.enc.Base64.stringify(salt.concat(iv).concat(encrypted.ciphertext));
  return result;
}

现在很容易在C#中解密:

public static string Decrypt(string cipherText, string password) {
    byte[] cipherBytes = Convert.FromBase64String(cipherText);
    using (Aes encryptor = Aes.Create()) {
        // extract salt (first 16 bytes)
        var salt = cipherBytes.Take(16).ToArray();
        // extract iv (next 16 bytes)
        var iv = cipherBytes.Skip(16).Take(16).ToArray();
        // the rest is encrypted data
        var encrypted = cipherBytes.Skip(32).ToArray();
        Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt, 100);
        encryptor.Key = pdb.GetBytes(32);
        encryptor.Padding = PaddingMode.PKCS7;
        encryptor.Mode = CipherMode.CBC;
        encryptor.IV = iv;
        // you need to decrypt this way, not the way in your question
        using (MemoryStream ms = new MemoryStream(encrypted)) {
            using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Read)) {
                using (var reader = new StreamReader(cs, Encoding.UTF8)) {
                    return reader.ReadToEnd();
                }
            }
        }
    }
}    

如果了解后果,可以使用固定盐(或者在应用程序中为每个用户使用固定盐),并减少PBKDF2中的迭代次数。不要使用固定的IV,也不要使用部分密钥作为IV。

答案 2 :(得分:0)

加密的基本思想是

  • 使用 PBKDF2 生成密钥。
  • 使用 AES 密码进行加密。

您可以在以下位置阅读有关此加密的更多信息:CrytoJs officialdocs

由于解密是在服务器(C#)代码中,我们需要为它提供值,例如-Salt、iv、我们的密码中的加密文本。 为了传递它,我们将所有信息编码为 base64 字符串并将其传递给服务器。

用于 Angular 中的加密-(我的项目在 TS 中) 如果有人有错误如

  • “wordArray 不包含 concat()”
  • 类型“WordArray”不可分配给类型“字符串”

我浏览了一些文档,并找到了能够结合 salt、iv 和密文的解决方案。

问题在于类型,我们需要有所有这 3 种的 WordArray 格式来编码。

我的方法很牵强,但很管用

  • 将所有 LIb.WordArray 转换为 ByteArray,以便将所有 3 个字符串合并为一个。
  • 在编码为 Base64 之前,将组合转换为 WordArray。
  • 现在将此编码字符串发送到服务器以在服务器端提取 salt,iv,encryted 文本以对其进行解密。

确保您的项目中有 @types/crypto-js 和 crypto-js。我的版本("crypto-js": "^4.0.0", "@types/crypto-js": "^3.1.47").

Angular 端 TypeScript 的加密

encrypt(msg: string) {
//will have this at C# as well.
var pass = "secret";
var keySize = 256;
//random salt
var salt = CryptoJS.lib.WordArray.random(16);
// to generate key
var key = CryptoJS.PBKDF2(pass, salt, {
  keySize: keySize / 32,
  iterations: 1000,
});
// random IV
var iv = CryptoJS.lib.WordArray.random(128 / 8);
//will attach link where you can find these
var encrypted = CryptoJS.AES.encrypt(msg, key, {
  iv: iv,
  padding: CryptoJS.pad.Pkcs7,
  mode: CryptoJS.mode.CBC,
});

//Convert Lib.WordArray to ByteArray so we can combine them like Concat
var saltwords = this.wordArrayToByteArray(salt);
var ivwords = this.wordArrayToByteArray(iv);
var cryptedText = this.wordArrayToByteArray(encrypted.ciphertext);
// combine everything together in ByteArray.
var header = saltwords.concat(ivwords).concat(cryptedText);
//Now convert to WordArray.
var headerWords = this.byteArrayToWordArray(header);
//Encode this to sent to server
var encodedString = CryptoJS.enc.Base64.stringify(headerWords);
return encodedString;  
}

类型转换

wordArrayToByteArray(wordArray) {
if (
  wordArray.hasOwnProperty("sigBytes") &&
  wordArray.hasOwnProperty("words")
) {
  length = wordArray.sigBytes;
  wordArray = wordArray.words;
}

var result = [],
  bytes,
  i = 0;
while (length > 0) {
  bytes = this.wordToByteArray(wordArray[i], Math.min(4, length));
  length -= bytes.length;
  result.push(bytes);
  i++;
 }
 return [].concat.apply([], result);
 }
byteArrayToWordArray(ba) {
var wa = [],
  i;
for (i = 0; i < ba.length; i++) {
  wa[(i / 4) | 0] |= ba[i] << (24 - 8 * i);
}

return CryptoJS.lib.WordArray.create(wa);
}
wordToByteArray(word, length) {
 var ba = [],
  xFF = 0xff;
 if (length > 0) ba.push(word >>> 24);
 if (length > 1) ba.push((word >>> 16) & xFF);
 if (length > 2) ba.push((word >>> 8) & xFF);
 if (length > 3) ba.push(word & xFF);

return ba;
}

C# 中的解密 与 EVK 给出的答案中提到的相同。

 public static string Decrypt(string cipherText)
    {
        var password = "secret";
        byte[] cipherBytes = Convert.FromBase64String(cipherText);
        using (Aes encryptor = Aes.Create())
        {
            // extract salt (first 16 bytes)
            var salt = cipherBytes.Take(16).ToArray();
            // extract iv (next 16 bytes)
            var iv = cipherBytes.Skip(16).Take(16).ToArray();
            // the rest is encrypted data
            var encrypted = cipherBytes.Skip(32).ToArray();
            Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(password, salt, 1000);
            encryptor.Key = pdb.GetBytes(32);
            encryptor.Padding = PaddingMode.PKCS7;
            encryptor.Mode = CipherMode.CBC;
            encryptor.IV = iv;

            using (MemoryStream ms = new MemoryStream(encrypted))
            {
                using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Read))
                {
                    using (var reader = new StreamReader(cs, Encoding.UTF8))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
        }
    }