用于 AES CBC 的 CryptoJS 和 CryptoSwift 的加密输出将会有所不同

问题描述 投票:0回答:1

下面是Java脚本代码

var keySize = 256;
var ivSize = 128;
var iterations = 1000;

var message = "Hello World";
var password = "secret";
var ivSfmc = "4963b7334a46352623252955df21d7f3";
var saltSFmc = "e0cf1267f564b362";
var encryptedString = "";

function encrypt(msg, pass) {

    salt = CryptoJS.enc.Hex.parse(saltSFmc);
  iv = CryptoJS.enc.Hex.parse(ivSfmc);

  var key = CryptoJS.PBKDF2(pass, salt, {
    keySize: keySize / 32,
    padding: CryptoJS.pad.Pkcs7,
    iterations: iterations
  });

  var encrypted = CryptoJS.AES.encrypt(msg, key, {
    iv: iv,
    mode: CryptoJS.mode.CBC
  });

  encryptedString = encrypted.toString();
  return encryptedString;
}


function decrypt(transitmessage, pass) {
  iv = CryptoJS.enc.Hex.parse(ivSfmc);
  salt = CryptoJS.enc.Hex.parse(saltSFmc);


  var key = CryptoJS.PBKDF2(pass, salt, {
    keySize: keySize / 32,
    iterations: iterations
  });

  var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
    iv: iv,
    padding: CryptoJS.pad.Pkcs7,
    mode: CryptoJS.mode.CBC

  })
  return decrypted;
}

var encrypted = encrypt(message, password);
var decrypted = decrypt(encryptedString, password);

输出

加密:ndLxNDM5BwSeqNfXAQ5P3g==
解密:你好世界

下面是Swift代码,多次交叉验证等效性,但结果仍然不同

import UIKit
import CryptoSwift

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        do {
            let password: [UInt8] = Array("secret".utf8)
            let salt = Array(hex: "e0cf1267f564b362")

            /* Generate a key from a `password`. Optional if you already have a key */
            let key = try PKCS5.PBKDF2(
                password: password,
                salt: salt,
                iterations: 1000,
                keyLength: 32, /* AES-256 */
                variant: .sha256
            ).calculate()

            /* Generate random IV value. IV is public value. Either need to generate, or get it from elsewhere */
            let iv = Array(hex: "4963b7334a46352623252955df21d7f3")

            /* AES cryptor instance */
            let aes = try AES(key: key, blockMode: CBC(iv: iv), padding: .pkcs7)

            /* Encrypt Data */
            let inputData = Array("Hello World".utf8)
            let encryptedBytes = try aes.encrypt(inputData)
            let encryptedData = Data(encryptedBytes)
            print(encryptedData.base64EncodedString())

            /* Decrypt Data */
            let decryptedBytes = try aes.decrypt(encryptedData.bytes)
            let decryptedData = Data(decryptedBytes)
            print(String(bytes: decryptedData, encoding: .utf8)!)

        } catch ( let error) {
            print(error)
        }
    }
}

输出

加密:n05I/Ub/GC/mzQRmlNTl7w==
解密:你好世界

由于两个级别的加密值不同,我无法解密从 CryptoJS 加密收到的字符串,经过大量试验后我仍然陷入困境,无法理解为什么存在差异,即使两端都使用了确切的值,任何帮助或建议将不胜感激。谢谢!

javascript ios swift encryption aes
1个回答
0
投票

在这两个代码中应用了不同的摘要,这就是密文不同的原因(对于相同的输入数据:salt、IV、消息和密码):

  • 在 CryptoJS 代码中,未明确指定 PBKDF2 的摘要,因此使用 CryptoJS 默认 SHA1。

  • 在 Swift 代码中,PBKDF2 的摘要被显式指定为 SHA256(这也是 CryptoSwift 默认值)。

为了使密文相同,必须使用相同的摘要。


因此,在 CryptoJS 代码中,应用 SHA-256:

...
var key = CryptoJS.PBKDF2(pass, salt, {
    keySize: keySize / 32,
    iterations: iterations,
    hasher: CryptoJS.algo.SHA256    // Fix, default: SHA1
});
...

var keySize = 256;
var ivSize = 128;
var iterations = 1000;

var message = "Hello World";
var password = "secret";
var ivSfmc = "4963b7334a46352623252955df21d7f3";
var saltSFmc = "e0cf1267f564b362";
var encryptedString = "";

function encrypt(msg, pass) {

    var salt = CryptoJS.enc.Hex.parse(saltSFmc);
    var iv = CryptoJS.enc.Hex.parse(ivSfmc);

    var key = CryptoJS.PBKDF2(pass, salt, {
        keySize: keySize / 32,
        iterations: iterations,
        hasher: CryptoJS.algo.SHA256    // Fix, default: SHA1
    });

    var encrypted = CryptoJS.AES.encrypt(msg, key, {
        iv: iv,
        padding: CryptoJS.pad.Pkcs7,    // default
        mode: CryptoJS.mode.CBC             // default
    });

    encryptedString = encrypted.toString();
    return encryptedString;
}


function decrypt(encrypted, pass) {
    var iv = CryptoJS.enc.Hex.parse(ivSfmc);
    var salt = CryptoJS.enc.Hex.parse(saltSFmc);


    var key = CryptoJS.PBKDF2(pass, salt, {
        keySize: keySize / 32,
        iterations: iterations,
        hasher: CryptoJS.algo.SHA256    // Fix, default: SHA1
    });

    var decrypted = CryptoJS.AES.decrypt(encrypted, key, {
        iv: iv,
        padding: CryptoJS.pad.Pkcs7,    // default
        mode: CryptoJS.mode.CBC             // default
    });
    
    return decrypted;
}

var message = "Hello World"
var password = "secret";
var encrypted = encrypt(message, password);
var decrypted = decrypt(encrypted, password);

console.log(encryptedString.toString(CryptoJS.enc.Base64));  // for SHA256:        n05I/Ub/GC/mzQRmlNTl7w==
                                                                                                                         // for SHA1, default: ndLxNDM5BwSeqNfXAQ5P3g==
console.log(decrypted.toString(CryptoJS.enc.Utf8));
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>

或者使用 Swift 代码 SHA1:

...
let key = try PKCS5.PBKDF2(
    password: password,
    salt: salt,
    iterations: 1000,
    keyLength: 32, /* AES-256 */
    variant: .sha1                  // Fix, default: SHA256
).calculate()
...

安全:

使用静态盐和 IV 是漏洞。通常,每次加密都会随机生成 salt 和 IV,与密文(例如 salt|iv|ciphertext)连接并发送到解密方。在那里,它们根据盐和 IV 的商定/已知长度进行分离(请记住,盐和 IV 不是秘密)。
尽管 SHA-1 已被破坏,但在 PBKDF2 的背景下,它并不被认为是不安全的(尽管如此,停止使用此摘要以使其从生态系统中消失是有意义的)。
对于 PBKDF2 来说,1000 次迭代计数通常太低。该值应设置得尽可能高,同时保持可接受的性能。

© www.soinside.com 2019 - 2024. All rights reserved.