Node.js中AES加密和其它语言不一致问题解决办法


Posted in Javascript onMarch 10, 2014

例子一:

这几天被一个问题困扰着。Nodejs的AES加密和Java,C#加密出来的不一致。当然,这样就不能解密了。纠结了许久:后来还是实在不行了,看了下源代码,要不然还得继续纠结下去。网上说,通常的nodejs AES和其他语言实现不一样。好吧~~或许吧。
nodejs的crypto模块。

var crypto = require('crypto');
    var data = "156156165152165156156";
    console.log('Original cleartext: ' + data);
    var algorithm = 'aes-128-ecb';
    var key = '78541561566';
    var clearEncoding = 'utf8';
    //var cipherEncoding = 'hex';
    //If the next line is uncommented, the final cleartext is wrong.
    var cipherEncoding = 'base64';
/*加密*/
    var cipher = crypto.createCipher(algorithm, key);
    var cipherChunks = [];
    cipherChunks.push(cipher.update(data, clearEncoding, cipherEncoding));
    cipherChunks.push(cipher.final(cipherEncoding));
    console.log(cipherEncoding + ' ciphertext: ' + cipherChunks.join(''));
/*解密*/
    var decipher = crypto.createDecipher(algorithm, key);
    var plainChunks = [];
    for (var i = 0;i < cipherChunks.length;i++) {
      plainChunks.push(decipher.update(cipherChunks[i], cipherEncoding, clearEncoding));
    }
    plainChunks.push(decipher.final(clearEncoding));
    console.log("UTF8 plaintext deciphered: " + plainChunks.join(''));

的确,没错~~加密解密成功。但是和java,C#中加密出来的不一样啊。神啊。我想,大家都在这里纠结着吧~~对不对。其实只要加个向量,就可以和一致了。网上搜索出来的资源太少。才让自己纠结那么久。好吧,正确代码是:
var crypto = require('crypto');
    var data = "156156165152165156156";
    console.log('Original cleartext: ' + data);
    var algorithm = 'aes-128-ecb';
    var key = '78541561566';
    var clearEncoding = 'utf8';
    var iv = "";
    //var cipherEncoding = 'hex';
    //If the next line is uncommented, the final cleartext is wrong.
    var cipherEncoding = 'base64';
    var cipher = crypto.createCipheriv(algorithm, key,iv);
    var cipherChunks = [];
    cipherChunks.push(cipher.update(data, clearEncoding, cipherEncoding));
    cipherChunks.push(cipher.final(cipherEncoding));
    console.log(cipherEncoding + ' ciphertext: ' + cipherChunks.join(''));
    var decipher = crypto.createDecipheriv(algorithm, key,iv);
    var plainChunks = [];
    for (var i = 0;i < cipherChunks.length;i++) {
      plainChunks.push(decipher.update(cipherChunks[i], cipherEncoding, clearEncoding));
    }
    plainChunks.push(decipher.final(clearEncoding));
    console.log("UTF8 plaintext deciphered: " + plainChunks.join(''));

对比发现,加密出来是一致的。好吧,结贴~~~我恨你,浪费了我一天时间。

例子二:

工作中遇到nodejs端通过aes加密,安卓客户端java解密,同意nodejs也需要解密安卓客户端加密过来的内容,发现两个加密结果不一样,查询资料发现java端需要对密钥za再MD5加密一遍,以下是aes ecb加密的内容,如果是cbc也同样需要对秘钥MD5加密:

nodejs:

/** 
 * aes加密 
 * @param data 
 * @param secretKey 
 */  
encryptUtils.aesEncrypt = function(data, secretKey) {  
    var cipher = crypto.createCipher('aes-128-ecb',secretKey);  
    return cipher.update(data,'utf8','hex') + cipher.final('hex');  
}  /** 
 * aes解密 
 * @param data 
 * @param secretKey 
 * @returns {*} 
 */  
