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进行拖拽
Jul 20 Javascript
js如何判断不同系统的浏览器类型
Oct 28 Javascript
js跳转页面方法总结
Jan 29 Javascript
JS实现的5级联动Select下拉选择框实例
Aug 17 Javascript
由浅入深讲解Javascript继承机制与simple-inheritance源码分析
Dec 13 Javascript
解决Vue页面固定滚动位置的处理办法
Jul 13 Javascript
深入理解ES6 Promise 扩展always方法
Sep 26 Javascript
vue使用监听实现全选反选功能
Jul 06 Javascript
JS实现的input选择图片本地预览功能示例
Aug 29 Javascript
详解js 创建对象的几种方法
Mar 08 Javascript
Vue Extends 扩展选项用法完整实例
Sep 17 Javascript
Element图表初始大小及窗口自适应实现
Jul 10 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
如何跨站抓取别的站点的页面的补充
2006/10/09 PHP
PHP文件读写操作之文件读取方法详解
2011/01/13 PHP
最新用php获取谷歌PR值算法,附上php查询PR值代码示例
2011/12/25 PHP
微信access_token的获取开发示例
2015/04/16 PHP
php封装的图片(缩略图)处理类完整实例
2016/10/19 PHP
Laravel框架生命周期与原理分析
2018/06/12 PHP
web页面数据展示新想法(json)
2010/06/08 Javascript
JavaScript isArray()函数判断对象类型的种种方法
2010/10/11 Javascript
原生js和jQuery随意改变div属性style的名称和值
2014/10/22 Javascript
windows8.1+iis8.5下安装node.js开发环境
2014/12/12 Javascript
JavaScript多并发问题如何处理
2015/10/28 Javascript
javascript日期验证之输入日期大于等于当前日期
2015/12/13 Javascript
详解jQuery UI库中文本输入自动补全功能的用法
2016/04/23 Javascript
通过原生JS实现为元素添加事件的方法
2016/11/23 Javascript
javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】
2016/12/15 Javascript
nodejs的压缩文件模块archiver用法示例
2017/01/18 NodeJs
JavaScript实现瀑布流图片效果
2017/06/30 Javascript
怎么使用javascript深度拷贝一个数组
2019/06/06 Javascript
vue解决花括号数据绑定不成功的问题
2019/10/30 Javascript
AngularJS动态生成select下拉框的方法实例
2019/11/17 Javascript
[02:55]DOTA2英雄基础教程 发条技师
2013/12/04 DOTA
极简的Python入门指引
2015/04/01 Python
Empty test suite.(PyCharm程序运行错误的解决方法)
2018/11/30 Python
opencv python统计及绘制直方图的方法
2019/01/21 Python
如何用Python制作微信好友个性签名词云图
2019/06/28 Python
python3.8与pyinstaller冲突问题的快速解决方法
2020/01/16 Python
谈一谈数组拼接tf.concat()和np.concatenate()的区别
2020/02/07 Python
Python运行提示缺少模块问题解决方案
2020/04/02 Python
用JAVA SOCKET编程,读服务器几个字符,再写入本地显示
2012/11/25 面试题
XMLHttpRequest对象在IE和Firefox中创建方式有没有不同
2016/03/23 面试题
Python如何定义一个函数
2015/09/01 面试题
机械制造与自动化应届生求职信
2013/11/16 职场文书
发展部经理职责规定
2014/02/22 职场文书
金融管理毕业生求职信
2014/03/03 职场文书
幼儿园六一亲子活动方案
2014/08/26 职场文书
分享MySQL常用 内核 Debug 几种常见方法
2022/03/17 MySQL