加解密--aes,des

5 篇文章 1 订阅
1 篇文章 0 订阅

加解密(aes,des)

前言

  • 数据加密方式有很多种,每个人都有自己的选择,一旦要跟别人对接加密的数据,一定要先去了解下加密方式的类型和各种参数的设置要求,以下就是笔者在跟别人对接过程中遇到的坑,一方面是自己对加密了解不深,另一方面使用加密的一方自己本身也可能是个半桶水,从网上抄了一段代码可以成功运行后就以为搞定了,连加密的各种参数设置都不太清楚的情况下,很容易导致互相加解密失败

AES

  • 首先,放上一个比较好用的工具:在线AES加密解密、AES在线加密解密、AES encryption and decryption–查错网
  • 使用aes加解密前,双方一定要协商好aes位数(是128bit还是256bit等),加密模式(是ECB还是CBC等),偏移量(ECB没有偏移量,偏移量不同加密的结果是不一致的,即同一密钥的明文在不同偏移量下加密的结果不同),密钥(格式是什么,什么字符集,字节长度是多少,是16进制字符串,还是utf8字符串等)
  • 上面提到的4个一定要双方确认清楚,否则这块的调试就能耗掉你许多时间
  • 很多库会有意无意地屏蔽掉aes的配置,从而宣称其使用起来多方便,但是如果使用者不了解这些参数的配置,那么在跨平台时就一定会有各种各样的问题,因为每个平台的实现库的默认配置一般都不会相同,既然配置不同,怎么可能相互加解密
  • 最后,提供一个js的加解密库 brix/crypto-js: JavaScript library of crypto standards.crypto-js - npm
  • 详细的api可以查看这里:https://cryptojs.gitbook.io/docs/

代码示例

js

var CryptoJS = require("../miniprogram_npm/crypto-js/index.js");
//加密设置,根据实际情况修改
var cfg={
  mode: CryptoJS.mode.ECB,
 // padding: CryptoJS.pad.Pkcs7 //pkcs7是默认的
  padding: CryptoJS.pad.NoPadding //本套协议采用的nopadding


}
//var key = CryptoJS.enc.Hex.parse("bc7a3dc9e79563291d7bfa93df67d545");
var key = CryptoJS.enc.Hex.parse("db1c29b3a9093117f773295b3f07bf93ff");//秘钥(16进制字符串)


/**
 * 设置aes秘钥,在加解密之前必须设置
 * 
 * @param {string} key  秘钥,16进制字符串
 */
function SetHexKey(hexKey){
  key = CryptoJS.enc.Hex.parse(hexKey)
}


/**
 * aes加密方法,返回16进制字符串
 * 
 * @param {string} hexWord  16进制字符串
 */
function AesEncrypt(hexWord) {
  let srcs = CryptoJS.enc.Hex.parse(hexWord);
  let encrypted = CryptoJS.AES.encrypt(srcs, key, cfg);
  return encrypted.ciphertext.toString().toUpperCase();
}



/**
 * aes解密方法,返回16进制字符串
 * @param {string} hexWord 16进制字符串
 */
function AesDecrypt(hexWord) {
  let encryptedHexStr = CryptoJS.enc.Hex.parse(hexWord);
  let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr);
  let decrypt = CryptoJS.AES.decrypt(srcs, key, cfg);
  let decryptedStr = decrypt.toString(CryptoJS.enc.Hex);
  return decryptedStr.toString();
}



/**
 *  将字符转为base64编码
 *  @param {string} utf8Str  字符串,utf8编码
 */
function Base64Encode(utf8Str) {
  let str = CryptoJS.enc.Utf8.parse(utf8Str);
  let base64 = CryptoJS.enc.Base64.stringify(str);
  return base64;
}

/**
 *  还原base64编码,utf8编码
 *  @param {string} base64Str  base64编码字符串
 */
function Base64Decode(base64Str) {
  let words = CryptoJS.enc.Base64.parse(base64Str);
  return words.toString(CryptoJS.enc.Utf8);
}