encryptUtils.aesDecrypt = function(data, secretKey) {  
    var cipher = crypto.createDecipher('aes-128-ecb',secretKey);  
    return cipher.update(data,'hex','utf8') + cipher.final('utf8');  
} 

java:
package com.iofamily.util;  import java.security.MessageDigest;  
import javax.crypto.Cipher;  
import javax.crypto.spec.SecretKeySpec;  
/** 
 * AES加密,与Nodejs 保持一致 
 * @author lmiky 
 * @date 2014-2-25 
 */  
public class AESForNodejs {  
    public static final String DEFAULT_CODING = "utf-8";  
    /** 
     * 解密 
     * @author lmiky 
     * @date 2014-2-25 
     * @param encrypted 
     * @param seed 
     * @return 
     * @throws Exception 
     */  
    private static String decrypt(String encrypted, String seed) throws Exception {  
        byte[] keyb = seed.getBytes(DEFAULT_CODING);  
        MessageDigest md = MessageDigest.getInstance("MD5");  
        byte[] thedigest = md.digest(keyb);  
        SecretKeySpec skey = new SecretKeySpec(thedigest, "AES");  
        Cipher dcipher = Cipher.getInstance("AES");  
        dcipher.init(Cipher.DECRYPT_MODE, skey);  
        byte[] clearbyte = dcipher.doFinal(toByte(encrypted));  
        return new String(clearbyte);  
    }  
    /** 
     * 加密 
     * @author lmiky 
     * @date 2014-2-25 
     * @param content 
     * @param key 
     * @return 
     * @throws Exception 
     */  
    public static String encrypt(String content, String key) throws Exception {  
        byte[] input = content.getBytes(DEFAULT_CODING);  
        MessageDigest md = MessageDigest.getInstance("MD5");  
        byte[] thedigest = md.digest(key.getBytes(DEFAULT_CODING));  
        SecretKeySpec skc = new SecretKeySpec(thedigest, "AES");  
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");  
        cipher.init(Cipher.ENCRYPT_MODE, skc);  
        byte[] cipherText = new byte[cipher.getOutputSize(input.length)];  
        int ctLength = cipher.update(input, 0, input.length, cipherText, 0);  
        ctLength += cipher.doFinal(cipherText, ctLength);  
        return parseByte2HexStr(cipherText);  
    }  
    /** 
     * 字符串转字节数组 
     * @author lmiky 
     * @date 2014-2-25 
     * @param hexString 
     * @return 
     */  
    private static byte[] toByte(String hexString) {  
        int len = hexString.length() / 2;  
        byte[] result = new byte[len];  
        for (int i = 0; i < len; i++) {  
            result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2), 16).byteValue();  
        }  
        return result;  
    }  
    /** 
     * 字节转16进制数组 
     * @author lmiky 
     * @date 2014-2-25 
     * @param buf 
     * @return 
     */  
    private static String parseByte2HexStr(byte buf[]) {  
        StringBuffer sb = new StringBuffer();  
        for (int i = 0; i < buf.length; i++) {  
            String hex = Integer.toHexString(buf[i] & 0xFF);  
            if (hex.length() == 1) {  
                hex = '0' + hex;  
            }  
            sb.append(hex);  
        }  
        return sb.toString();  
    }  
    public static void main(String[] args) throws Exception {  
        System.out.println(AESForNodejs.encrypt("fsadfsdafsdafsdafsadfsadfsadf", "1234fghjnmlkiuhA"));  
        System.out.println(AESForNodejs.decrypt("5b8e85b7a86ad15a275a7cb61fe4c0606005e8741f68797718a3e90d74b5092a", "1234fghjnmlkiuhA"));  
    }  
}
Javascript 相关文章推荐
Javascript 两个窗体之间传值实现代码
Sep 25 Javascript
jQuery对象和DOM对象的相互转化实现代码
Mar 02 Javascript
js 操作select和option常用代码整理
Dec 13 Javascript
jQuery的控件及事件(输入控件及回车事件)使用示例
Jul 25 Javascript
jquery实现上下左右滑动的方法
Feb 09 Javascript
JavaScript数据结构和算法之二叉树详解
Feb 11 Javascript
Bootstrap中CSS的使用方法
Feb 17 Javascript
利用JS实现文字的聚合动画效果
Jan 22 Javascript
ES6中Array.find()和findIndex()函数的用法详解
Sep 16 Javascript
promise和co搭配生成器函数方式解决js代码异步流程的比较
May 25 Javascript
Vue Promise的axios请求封装详解
Aug 13 Javascript
JS中锚点链接点击平滑滚动并自由调整到顶部位置
Feb 06 Javascript
JS中的构造函数详细解析
Mar 10 #Javascript
node.js使用nodemailer发送邮件实例
Mar 10 #Javascript
php中给js数组赋值方法
Mar 10 #Javascript
javascript操作referer详细解析
Mar 10 #Javascript
JS数组的赋值介绍
Mar 10 #Javascript
JS删除字符串中重复字符方法
Mar 09 #Javascript
用JavaScript实现类似于ListBox功能示例代码
Mar 09 #Javascript
You might like
PHP源码分析之变量的存储过程分解
2014/07/03 PHP
PHP中each与list用法分析
2016/01/08 PHP
php面向对象之反射功能与用法分析
2017/03/29 PHP
谷歌浏览器 insertCell与appendChild的区别
2009/02/12 Javascript
Javascript 网页黑白效果实现代码(兼容IE/FF等)
2010/04/23 Javascript
JQuery 拾色器插件发布-jquery.icolor.js
2010/10/20 Javascript
JQuery获取各种宽度、高度(format函数)实例
2013/03/04 Javascript
Jquery操作radio的简单实例
2014/01/06 Javascript
jquery进行数组遍历如何跳出当前的each循环
2014/06/05 Javascript
jQuery Real Person验证码插件防止表单自动提交
2015/11/06 Javascript
jQuery实现获取绑定自定义事件元素的方法
2015/12/02 Javascript
jQuery实现的placeholder效果完整实例
2016/08/02 Javascript
js Canvas实现的日历时钟案例分享
2016/12/25 Javascript
JavaScript使用delete删除数组元素用法示例【数组长度不变】
2017/01/17 Javascript
微信小程序中使用javascript 回调函数
2017/05/11 Javascript
解决npm管理员身份install时出现权限的问题
2018/03/16 Javascript
小程序实现左滑删除功能
2018/10/30 Javascript
简单通过settimeout看javascript的运行机制
2019/05/10 Javascript
微信小程序 如何获取网络状态
2019/07/26 Javascript
Javascript和jquery在selenium的使用过程
2019/10/31 jQuery
用Python的Django框架来制作一个RSS阅读器
2015/07/22 Python
Python闭包执行时值的传递方式实例分析
2018/06/04 Python
python之文件读取一行一行的方法
2018/07/12 Python
一行代码让 Python 的运行速度提高100倍
2018/10/08 Python
在Python中实现替换字符串中的子串的示例
2018/10/31 Python
Python 文本文件内容批量抽取实例
2018/12/10 Python
利用Python+阿里云实现DDNS动态域名解析的方法
2019/04/01 Python
基于Python批量生成指定尺寸缩略图代码实例
2019/11/20 Python
python可视化 matplotlib画图使用colorbar工具自定义颜色
2020/12/07 Python
HTML5 Canvas——用路径描画线条实例介绍
2013/06/09 HTML / CSS
父亲生日宴会答谢词
2014/01/10 职场文书
电子商务专业学生职业生涯规划
2014/03/07 职场文书
党员专题组织生活会发言材料
2014/10/17 职场文书
公务员个人考察材料
2014/12/23 职场文书
“爱眼护眼,提前预防近视”倡议书3篇
2019/10/30 职场文书
我去timi了,一起去timi是什么意思?
2022/04/13 杂记