記一次在node.js中使用crypto的createCipheriv方法進行加密時所遇到的坑


  Node.js的crypto模塊提供了一組包括對OpenSSL的哈希、HMAC、加密、解密、簽名,以及驗證等一整套功能的封裝。具體的使用方法可以參考這篇文章中的描述:node.js_crypto模塊

  本文重點介紹在使用createCipheriv方法時所遇到的坑。對應的解密算法createDecipheriv應該是一樣的問題。

  按照文檔中的描述,createCipheriv方法接受三個參數:algorithm用於指定加密算法,如aes-128-ecb、aes-128-cbc等;key是用於加密的密鑰;iv參數可選,用於指定加密時所用的向量。注意這里的密鑰必須是8/16/32位,如果加密算法是128,則對應的密鑰是16位,如果加密算法是256,則對應的密鑰是32位。代碼如下:

const crypto = require("crypto");

function encrypt (key, iv, data) {
    let decipher = crypto.createCipheriv('aes-128-cbc', key, iv);
    // decipher.setAutoPadding(true);
    return decipher.update(data, 'binary', 'base64') + decipher.final('base64');
}

function decrypt (key, iv, crypted) {
     crypted = new Buffer(crypted, 'base64').toString('binary');
     let decipher = crypto.createDecipheriv('aes-128-cbc', key, iv);
     return decipher.update(crypted, 'binary', 'utf8') + decipher.final('utf8');
}

  下面是測試結果:

let key = '123456789abcdefg';
console.log('加密的key:', key);
let iv = 'abcdefg123456789';
console.log('加密的iv:', iv);
let data = "This is an example";
console.log("需要加密的數據:", data);
let crypted = encrypt(key, iv, data);
console.log("數據加密后:", crypted);
let dec = decrypt(key, iv, crypted);
console.log("數據解密后:", dec);

  以上加密和解密的算法在node.js中運行沒有問題。但如果服務端用的不是node.js,而是Java、C#或者C語言編寫的服務,則用node.js加密之后的結果在服務端驗證無法通過。究其原因可能是因為node.js在實現createCipheriv的算法上與其它語言有差異,而這個差異也可能體現在編碼格式上。在上述node.js代碼中,無論如何修改encrypt函數中update()和final()方法的參數,例如改為"utf8"、"hex",或者將傳入的參數改為buffer等,雖然得出的加密結果會有區別,但是服務端驗證都會失敗。

  在多次嘗試失敗后,我們只能認定node.js中的crypto模塊與其它語言中的實現存在差異。所以我們不得已選擇其它的開源包來替換node.js中的crypto模塊。經過嘗試,aes-js包是個不錯的選擇。按照文檔中的描述,我們將上面node.js中的encrypt函數修改為:

const aesjs = require('aes-js');

function encrypt (key, iv, data) {
    let aesCbc = new aesjs.ModeOfOperation.cbc(aesjs.utils.utf8.toBytes(key), aesjs.utils.utf8.toBytes(iv));
    let encryptedBytes = aesCbc.encrypt(aesjs.utils.utf8.toBytes(data));
    return aesjs.utils.hex.fromBytes(encryptedBytes);
}

function decrypt (key, iv, crypted) {
    let aesCbc = new aesjs.ModeOfOperation.cbc(aesjs.utils.utf8.toBytes(key), aesjs.utils.utf8.toBytes(iv));
    let encryptedBytes = aesCbc.decrypt(aesjs.utils.hex.toBytes(crypted));
    return aesjs.utils.utf8.fromBytes(encryptedBytes);
}

  上面這段代碼要求加密的數據是16位,測試結果如下:

let key = '123456789abcdefg';
console.log('加密的key:', key);
let iv = 'abcdefg123456789';
console.log('加密的iv:', iv);
let data = "Thisisanexample.";
console.log("需要加密的數據:", data);
let crypted = encrypt(key, iv, data);
console.log("數據加密后:", crypted);
let dec = decrypt(key, iv, crypted);
console.log("數據解密后:", dec);

  采用aes-js計算得到的加密結果可以通過服務端的驗證。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM