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 相关文章推荐
自用js开发框架小成 学习js的朋友可以看看
Nov 16 Javascript
JavaScript运行机制之事件循环(Event Loop)详解
Oct 10 Javascript
兼容各大浏览器的JavaScript阻止事件冒泡代码
Jul 09 Javascript
JavaScript实现的浮动层框架用法实例分析
Oct 10 Javascript
使用JQuery实现的分页插件分享
Nov 05 Javascript
bootstrap日期插件daterangepicker使用详解
Oct 19 Javascript
JavaScript实现树的遍历算法示例【广度优先与深度优先】
Oct 26 Javascript
vue的常用组件操作方法应用分析
Apr 13 Javascript
基于vue循环列表时点击跳转页面的方法
Aug 31 Javascript
ng-zorro-antd 入门初体验
Dec 03 Javascript
详解Vue.js v-for不支持IE9的解决方法
Dec 29 Javascript
p5.js实现动态图形临摹
Oct 23 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 服务器配置(使用Apache及IIS两种方法)
2009/06/01 PHP
php数组添加与删除单元的常用函数实例分析
2015/02/16 PHP
用JavaScript隐藏控件的方法
2009/09/21 Javascript
js同比例缩放图片的小例子
2013/10/30 Javascript
为Javascript中的String对象添加去除左右空格的方法(示例代码)
2013/11/30 Javascript
JavaScript字符串对象slice方法入门实例(用于字符串截取)
2014/10/16 Javascript
JavaScript获取网页中第一个链接ID的方法
2015/04/03 Javascript
Vue.js学习笔记之 helloworld
2016/08/14 Javascript
js判断价格,必须为数字且不能为负数的实现方法
2016/10/07 Javascript
js实现对table的增加行和删除行的操作方法
2016/10/13 Javascript
利用jQuery来动态为属性添加或者删除属性的简单方法
2016/12/02 Javascript
Babel 入门教程学习笔记
2018/06/13 Javascript
JavaScript引用类型Function实例详解
2018/08/09 Javascript
微信小程序scroll-view横向滑动嵌套for循环的示例代码
2018/09/20 Javascript
使用wxapp-img-loader自定义组件实现微信小程序图片预加载功能
2018/10/18 Javascript
详解mpvue中小程序自定义导航组件开发指南
2019/02/11 Javascript
JavaScript实现的联动菜单特效示例
2019/07/08 Javascript
JavaScript计算出两个数的差值
2020/03/19 Javascript
vue项目在线上服务器访问失败原因分析
2020/08/14 Javascript
详解三种方式在React中解决绑定this的作用域问题并传参
2020/08/18 Javascript
vue实现div可拖动位置也可改变盒子大小的原理
2020/09/16 Javascript
vue.js+element 默认提示中英文操作
2020/11/11 Javascript
[01:09:20]NB vs NAVI Supermajor小组赛A组 BO3 第二场 6.2
2018/06/03 DOTA
python连接mongodb操作数据示例(mongodb数据库配置类)
2013/12/31 Python
scrapy自定义pipeline类实现将采集数据保存到mongodb的方法
2015/04/16 Python
python 写入csv乱码问题解决方法
2016/10/23 Python
[原创]使用豆瓣提供的国内pypi源
2017/07/02 Python
pyqt5 从本地选择图片 并显示在label上的实例
2019/06/13 Python
matlab中二维插值函数interp2的使用详解
2020/04/22 Python
Python过滤序列元素的方法
2020/07/31 Python
PyCharm 2020.1版安装破解注册码永久激活(激活到2089年)
2020/09/24 Python
html5绘制时钟动画
2014/12/15 HTML / CSS
世界上最大的专业美容用品零售商:Sally Beauty
2017/07/02 全球购物
项目经理岗位职责
2013/11/11 职场文书
母婴店促销方案
2014/03/05 职场文书
中学总务处工作总结
2015/08/12 职场文书