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 相关文章推荐
jQuery 可以拖动的div实现代码 脚本之家修正版
Jun 26 Javascript
jQuery实现在textarea指定位置插入字符或表情的方法
Mar 11 Javascript
JavaScript函数学习总结以及相关的编程习惯指南
Nov 16 Javascript
jQuery获得字体颜色16位码的方法
Feb 20 Javascript
数组Array的排序sort方法
Feb 17 Javascript
Ionic项目中Native Camera的使用方法
Jun 07 Javascript
js实现随机点名小功能
Aug 17 Javascript
关于react中组件通信的几种方式详解
Dec 10 Javascript
vue2.0获取鼠标位置的方法
Sep 13 Javascript
Vue v-bind动态绑定class实例方法
Jan 15 Javascript
js实现简单的秒表
Jan 16 Javascript
vue 通过绑定事件获取当前行的id操作
Jul 27 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
?生?D片??C字串
2006/12/06 PHP
php自动跳转中英文页面
2008/07/29 PHP
AJAX的跨域访问-两种有效的解决方法介绍
2013/06/22 PHP
smarty表格换行实例
2014/12/15 PHP
PHP中require和include路径问题详解
2014/12/25 PHP
php判断访问IP的方法
2015/06/19 PHP
JavaScript 图像动画的小demo
2012/05/23 Javascript
JQuery的自定义事件代码,触发,绑定简单实例
2013/08/01 Javascript
关于javascript event flow 的一个bug详解
2013/09/17 Javascript
jQuery模拟点击A标记示例参考
2014/04/17 Javascript
js清空form表单中的内容示例
2014/05/20 Javascript
一个支付页面DEMO附截图
2014/07/22 Javascript
javascript实现日期按月份加减
2015/05/15 Javascript
js实现文本框宽度自适应文本宽度的方法
2015/08/13 Javascript
ionic js 模型 $ionicModal 可以遮住用户主界面的内容框
2016/06/06 Javascript
js拖拽功能实现代码解析
2016/11/28 Javascript
vue-cli+webpack在生成的项目中使用bootstrap实例代码
2017/05/26 Javascript
微信小程序下拉刷新界面的实现
2017/09/28 Javascript
vue 系列——vue2-webpack2框架搭建踩坑之路
2017/12/22 Javascript
JavaScript实现微信号随机切换代码
2018/03/09 Javascript
在vue项目中引入vue-beauty操作方法
2019/02/11 Javascript
JS中数组实现代码(倒序遍历数组,数组连接字符串)
2019/12/29 Javascript
微信小程序订阅消息(java后端实现)开发
2020/06/01 Javascript
vue 项目@change多个参数传值多个事件的操作
2021/01/29 Vue.js
Tornado协程在python2.7如何返回值(实现方法)
2017/06/22 Python
django配置连接数据库及原生sql语句的使用方法
2019/03/03 Python
python分布式计算dispy的使用详解
2019/12/22 Python
Python如何输出警告信息
2020/07/30 Python
纯CSS3打造属于自己的“小黄人”
2016/03/14 HTML / CSS
ROSEFIELD手表荷兰官方网上商店:北欧极简设计女士腕表品牌
2018/01/24 全球购物
JVM是一个编译程序还是解释程序
2012/09/11 面试题
《神奇的克隆》教学反思
2014/04/10 职场文书
门市房租房协议书
2014/12/04 职场文书
Vue3中的Refs和Ref详情
2021/11/11 Vue.js
vue+elementUI实现表格列的显示与隐藏
2022/04/13 Vue.js
使用python绘制横竖条形图
2022/04/21 Python