//暴露接口
module.exports = {
  SetHexKey,
  AesEncrypt,
  AesDecrypt,
  Base64Encode,
  Base64Decode
}


3DES(TripleDES)

  • 注意3des的秘钥长度是24字节,有些人发现js和java的加密结果不同,其中可能的原因就是密钥长度不同导致,因为不管是java还是js,如果密钥长度不足24个字节,它们都有各自的策略去补到24个字节,而策略不同,导致实际的密钥是不一样的,因此才会产生不同的结果
  • 偏移量一般是8个字节
  • 下面的java代码中(其他代码会帮你补齐还是报错我就不得而知了,感觉这里应该直接报错才好,查了老半天才知道是背地里偷偷帮我补齐到24个字节,但使用者完全不知道),如果密钥不足24个字节,比如只有16个字节,那么默认会将前8个字节补到后面凑齐24个字节,比如你在java里写的密钥是00112233445566778899AABBCCDDEEFF,那么实际上的密钥是00112233445566778899AABBCCDDEEFF0011223344556677,因此如果在web平台js里不能用00112233445566778899AABBCCDDEEFF当做密钥,要用00112233445566778899AABBCCDDEEFF0011223344556677去加解密,才能正确解出结果
  • 当然会造成这些问题都是因为对3des不够熟悉造成的,如果熟悉就会用24个字节作为密钥,就不会出现这种需要补齐的问题,因此坑都是自己挖的,还得自己好好填

代码示例

java
import org.apache.commons.codec.binary.Base64;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;


public class TripleDESUtil {

	public static void main(String[] args) throws Exception{
		encryptTest();//8FB06F38DCEBA75C3D2B3D6257EEAEB0
	}
	
