java端采用DES/CBC/PKCS5Padding 加密,js解密不了。google搜了好多方法没能解决

发送一段java 的DES加密和解密

    /**
     * 加密
     */
             private static byte[] iv = {1, 2, 3, 4, 5, 6, 7, 8};
    public static String encryptDES(String encryptString, String encryptKey) {
    try {
        IvParameterSpec zeroIv = new IvParameterSpec(iv);
        SecretKeySpec key = new SecretKeySpec(encryptKey.getBytes(), "DES");
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, key, zeroIv);
        byte[] encryptedData = cipher.doFinal(encryptString.getBytes());
        return Base64.encode(encryptedData);
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }

    }

    /**
     * 解密
     */
    public static String decryptDES(String decryptString, String decryptKey) {
    try {
        byte[] byteMi = Base64.decode(decryptString);
        IvParameterSpec zeroIv = new IvParameterSpec(iv);
        SecretKeySpec key = new SecretKeySpec(decryptKey.getBytes(), "DES");
        Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, key, zeroIv);
        byte decryptedData[] = cipher.doFinal(byteMi);

        return new String(decryptedData);
    } catch (Exception e) {
        e.printStackTrace();
        return "";
    }

    }

现在的javascript解密库是用crypto-js

但是没找到能支持DES/CBC/PKCS5Padding的算法。怎么办

阅读 10.5k
4 个回答

看了一下,Crypto-js是支持des-cbc加密的。
Pkcs5Pkcs7在块大小为8时特殊情况,本质上是一样的。Crypto-js默认padding是Pkcs7,可以直接使用。
给个例子:

#加密,key: testtest iv:abcdefgh
echo message | openssl enc -a -des-cbc -K 7465737474657374 -iv 6162636465666768
#输出:kEiztbNAuirF25k0FAcylA==
//解密
var key = CryptoJS.enc.Utf8.parse('testtest');
var iv = CryptoJS.enc.Utf8.parse('abcdefgh');
CryptoJS.DES.decrypt("kEiztbNAuirF25k0FAcylA==", key, {
    iv : iv,
    mode: CryptoJS.mode.CBC,    //可省略
    padding: CryptoJS.pad.Pkcs7 //可省略
}).toString(CryptoJS.enc.Utf8);
//输出:message

回答你评论中的问题。
首先,你这里des加密出来的结果,是用base64编码表示的,base64编码里,合法字符范围是[A-Za-z0-9+=/],空格根本就不是合法字符,是不应该出现的。所以不是Cryptojs的问题。

那么到底是哪里出了问题呢,首先来看看你给的第一端密文:

echo DrXWLKRt5byd6XcRGCk66G3BEQ0V7KA9gVZl0kaj/2WK9T+wWarVG7CUtN2H33VDZgVZ3DEuG4O3ja179eyPe6+//9I8w/JxQ2lvLNV4+PaD+in2ltgf3A== | openssl enc -d -a -des-cbc -K 55494a443839486b -iv 3132333435363738 | xxd
#输出
0000000: 5844 4440 0a1f 1f02 3030 3032 3135 3037  XDD@....00021507
0000010: 2e76 6f64 2e6d 7971 636c 6f75 642e 636f  .vod.myqcloud.co
0000020: 6d2f 3230 3030 3231 3530 375f 6638 6131  m/200021507_f8a1
0000030: 3733 6134 6131 3837 3131 6536 3934 3564  73a4a18711e6945d
0000040: 3739 3730 3130 3738 6434 3862 2e66 3230  79701078d48b.f20
0000050: 2e6d 7034                                .mp4

可以看到XXD@后面出现了0a1f1f02这一段,在utf-8编码下,0x0a被解释为换行,其他的被解释为控制字符无法显示。解密过程正常,输出也正常,说明解密出来的就是原文(如果密文有问题,应该是报错,一点都解密不出来),至于为什么会包含这些奇怪的字符,就要问问你们后端怎么弄出来的这段了,是不是把非utf-8编码的字符强行连接在一起了。

那么这个空格又是如何出现的呢?我们把解密后的密文重新加密回去:

echo DrXWLKRt5byd6XcRGCk66G3BEQ0V7KA9gVZl0kaj/2WK9T+wWarVG7CUtN2H33VDZgVZ3DEuG4O3ja179eyPe6+//9I8w/JxQ2lvLNV4+PaD+in2ltgf3A== | openssl enc -d -a -des-cbc -K 55494a443839486b -iv 3132333435363738 | openssl enc -a -des-cbc -K 55494a443839486b -iv 3132333435363738
#输出
DrXWLKRt5byd6XcRGCk66G3BEQ0V7KA9gVZl0kaj/2WK9T+wWarVG7CUtN2H33VD
ZgVZ3DEuG4O3ja179eyPe6+//9I8w/JxQ2lvLNV4+PaD+in2ltgf3A==

注意到这里出现了换行,这时因为openssl会调用base64命令进行编码,为了兼容某些旧程序,会自动进行换行。之后在网络传输过程中或者你们后端做了替换或者你们的复制粘贴过程中,这个换行符变成了空格。从你给的第二段密文也可以看出,是同样的60个字符一个空格。这里的换行宽度和java的不一样,但是道理是一样的。

所以,解决方案就是,在前端或者后端移除空白字符。

Base64.encodeBase64String(text, Base64.NO_WRAP)
encrypted_msg.replace(/\s/g, '');

js如果有DES/CBC的话,Padding可以自己实现哈。

新手上路,请多包涵

可以请教下作者最后是怎么解决的吗,我的Java端代码和你一样?

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