我正在尝试在Java和PHP中加密和解密Strings
,因此我使用AES/CFB8/NoPadding
可以在双方都工作。
现在,只要我将Charset设置为拉丁语,我的Cryptor
就可以很好地退出拉丁字符。但是当我将它设置为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])_�ELJI�S�;�W��W?*
*/
由于“ʞ”不是拉丁字符,我知道它无法正确加密。但为什么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);
}
}
}
答案 0 :(得分:11)
我认为将加密的字节转换为String
是一个坏主意。这些字节对任何编码都无效,它们是随机的。
您需要将生成的byte[]
编码为base64以获得一致的结果。请参阅sun.misc.BASE64Encoder
/ sun.misc.BASE64Decoder
。
Here是将base64 String
解码为byte[]
的示例,反向过程非常相似。
您可以声明解码器/编码器和班级的顶部:
private final BASE64Decoder base64Decoder = new BASE64Decoder();
private final BASE64Encoder base64Encoder = new BASE64Encoder();
然后在decypt
方法中,您需要致电
return new String(cipher.doFinal(base64Decoder.decodeBuffer(input)), CHARSET);
并在您的encrypt
方法
return base64Encoder.encode(cipher.doFinal(input.getBytes(CHARSET)));
使用UTF-8输出:
Original: MiiiMüäöMeeʞ
Encoded: clEUtlv2ALXsKYw4ivOfwQ==
Decoded: MiiiMüäöMeeʞ
一方面注意,使用来自sun.*
的软件包并不是严格来说的良好做法,因为它们不是Java规范的一部分,因此可能会从版本更改/消失。
Here是一篇关于迁移到Apache Commons Codec实现的文章 这也是Guava API中的a similar类。
答案 1 :(得分:1)
非常感谢你的回答,这对我很有帮助。
以下是我用来加密和解密JAVA和PHP中的JSON内容的工作代码:
/*-- JAVA --*/
/**
* Is used for encrypting and decrypting Strings and JSONObjects. <br>
* The JSON Objects can then be sent to a PHP script where they can be encrypted and decrypted with the same algorithm.
* @throws CryptingException
*/
public class Cryptor {
private Cipher cipher;
private String secretKey = "1234567890qwertz";
private String iv = "1234567890qwertz";
private final String CIPHER_MODE = "AES/CFB8/NoPadding";
private SecretKey keySpec;
private IvParameterSpec ivSpec;
private Charset CHARSET = Charset.forName("UTF8");
public Cryptor() throws CryptingException {
keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES");
ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
try {
cipher = Cipher.getInstance(CIPHER_MODE);
} catch (NoSuchAlgorithmException e) {
throw new SecurityException(e);
} catch (NoSuchPaddingException e) {
throw new SecurityException(e);
}
}
/**
* @param input A "AES/CFB8/NoPadding" encrypted String
* @return The decrypted String
* @throws CryptingException
*/
public String decrypt(String input) throws CryptingException {
try {
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(input)));
} 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);
}
}
/**
* @param input Any String to be encrypted
* @return An "AES/CFB8/NoPadding" encrypted String
* @throws CryptingException
*/
public String encrypt(String input) throws CryptingException {
try {
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return DatatypeConverter.printBase64Binary(cipher.doFinal(input.getBytes(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);
}
}
/**
* Encrypts the keys and values of a JSONObject with Cryptor.encrypt(String input)
* @param o The JSONObject to be encrypted
* @return A JSONObject with encrypted keys and values
*/
public JSONObject jsonObjectEncrypt(JSONObject o) {
Iterator<?> keys = o.keys();
JSONObject returnObject = new JSONObject();
while( keys.hasNext() ){
String key = (String)keys.next();
returnObject.put(this.encrypt(key), this.encrypt(o.getString(key)));
}
return returnObject;
}
/**
* Decrypts the keys and values of a JSONObject with Cryptor.decrypt(String input)
* @param o The JSONObject to be decrypted
* @return A JSONObject with decrypted keys and values
*/
public JSONObject jsonObjectDecrypt(JSONObject o) {
Iterator<?> keys = o.keys();
JSONObject returnObject = new JSONObject();
while( keys.hasNext() ){
String key = (String)keys.next();
if(key != null && !key.equals("")) {
returnObject.put(this.decrypt(key), this.decrypt(o.getString(key)));
}
}
return returnObject;
}
/**
* Encrypts keys and values of every JSONObject in a JSONArray
* @param a The JSONArray to be encrypted
* @return A JSONArray with encrypted keys and values
*/
public JSONArray jsonArrayEncrypt(JSONArray a) {
JSONArray returnArray = new JSONArray();
for(int i = 0; i < a.length(); i++) {
returnArray.put(this.jsonObjectEncrypt((JSONObject)a.get(i)));
}
return returnArray;
}
/**
* Decrypts keys and values of every JSONObject in a JSONArray
* @param a The JSONArray to be decrypted
* @return A JSONArray with decrypted keys and values
*/
public JSONArray jsonArrayDecrypt(JSONArray a) {
JSONArray returnArray = new JSONArray();
for(int i = 0; i < a.length(); i++) {
returnArray.put(this.jsonObjectDecrypt((JSONObject)a.get(i)));
}
return returnArray;
}
public static void main(String Args[]) {
try {
Cryptor c = new Cryptor();
String original = "MiiiMüäöMeeʞ";
System.out.println("Original: " + original);
String encrypted = c.encrypt(original);
System.out.println("Encoded: " + encrypted);
System.out.println("Decoded: " + c.decrypt(encrypted));
JSONArray arr = new JSONArray("[{\"id\"=\" 1 ʞ3 \"},{\"id\"=\"4\"}]");
System.out.println(c.jsonArrayDecrypt(c.jsonArrayEncrypt(arr)).getJSONObject(0).getString("id"));
} catch (CryptingException e) {
e.printStackTrace();
}
}
}
/*-- PHP ---*/
<html>
<meta charset='utf-8'>
<?php
$cryptor = new Cryptor();
echo $cryptor->decrypt($cryptor->encrypt("MiiiMüäöMeeʞ"));
class Cryptor
{
//Use same as in java Cryptor
private $iv = '1234567890qwertz';
private $secretKey = '1234567890qwertz';
function encrypt($input) {
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$this->secretKey,
$input,
MCRYPT_MODE_CFB,
$this->iv
)
);
}
function decrypt($input) {
return mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$this->secretKey,
base64_decode($input),
MCRYPT_MODE_CFB,
$this->iv
);
}
function arrayDecrypt($array) {
$returnArray = array();
foreach($array as $key=>$value) {
$newKey = $this->decrypt($key);
$returnArray[$newKey] = $this->decrypt($value);
}
return $returnArray;
}
function arrayEncrypt($array) {
$returnArray = array();
foreach($array as $key=>$value) {
$returnArray[$this->encrypt($key)] = $this->encrypt($value);
}
return $returnArray;
}
}
?>
</html>
/*-- JAVA --*/
/**
* Is used for encrypting and decrypting Strings and JSONObjects. <br>
* The JSON Objects can then be sent to a PHP script where they can be encrypted and decrypted with the same algorithm.
* @throws CryptingException
*/
public class Cryptor {
private Cipher cipher;
private String secretKey = "1234567890qwertz";
private String iv = "1234567890qwertz";
private final String CIPHER_MODE = "AES/CFB8/NoPadding";
private SecretKey keySpec;
private IvParameterSpec ivSpec;
private Charset CHARSET = Charset.forName("UTF8");
public Cryptor() throws CryptingException {
keySpec = new SecretKeySpec(secretKey.getBytes(CHARSET), "AES");
ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
try {
cipher = Cipher.getInstance(CIPHER_MODE);
} catch (NoSuchAlgorithmException e) {
throw new SecurityException(e);
} catch (NoSuchPaddingException e) {
throw new SecurityException(e);
}
}
/**
* @param input A "AES/CFB8/NoPadding" encrypted String
* @return The decrypted String
* @throws CryptingException
*/
public String decrypt(String input) throws CryptingException {
try {
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(input)));
} 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);
}
}
/**
* @param input Any String to be encrypted
* @return An "AES/CFB8/NoPadding" encrypted String
* @throws CryptingException
*/
public String encrypt(String input) throws CryptingException {
try {
cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
return DatatypeConverter.printBase64Binary(cipher.doFinal(input.getBytes(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);
}
}
/**
* Encrypts the keys and values of a JSONObject with Cryptor.encrypt(String input)
* @param o The JSONObject to be encrypted
* @return A JSONObject with encrypted keys and values
*/
public JSONObject jsonObjectEncrypt(JSONObject o) {
Iterator<?> keys = o.keys();
JSONObject returnObject = new JSONObject();
while( keys.hasNext() ){
String key = (String)keys.next();
returnObject.put(this.encrypt(key), this.encrypt(o.getString(key)));
}
return returnObject;
}
/**
* Decrypts the keys and values of a JSONObject with Cryptor.decrypt(String input)
* @param o The JSONObject to be decrypted
* @return A JSONObject with decrypted keys and values
*/
public JSONObject jsonObjectDecrypt(JSONObject o) {
Iterator<?> keys = o.keys();
JSONObject returnObject = new JSONObject();
while( keys.hasNext() ){
String key = (String)keys.next();
if(key != null && !key.equals("")) {
returnObject.put(this.decrypt(key), this.decrypt(o.getString(key)));
}
}
return returnObject;
}
/**
* Encrypts keys and values of every JSONObject in a JSONArray
* @param a The JSONArray to be encrypted
* @return A JSONArray with encrypted keys and values
*/
public JSONArray jsonArrayEncrypt(JSONArray a) {
JSONArray returnArray = new JSONArray();
for(int i = 0; i < a.length(); i++) {
returnArray.put(this.jsonObjectEncrypt((JSONObject)a.get(i)));
}
return returnArray;
}
/**
* Decrypts keys and values of every JSONObject in a JSONArray
* @param a The JSONArray to be decrypted
* @return A JSONArray with decrypted keys and values
*/
public JSONArray jsonArrayDecrypt(JSONArray a) {
JSONArray returnArray = new JSONArray();
for(int i = 0; i < a.length(); i++) {
returnArray.put(this.jsonObjectDecrypt((JSONObject)a.get(i)));
}
return returnArray;
}
public static void main(String Args[]) {
try {
Cryptor c = new Cryptor();
String original = "MiiiMüäöMeeʞ";
System.out.println("Original: " + original);
String encrypted = c.encrypt(original);
System.out.println("Encoded: " + encrypted);
System.out.println("Decoded: " + c.decrypt(encrypted));
JSONArray arr = new JSONArray("[{\"id\"=\" 1 ʞ3 \"},{\"id\"=\"4\"}]");
System.out.println(c.jsonArrayDecrypt(c.jsonArrayEncrypt(arr)).getJSONObject(0).getString("id"));
} catch (CryptingException e) {
e.printStackTrace();
}
}
}
/*-- PHP ---*/
<html>
<meta charset='utf-8'>
<?php
$cryptor = new Cryptor();
echo $cryptor->decrypt($cryptor->encrypt("MiiiMüäöMeeʞ"));
class Cryptor
{
//Use same as in java Cryptor
private $iv = '1234567890qwertz';
private $secretKey = '1234567890qwertz';
function encrypt($input) {
return base64_encode(
mcrypt_encrypt(
MCRYPT_RIJNDAEL_128,
$this->secretKey,
$input,
MCRYPT_MODE_CFB,
$this->iv
)
);
}
function decrypt($input) {
return mcrypt_decrypt(
MCRYPT_RIJNDAEL_128,
$this->secretKey,
base64_decode($input),
MCRYPT_MODE_CFB,
$this->iv
);
}
function arrayDecrypt($array) {
$returnArray = array();
foreach($array as $key=>$value) {
$newKey = $this->decrypt($key);
$returnArray[$newKey] = $this->decrypt($value);
}
return $returnArray;
}
function arrayEncrypt($array) {
$returnArray = array();
foreach($array as $key=>$value) {
$returnArray[$this->encrypt($key)] = $this->encrypt($value);
}
return $returnArray;
}
}
?>
</html>