    public static String encryptTest(){
        try {
            byte[] src = hexStringToByte("61207375706572206d616e2104040404");
            byte[] key = hexStringToByte("00112233445566778899AABBCCDDEEFF1122334455667788");
              byte[] ivs = new byte[] { 0x0, 0x0, 0x0,0x0, 0x0, 0x0, 0x0,0x0};
              IvParameterSpec iv = new IvParameterSpec(ivs);
            SecretKey deskey = new SecretKeySpec(key, "desede"); // 生成密钥21
            Cipher c1 = Cipher.getInstance("DESede/CBC/NoPadding"); // 实例化负责加密/解密的Cipher工具类22
            c1.init(Cipher.ENCRYPT_MODE, deskey, iv); // 初始化为加密模式23
            return bytesToHexString(c1.doFinal(src));
        } catch (java.security.NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (javax.crypto.NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (java.lang.Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    public static final String bytesToHexString(byte[] var0) {
        if (var0 == null) {
            return "";
        } else {
            StringBuffer var1 = new StringBuffer(var0.length);

            for(int var3 = 0; var3 < var0.length; ++var3) {
                String var2 = Integer.toHexString(255 & var0[var3]);
                if (var2.length() < 2) {
                    var1.append(0);
                }

                var1.append(var2.toUpperCase());
            }

            return var1.toString();
        }
    }

    public static byte[] hexStringToByte(String var0) {
        if (var0 != null && !var0.isEmpty()) {
            var0 = var0.toUpperCase();
            int var1 = var0.length() / 2;
            byte[] var2 = new byte[var1];
            char[] var3 = var0.toCharArray();

            for(int var4 = 0; var4 < var1; ++var4) {
                int var5 = var4 * 2;
                var2[var4] = (byte)(toByte(var3[var5]) << 4 | toByte(var3[var5 + 1]));
            }

            return var2;
        } else {
            return null;
        }
    }

    private static byte toByte(char var0) {
        byte var1 = (byte)"0123456789ABCDEF".indexOf(var0);
        return var1;
    }

}
js
var CryptoJS = require("../crypto/index.js")


var iv = CryptoJS.enc.Hex.parse("db1c29b3a9093117f773295b3f07bf93")
//var iv = CryptoJS.enc.Hex.parse("11223344556677889900")
//var key = CryptoJS.enc.Hex.parse("bc7a3dc9e79563291d7bfa93df67d545")
var key = CryptoJS.enc.Hex.parse("db1c29b3a9093117f773295b3f07bf93")//秘钥(16进制字符串)

//加密设置,根据实际情况修改
var cfg = {
  mode: CryptoJS.mode.CBC,
  // padding: CryptoJS.pad.Pkcs7 //pkcs7是默认的
  padding: CryptoJS.pad.NoPadding, //本套协议采用的nopadding
  iv: iv
};

/**
 * 设置3des秘钥,在加解密之前必须设置
 * 
 * @param {string} hexKey  秘钥,16进制字符串
 */
function setHexKey(hexKey){
  key = CryptoJS.enc.Hex.parse(hexKey)
}

/**
 * 设置3des偏移量,在加解密之前必须设置
 * 
 * @param {string} hexKey  秘钥,16进制字符串
 */
function setHexIV(hexIV) {
  iv = CryptoJS.enc.Hex.parse(hexIV)
  cfg.iv=iv
}

/**
 * 加密方法,返回16进制字符串
 * 
 * @param {string} hexWord  16进制字符串,必须是8个字节的倍数
 */
function encrypt(hexWord) {
  let srcs = CryptoJS.enc.Hex.parse(hexWord)
  let encrypted = CryptoJS.TripleDES.encrypt(srcs, key, cfg)
  return encrypted.ciphertext.toString().toUpperCase()
}


/**
 * 解密方法,返回16进制字符串
 * @param {string} hexWord 16进制字符串
 */
function decrypt(hexWord) {
  let encryptedHexStr = CryptoJS.enc.Hex.parse(hexWord)
  let srcs = CryptoJS.enc.Base64.stringify(encryptedHexStr)
  let decrypt = CryptoJS.TripleDES.decrypt(srcs, key, cfg)
  let decryptedStr = decrypt.toString(CryptoJS.enc.Hex)
  return decryptedStr.toString()

}


//暴露接口
module.exports = {
  setHexKey,
  setHexIV,
  encrypt,
  decrypt
}

crc校验码

  • js-crc - npm
    https://www.npmjs.com/package/js-crc

  • crc在线计算
    http://www.ip33.com/crc.html

工具

  • js工具类

/**
 * ArrayBuffer转16进制字符串
 * @param {ArrayBuffer} buffer 
 */
function ab2hex(buffer) {
    let hexArr = Array.prototype.map.call(
      new Uint8Array(buffer),
      function(bit) {
        return ('00' + bit.toString(16)).slice(-2)
      }
    )
    return hexArr.join('');
  }

  /**
   * 16进制字符串转ArrayBuffer
   * @param {String} hexStr 
   */
function hex2ab(hexStr){

    var typedArray = new Uint8Array(hexStr.match(/[\da-fA-F]{2}/gi).map(function (h) {
      return parseInt(h, 16)
    }))
    
    return typedArray.buffer
}


module.exports={
    ab2hex,
    hex2ab
}

参考

细说CryptoJs使用(微信小程序加密解密)-7855145-51CTO博客
https://blog.51cto.com/7865145/2090041

https://code.google.com/archive/p/crypto-js/downloads

brix/crypto-js: JavaScript library of crypto standards.
https://github.com/brix/crypto-js

JS中ArrayBuffer转字符串,字符串转ArrayBuffer,字符与字节桥转换 - xyzdwf的博客 - CSDN博客
https://blog.csdn.net/xyzdwf/article/details/82220987

标准crc16,通用javascript,java,c语言 - 简书
https://www.jianshu.com/p/0d810302ddff

js-crc - npm
https://www.npmjs.com/package/js-crc
crc在线计算
http://www.ip33.com/crc.html

java 3des加密问题记录 - 无所事事O_o - 博客园
https://www.cnblogs.com/wsss/p/6925090.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值