php base64_decode与java base64解密结果不匹配问题

1.正常的字符串base64加密后,php和java都可以正常解析

例如:

原文:

this is a test

java代码:

String test = "this is a test";
System.out.println(new String(java.util.Base64.getEncoder().encode(test.getBytes())));
System.out.println(org.apache.commons.codec.binary.Base64.encodeBase64String(test.getBytes()));

java代码结果:

dGhpcyBpcyBhIHRlc3Q=
dGhpcyBpcyBhIHRlc3Q=

php代码:

<?php
        echo base64_encode('this is a test')."\n";
?>

php代码结果:

dGhpcyBpcyBhIHRlc3Q=

解析过程就不再列举了,解析结果都是可以还原原字符串。

2.特殊字符串(非base64加密的字符串结果)进行base64 decode解析结果不同

场景:公司某个业务的手机号php系统加密算法传输(涉及到base64加密),对端java系统进行解密(涉及到base64解密)

加密流程暂不列举,直接列举base64解密结果

加密原文:

MzMdWpavMBd+FBUoJWmdQeaqV5J1z57zXLKAn6NWtGhL1ygVtA

php代码:

<?php
        $string = base64_decode('MzMdWpavMBd+FBUoJWmdQeaqV5J1z57zXLKAn6NWtGhL1ygVtA');
        echo $string."\n";
        echo strlen($string)."\n";
?>

php代码结果:

33Z��0~(%i�A��W�uϞ�\����V�hK�(�
37

java代码:

String test = "MzMdWpavMBd+FBUoJWmdQeaqV5J1z57zXLKAn6NWtGhL1ygVtA";
String result1 = new String(java.util.Base64.getDecoder().decode(test.getBytes()));
System.out.println(result1);
System.out.println(result1.length());
String result2 = new String(org.apache.commons.codec.binary.Base64.decodeBase64(test));
System.out.println(result2);
System.out.println(result2.length());

java代码结果:

33Z��0~(%i�A�W�uϞ�\����V�hK�(�
35
33Z��0~(%i�A�W�uϞ�\����V�hK�(�
35

很明显,php解密的结果文本和字符串长度都与java不同

java解决问题:

1.查看解密后字节长度

java代码:

String test = "MzMdWpavMBd+FBUoJWmdQeaqV5J1z57zXLKAn6NWtGhL1ygVtA";
byte[] result1 = java.util.Base64.getDecoder().decode(test.getBytes());
System.out.println(result1.length);
byte[] result2 = org.apache.commons.codec.binary.Base64.decodeBase64(test);
System.out.println(result2.length);

java代码结果:

37
37

结论:字节长度相符,所以最终得到的字符串,并不是通过new String()生成。

2.查看php解密后ASCII码与java字节码的对比

php代码:

<?php
        $string = base64_decode('MzMdWpavMBd+FBUoJWmdQeaqV5J1z57zXLKAn6NWtGhL1ygVtA');
        for($i = 0; $i < strlen($string); $i++) {
            echo ord($string[$i])." ";
        }
?>

php代码结果:

51 51 29 90 150 175 48 23 126 20 21 40 37 105 157 65 230 170 87 146 117 207 158 243 92 178 128 159 163 86 180 104 75 215 40 21 180

java代码:

String test = "MzMdWpavMBd+FBUoJWmdQeaqV5J1z57zXLKAn6NWtGhL1ygVtA";
byte[] result1 = java.util.Base64.getDecoder().decode(test.getBytes());
for (int i = 0; i < result1.length; i++) {
    System.out.print(result1[i] + " ");
}
System.out.println();
byte[] result2 = org.apache.commons.codec.binary.Base64.decodeBase64(test);
for (int i = 0; i < result2.length; i++) {
    System.out.print(result2[i] + " ");
}

java代码结果:

51 51 29 90 -106 -81 48 23 126 20 21 40 37 105 -99 65 -26 -86 87 -110 117 -49 -98 -13 92 -78 -128 -97 -93 86 -76 104 75 -41 40 21 -76
51 51 29 90 -106 -81 48 23 126 20 21 40 37 105 -99 65 -26 -86 87 -110 117 -49 -98 -13 92 -78 -128 -97 -93 86 -76 104 75 -41 40 21 -76

对比后发现:

java的负数字节码与php的字节码结果相差256

ok,修改java解密逻辑,新增256的计算

java代码:

String test = "MzMdWpavMBd+FBUoJWmdQeaqV5J1z57zXLKAn6NWtGhL1ygVtA";
byte[] result1 = java.util.Base64.getDecoder().decode(test.getBytes());
StringBuffer sb1 = new StringBuffer();
for (int i = 0; i < result1.length; i++) {
    if (result1[i] > 0) {
        sb1.append((char) result1[i]);
    } else {
        sb1.append((char) (result1[i] + 256));
    }
}
System.out.println(sb1.toString());
System.out.println(sb1.length());
byte[] result2 = org.apache.commons.codec.binary.Base64.decodeBase64(test);
StringBuffer sb2 = new StringBuffer();
for (int i = 0; i < result2.length; i++) {
    if (result2[i] > 0) {
        sb2.append((char) result2[i]);
    } else {
        sb2.append((char) (result2[i] + 256));
    }
}
System.out.println(sb2.toString());
System.out.println(sb2.length());

String str3 = new String(result1, java.nio.charset.StandardCharsets.ISO_8859_1);
System.out.println(str3);
System.out.println(str3.length());

java代码结果:

33Z¯0~(%iAæªWuÏó\²£V´hK×(´
37
33Z¯0~(%iAæªWuÏó\²£V´hK×(´
37
33Z¯0~(%iAæªWuÏó\²£V´hK×(´
37

3.结论

1.非base64加密的标准数据,通过base64解码,php和java结果字符串不同

2.java获取base64解码的字节数组,长度与php解码长度一致,字节数字为正数,与php的ASCII码一致,负数的话,与php的ASCII码相差256;

3.也可以通过ISO_8859_1编码,获取到长度一致的字符串,遍历字符串每个char的int值,也是与php的ASCII码相同

4.不同的第三方jar解析base64,结果是一样的

5.长度和ASCII码都与php相同时,得到的字符串与php也不相同,暂时不知道什么原因

原文地址:https://www.cnblogs.com/forforever/p/15624480.html