crypto-js的使用

如果不是跟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在线,是可以解密的
1
使用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('')
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

warrah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值