赞
踩
如果不是跟c++对接,很多加密算法搞成java的人是很不容易接触到的,因为只需要调用jar就可以了。但是node侧就需要自己实现一些了
1 ECB算法
下面的算法正常貌似没有什么问题,但实际在解密的时候,经常出现有些c++加密的数据,在js侧却解不出来。
const CryptoJS = require('crypto-js');
const mode = CryptoJS.mode.ECB
const padding = CryptoJS.pad.NoPadding
/**
* 解密方法
* @param: str 需要解密的字符
* @param: key 密钥
* @param: iv 密钥偏移量
*/
function decrypt(str, key, iv) {
const keyStr = key ? encParse(key) : encParse(defaultKey);
const ivStr = iv ? encParse(iv) : encParse(defaultIv);
// 判断str是否为base64,如果不是就要转base64,是了就不能再转
const flag = isBase64(str);
if (!flag) {
// 转为base64之前要先转16进制
str = CryptoJS.enc.Hex.parse(str);
// 只有base64格式的字符才能被解密
str = CryptoJS.enc.Base64.stringify(str);
}
const encryptedStr = CryptoJS.AES.decrypt(str, keyStr, {
// iv: ivStr,
mode: mode,
padding: padding
});
return encryptedStr.toString(CryptoJS.enc.Utf8);
}
/**
* 处理密钥字符格式
* @param: key 需要转格式的字符
*/
function encParse(key) {
return CryptoJS.enc.Utf8.parse(key);
// return CryptoJS.enc.Latin1.parse(key);
}
但在C++后台对接的时候,9条数据,有两条解密不了提示,这是什么原因呢?
VM2109 WAService.js:2 Error: Malformed UTF-8 data
at Object.stringify (tripledes.js:450)
at WordArray.init.toString (tripledes.js:205)
at Object.decrypt (aes_util.js? [sm]:100)
at Ze.jiemi (index.js? [sm]:53)
at Object.o.safeCallback (VM2109 WAService.js:2)
at VM2109 WAService.js:2
at s (VM2109 WAService.js:2)
at VM2109 WAService.js:2
at v (VM2109 WAService.js:2)
at VM2109 WAService.js:2(env: Windows,mp,1.06.2206090; lib: 2.17.0)
使用AES在线,是可以解密的
使用crypto-js
不行,这个js库还是有关系,这个js端无法处理,只能从源头开始处理,将·回车键(换行符)
去掉后,再加密后,传到前端,问题就可以解决了
今天想到一种更好的解决办法,灵感来自微信小程序解密手机号的cbc算法。
function decrypt(str, key, iv) {
iv = iv || "";
var clearEncoding = 'utf8';
var cipherEncoding = 'base64';
var cipherChunks = [];
var decipher = crypto.createDecipheriv('aes-256-ecb', key, iv);
decipher.setAutoPadding(false);
cipherChunks.push(decipher.update(str, cipherEncoding, clearEncoding));
cipherChunks.push(decipher.final(clearEncoding));
let decoded = cipherChunks.join('');
return decoded.toString(CryptoJS.enc.Utf8)
}
使用crypto
是有权限的,应该是node的内置模块,如果跨平台,则不行,于是调整如下
function decrypt(str, key, iv) {
key = CryptoJS.enc.Utf8.parse(key || defaultKey); // defaultKey应该是一个UTF-8编码的字符串
iv = iv || ""; // ECB模式不需要IV,但这里为了保持一致还是保留
// const str = yourEncryptedString; // base64编码的密文
// CryptoJS默认使用PKCS7填充,所以不需要显式设置setAutoPadding(false)
// 但如果你确实需要禁用自动填充(这通常不推荐),你将需要手动处理填充
// 解密
const bytes = CryptoJS.AES.decrypt({
ciphertext: CryptoJS.enc.Base64.parse(str) // 解析base64编码的密文
}, key, {
mode: CryptoJS.mode.ECB, // 注意:ECB模式通常被认为是不安全的
padding: CryptoJS.pad.Pkcs7 // CryptoJS默认使用PKCS7填充
});
// 获取解密后的字符串
const decoded = bytes.toString(CryptoJS.enc.Utf8); // 转换为UTF-8编码的字符串
// 返回解密后的字符串
return decoded;
}
2 CBC算法
这个是微信小程序官方解密手机号的写法,依然是要安装crypto-js
,看来crypto-js
以来crypto
var crypto = require('crypto')
function WXBizDataCrypt(appId, sessionKey) {
this.appId = appId
this.sessionKey = sessionKey
}
WXBizDataCrypt.prototype.decryptData = function (encryptedData, iv) {
// base64 decode
var sessionKey = new Buffer(this.sessionKey, 'base64')
encryptedData = new Buffer(encryptedData, 'base64')
iv = new Buffer(iv, 'base64')
try {
// 解密
var decipher = crypto.createDecipheriv('aes-128-cbc', sessionKey, iv)
// 设置自动 padding 为 true,删除填充补位
decipher.setAutoPadding(true)
var decoded = decipher.update(encryptedData, 'binary', 'utf8')
decoded += decipher.final('utf8')
decoded = JSON.parse(decoded)
} catch (err) {
throw new Error('Illegal Buffer')
}
if (decoded.watermark.appid !== this.appId) {
throw new Error('Illegal Buffer')
}
return decoded
}
module.exports = WXBizDataCrypt
3 3DES 2倍长
nodejs实现3des(2倍长)加密方式,与DES加密工具一致
这里稍作了改动,它的程序实际应用有点小问题
const crypto = require('crypto');
const tools = require('./cgw');
const algorithm = { ecb: 'des-ecb' }
function encrypt(plaintext, keytext) {
let key = new Uint8Array(keytext);
let iv = new Uint8Array("");
let txt = new Uint8Array(plaintext)
let cipher = crypto.createCipheriv(algorithm.ecb, key, iv);
cipher.setAutoPadding(true);
let ciph = cipher.update(txt);
return ciph;
}
function decrypt(encrypttext, keytext) {
let key = new Uint8Array(keytext);
let iv = new Uint8Array("");
let txt = new Uint8Array(encrypttext);
let decipher = crypto.createDecipheriv(algorithm.ecb, key, iv);
decipher.setAutoPadding(true);
decipher.update(txt);
let ciph = decipher.update(txt);
return ciph;
}
/**
* 补00
* @param {*} p
*/
function fillZero(p){
let nAddCount = (16-p.length%16)/2;
for (let i=0; i<nAddCount; i++){
p += '00';
}
return p;
}
/**
* 规则是先加80,后面凑齐16的整数倍补00
* 3DES双倍长
* @param {*} src
* @param {*} key
*/
function encrypt3Des(src, key) {
src = tools.StringToAscii(src)+'80'
src = fillZero(src)
let temp = null;
let temp1 = null;
temp1 = encrypt(tools.HexStringToBytes(src), tools.HexStringToBytes(key.substring(0, 16)));
temp = decrypt(temp1, tools.HexStringToBytes(key.substring(16, 32)));
temp1 = encrypt(temp, tools.HexStringToBytes(key.substring(0, 16)));
return tools.BytesToHexString(temp1);
}
function decrypt3Des(src, key) {
let temp = null;
let temp1 = null;
temp1 = decrypt(tools.HexStringToBytes(src), tools.HexStringToBytes(key.substring(0, 16)));
temp = encrypt(temp1, tools.HexStringToBytes(key.substring(16, 32)));
temp1 = decrypt(temp, tools.HexStringToBytes(key.substring(0, 16)));
return tools.BytesToHexString(temp1);
}
export default {
encrypt3Des,
decrypt3Des
}
var bytesToHexString = function (src) {
if (src == null || src.length <= 0) {
return null;
}
let d = "";
for (let i = 0; i < src.length; i++) {
let v = src[i] & 0xFF;
let hv = intTo16value(v);
d += hv;
}
let strs = []
// 字符串每8位进行分隔
for (let j=0; j<d.length/16; j++){
strs.push(d.slice(j*16,(j+1)*16))
}
//
return strs.reverse().join('')
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。