JAVA后台DES加密,Node后台解密填坑之旅

2,086 阅读3分钟

背景

上一篇文章写到我自己撸了一个node后台,这两天想着把权限验证做了。

填坑

我们的权限是通过token来验证的,所以我需要把token获取到,然后解密之后获取用户的信息,通过和redis中的数据比较,然后验证用户是否有效。

获取token简单,通过req.headers.token即可获取。问题出在token解密的地方。

我们的java后台给了我两个byte数组。我瞬间就迷茫了。js里貌似没有byte数组这个东西呀,这让我怎么搞。 一般的node加密解密 key,iv都是字符串。所以我想着,是不是转成字符串就可以了,那么两个字,办它!!!

// java代码
public static byte[] TOKEN_KEY = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
// 隐藏公用的参数向量
public static byte[] COMMON_IV = new byte[]{1, 2, 3, 4, 5, 6, 7, 8};

网上搜索java byte数组转字符串方法

byte[] srtbyte =  new byte[]{1, 2, 3, 4, 5, 6, 7, 8};
// byte[] 转 string
String res = new String(srtbyte);
System.out.println(res);
// ��B�_W  乱码!!!

输出结果竟然是乱码!!!无奈了,是不是姿势有问题?!!!

那么我就想了,莫非是需要需要转成16进制的字符串??一个字,干!!! 找呀找,找到了这个方法。

 public static String ByteArrayToHexString(byte[] bytes) {
        final char[] hexArray = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
        char[] hexChars = new char[bytes.length * 2]; // Each byte has two hex characters (nibbles)
        int v;
        for (int j = 0; j < bytes.length; j++) {
            v = bytes[j] & 0xFF; // Cast bytes[j] to int, treating as unsigned value
            hexChars[j * 2] = hexArray[v >>> 4]; // Select hex character from upper nibble
            hexChars[j * 2 + 1] = hexArray[v & 0x0F]; // Select hex character from lower nibble
        }
        return new String(hexChars);
    }

结果转成了一个16位的16进制数据。 然后传入解密方法中。 很开心的看到一个报错

(node:66592) UnhandledPromiseRejectionWarning: Error: Invalid IV length

神特么无效的iv长度。没办法,继续搜。

看到一篇问题里的回复说,des加密解密key,iv只需要8位即可。上边说了,我们通过转化得到了一个16位的数字。那么是不是只取前八位就好了?

那就试试呗,反正也不要钱!结果。。还是不说了。。

UnhandledPromiseRejectionWarning: Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt

通过github上边issue解释,断定这个是因为key不对的原因!!!但是真相貌似已经越来越近了!

继续找呗。期间各种尝试,就不说了!!! 最后在 codeday.me/bug/2019030… 这篇文章里发现了一个操作。

var iv = new Buffer(8);
iv.fill(0);

var decipher = crypto.createDecipheriv('des-cbc', privateKey.substr(0,8), iv);
var dec = decipher.update(textToDecipher, 'base64', 'utf8');
dec += decipher.final('utf8');

new 一个Buffer数组,然后向里面添加值。Buffer一般是是用于二进制流的操作。 通过Buffer.from操作之后将key,iv传入解密方法中,成功解密!!! 完整方法如下。

import crypto from 'crypto'

const TOKEN_KEY = [1, 2, 3, 4, 5, 6, 7, 8]
const COMMON_IV = [1, 2, 3, 4, 5, 6, 7, 8]

let key = Buffer.from(TOKEN_KEY)
let iv = Buffer.from(COMMON_IV)

// DES 加密
export function desEncrypt(message: string) {
  const cipher = crypto.createCipheriv('des-cbc', key, iv)
  let c = cipher.update(message, 'utf8', 'base64')
  c += cipher.final('base64')
  return c
}

// DES 解密
export function desDecrypt(text: any) {
  const cipher = crypto.createDecipheriv('des-cbc', key, iv)
  cipher.setAutoPadding(true)
  let c = cipher.update(text, 'base64', 'utf8')
  c += cipher.final('utf8')
  return c
}

结果写出来很容易,但是寻找结果的过程真的是很纠结。期间碰到了很多问题。现在回头想想,如果自己能够再仔细一点,其实问题可以更快的解决的。