在做项目使用 AES加密串作为TOKEN时遇到一个问题 ==,而且是在服务器上才会出现。加密好好的解密后数据乱码的问题。 因为加解密这些东西都是直接拿网上写的算法,具体里面的方法没有研究透彻,更别说去改了==。首先没想到是乱码的问题,只是解密返回过来的JSON串(因为加密数据就是JSON)在回转的时候一直回转失败。用的是阿里的fastJson ,难道是这个包有问题?然后排查发现,在断点进入后发现加密过后的数据回传过来后乱码了。。。。。所以初步判定是 乱码导致 JSON 回转失败。。。
然后将加密解密方法中的所有String.getBytes()方法全部指定 UTF-8 而且new String(bytes[],"UTF-8"),全部指定为UTF-8,测试。不行,还是乱码,上网查找资料,发现好多人都会出现,因为AES的加密是有要求的, 由于AES加密算法要求密文是16位的倍数所以会有信息的填充,猜测是在填充的数据中,解密时出现了问题。而且所有的的加密解密在经过转换后最后的状态都是 bytes[]数组,展现出来的字符状态都是经过处理的(大部分时base64的加密转换),而base64字符在网络传输中有可能特殊字符会经过转义,目前发现的就有加号被转换成了空格==。猜测也有可能是这个原因导致失败。(但是不应该时解密失败嘛,为啥会转换成特殊字符)。使用加密解密时,别人都是汉字转换会成为特殊字符,我这里是 数字和字母==。根据大神给出的信息,重新定义AES的加密解密类,并且将加密返回的字符串改成16进制,这样就只会存在字母和数字,就是将加密返回的bytes[]转成16进制而不是base64,这样,会解决掉解密后出现字符乱码的问题。(同样的在网络传输中因为特殊字符被转换的问题也会被解决掉)代码:
packagecom.tl.handlpower.util; importorg.apache.commons.codec.binary.Base64; importorg.apache.commons.lang3.StringUtils; importsun.misc.BASE64Decoder; importjavax.crypto.*; importjavax.crypto.spec.SecretKeySpec; importjava.io.UnsupportedEncodingException; importjava.security.InvalidKeyException; importjava.security.NoSuchAlgorithmException; importjava.security.SecureRandom; /*** AESUtils** @author mjx* @date 2020/4/15*/publicclassAESUtils { /*** 密钥*/// public static final String KEY = "1234567887654321";// AES加密要求key必须要128个比特位(这里需要长度为16,否则会报错)/*** 加密** @param content* 需要加密的内容* @param password* 加密密码* @return*/publicstaticbyte[] encrypt(Stringcontent, Stringpassword) { try { KeyGeneratorkgen=KeyGenerator.getInstance("AES"); kgen.init(128, newSecureRandom(password.getBytes())); SecretKeysecretKey=kgen.generateKey(); byte[] enCodeFormat=secretKey.getEncoded(); SecretKeySpeckey=newSecretKeySpec(enCodeFormat, "AES"); Ciphercipher=Cipher.getInstance("AES");// 创建密码器byte[] byteContent=content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化byte[] result=cipher.doFinal(byteContent); returnresult; // 加密 } catch (NoSuchAlgorithmExceptione) { e.printStackTrace(); } catch (NoSuchPaddingExceptione) { e.printStackTrace(); } catch (InvalidKeyExceptione) { e.printStackTrace(); } catch (UnsupportedEncodingExceptione) { e.printStackTrace(); } catch (IllegalBlockSizeExceptione) { e.printStackTrace(); } catch (BadPaddingExceptione) { e.printStackTrace(); } returnnull; } /*** 解密** @param content* 待解密内容* @param password* 解密密钥* @return*/publicstaticbyte[] decrypt(byte[] content, Stringpassword) { try { KeyGeneratorkgen=KeyGenerator.getInstance("AES"); kgen.init(128, newSecureRandom(password.getBytes())); SecretKeysecretKey=kgen.generateKey(); byte[] enCodeFormat=secretKey.getEncoded(); SecretKeySpeckey=newSecretKeySpec(enCodeFormat, "AES"); Ciphercipher=Cipher.getInstance("AES");// 创建密码器cipher.init(Cipher.DECRYPT_MODE, key);// 初始化byte[] result=cipher.doFinal(content); returnresult; // 加密 } catch (NoSuchAlgorithmExceptione) { e.printStackTrace(); } catch (NoSuchPaddingExceptione) { e.printStackTrace(); } catch (InvalidKeyExceptione) { e.printStackTrace(); } catch (IllegalBlockSizeExceptione) { e.printStackTrace(); } catch (BadPaddingExceptione) { e.printStackTrace(); } returnnull; } /*** 将二进制转换成16进制** @param buf* @return*/publicstaticStringparseByte2HexStr(bytebuf[]) { StringBuffersb=newStringBuffer(); for (inti=0; i<buf.length; i++) { Stringhex=Integer.toHexString(buf[i] &0xFF); if (hex.length() ==1) { hex='0'+hex; } sb.append(hex.toUpperCase()); } returnsb.toString(); } /*** 将16进制转换为二进制** @param hexStr* @return*/publicstaticbyte[] parseHexStr2Byte(StringhexStr) { if (hexStr.length() <1) { returnnull; } byte[] result=newbyte[hexStr.length() /2]; for (inti=0; i<hexStr.length() /2; i++) { inthigh=Integer.parseInt(hexStr.substring(i*2, i*2+1), 16); intlow=Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16); result[i] = (byte) (high*16+low); } returnresult; } /*** 加密** @param content* 需要加密的内容* @param password* 加密密码* @return*/publicstaticbyte[] encrypt2(Stringcontent, Stringpassword) { try { SecretKeySpeckey=newSecretKeySpec(password.getBytes(), "AES"); Ciphercipher=Cipher.getInstance("AES/ECB/NoPadding"); byte[] byteContent=content.getBytes("utf-8"); cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化byte[] result=cipher.doFinal(byteContent); returnresult; // 加密 } catch (NoSuchAlgorithmExceptione) { e.printStackTrace(); } catch (NoSuchPaddingExceptione) { e.printStackTrace(); } catch (InvalidKeyExceptione) { e.printStackTrace(); } catch (UnsupportedEncodingExceptione) { e.printStackTrace(); } catch (IllegalBlockSizeExceptione) { e.printStackTrace(); } catch (BadPaddingExceptione) { e.printStackTrace(); } returnnull; } publicstaticvoidmain(String[] args) throwsUnsupportedEncodingException { Stringcontent="我是shoneworn"; Stringpassword="12345678"; // 加密System.out.println("加密前:"+content); byte[] encode=encrypt(content, password); //传输过程,不转成16进制的字符串,就等着程序崩溃掉吧Stringcode=parseByte2HexStr(encode); System.out.println("密文字符串:"+code); byte[] decode=parseHexStr2Byte(code); // 解密byte[] decryptResult=decrypt(decode, password); System.out.println("解密后:"+newString(decryptResult, "UTF-8")); //不转码会乱码 } /**** 解密* @Author: mjx* @DateTime: 2020/4/28 10:42* @Params: []* @Return java.lang.String*/publicstaticStringaesDecrypt(Stringdata, Stringkey) { try { returnnewString(decrypt(parseHexStr2Byte(data), key),"UTF-8"); } catch (UnsupportedEncodingExceptione) { e.printStackTrace(); } returnnull; } /**** 加密* @Author: mjx* @DateTime: 2020/4/28 10:43* @Params: []* @Return java.lang.String*/publicstaticStringaesEncrypt(Stringdata,Stringkey) { returnparseByte2HexStr(encrypt(data, key)); } }