Mic*_*ael 3 java encryption aes character-encoding
我正在尝试Strings使用Java和PHP 加密和解密,所以我使用AES/CFB8/NoPadding它可以在双方都工作.
现在Cryptor,只要我将Charset设置为拉丁语,我的作品就会完全放弃拉丁字符.但是当我将它设置为UTF-8(这是我在我的数据库中使用的)时,加密没有正确完成.
这是输出:
/*
* Latin (ISO-8859-1) output:
* Original: MiiiMüäöMee?
* Encoded: rQ¶[ÉÐRíD
* Decoded: MiiiMüäöMee?
*
* UTF-8 output:
* Original: MiiiMüäöMee?
* Encoded: rQ?[?
* Decoded: Mii0SS1])_?E?I?S?;?W??W?*
*/
Run Code Online (Sandbox Code Playgroud)
由于"ʞ"不是拉丁字符,我理解它无法正确加密.但为什么UTF-8不起作用?
public class Cryptor {
private Cipher cipher;
private String secretKey = "1234567890qwertz";
private String iv = "1234567890qwertz";
private SecretKey keySpec;
private IvParameterSpec ivSpec;
private Charset CHARSET = Charset.forName("ISO-8859-1"); // ISO-8859-1 vs. UTF-8
public Cryptor() throws CryptingException {
keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES");
ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
try {
cipher = Cipher.getInstance("AES/CFB8/NoPadding");
} catch (NoSuchAlgorithmException e) {
throw new SecurityException(e);
} catch (NoSuchPaddingException e) {
throw new SecurityException(e);
}
}
public String decrypt(String input) throws CryptingException {
try {
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return new String(cipher.doFinal(input.getBytes(CHARSET)), CHARSET).trim();
} catch (IllegalBlockSizeException e) {
throw new SecurityException(e);
} catch (BadPaddingException e) {
throw new SecurityException(e);
} catch (InvalidKeyException e) {
throw new SecurityException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new SecurityException(e);
}
}
public String encrypt(String input) throws CryptingException {
try {
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return new String(cipher.doFinal(input.getBytes(CHARSET)), CHARSET).trim();
} catch (InvalidKeyException e) {
throw new SecurityException(e);
} catch (InvalidAlgorithmParameterException e) {
throw new SecurityException(e);
} catch (IllegalBlockSizeException e) {
throw new SecurityException(e);
} catch (BadPaddingException e) {
throw new SecurityException(e);
}
}
public static void main(String Args[]) {
try {
Cryptor c = new Cryptor();
String original = "MiiiMüäöMee?";
System.out.println("Original: " + original);
String encrypted = c.encrypt("MiiiMüäöMee?");
System.out.println("Encoded: " + encrypted);
System.out.println("Decoded: " + c.decrypt(encrypted));
} catch (CryptingException e) {
e.printStackTrace();
}
}
class CryptingException extends RuntimeException {
private static final long serialVersionUID = 7123322995084333687L;
public CryptingException() {
super();
}
public CryptingException(String message) {
super(message);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Bor*_*der 12
我认为将加密的字节转换为a String是一个坏主意.字节对任何编码都无效,它们是随机的.
您需要将结果编码byte[]为base64以获得一致的结果.见sun.misc.BASE64Encoder/ sun.misc.BASE64Decoder.
这里是一个base64解码的一个例子String的byte[],相反的过程非常相似.
您可以声明解码器/编码器和类的顶部:
private final BASE64Decoder base64Decoder = new BASE64Decoder();
private final BASE64Encoder base64Encoder = new BASE64Encoder();
Run Code Online (Sandbox Code Playgroud)
然后在你的decypt方法中你需要打电话
return new String(cipher.doFinal(base64Decoder.decodeBuffer(input)), CHARSET);
Run Code Online (Sandbox Code Playgroud)
在你的encrypt方法
return base64Encoder.encode(cipher.doFinal(input.getBytes(CHARSET)));
Run Code Online (Sandbox Code Playgroud)
使用UTF-8输出:
Original: MiiiMüäöMee?
Encoded: clEUtlv2ALXsKYw4ivOfwQ==
Decoded: MiiiMüäöMee?
Run Code Online (Sandbox Code Playgroud)
一方面注意,使用包不是严格意义上的好习惯,sun.*因为它们不是java规范的一部分,因此可能会因版本而变化/消失.
这是关于迁移到Apache Commons Codec实现的一篇小文章.
这也是Guava API中的类似类.