我正在尝试编写一个使用AES加密/解密文本的类。
我想生成一个密钥,将密钥存储在数据库列中,并使用该密钥加密/解密包含密钥的数据库行中的相应文本。
以下是我编写的用于生成密钥并执行加密和解密任务的类。
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class StringDecryptor {
public static String encrypt(String text, String key) {
Key aesKey = null;
Cipher cipher = null;
byte[] encrypted = null;
try {
aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
encrypted = cipher.doFinal(text.getBytes());
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
}
return new String(encrypted);
}
public static String decrypt(String text, String key) {
Key aesKey = null;
Cipher cipher;
String decrypted = null;
try {
aesKey = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, aesKey);
decrypted = new String(cipher.doFinal(text.getBytes()));
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (NoSuchPaddingException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (InvalidKeyException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalBlockSizeException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (BadPaddingException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
}
return decrypted;
}
public static String generateKey() {
SecretKey secretKey = null;
try {
secretKey = KeyGenerator.getInstance("AES").generateKey();
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
}
String keyString = bytesToString(secretKey.getEncoded());
return keyString;
}
public static String bytesToString(byte[] b) {
String decoded = null;
try {
decoded = new String(b, "UTF-8");
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(StringDecryptor.class.getName()).log(Level.SEVERE, null, ex);
}
return decoded;
}
public static void main(String args[]) {
String key = generateKey();
System.out.println("key: " + key);
String str = "This is the original string...";
String enc = encrypt(str, key);
System.out.println("enc: " + enc);
String dec = decrypt(enc, key);
System.out.println("dec: " + dec);
}
}
此代码抛出以下异常。
SEVERE: null
java.security.InvalidKeyException: Invalid AES key length: 26 bytes
at com.sun.crypto.provider.AESCipher.engineGetKeySize(AESCipher.java:372)
at javax.crypto.Cipher.passCryptoPermCheck(Cipher.java:1052)
at javax.crypto.Cipher.checkCryptoPerm(Cipher.java:1010)
at javax.crypto.Cipher.implInit(Cipher.java:786)
at javax.crypto.Cipher.chooseProvider(Cipher.java:849)
at javax.crypto.Cipher.init(Cipher.java:1213)
at javax.crypto.Cipher.init(Cipher.java:1153)
at com.innolabmm.software.luckydraw.utils.StringDecryptor.encrypt(StringDecryptor.java:27)
at com.innolabmm.software.luckydraw.utils.StringDecryptor.main(StringDecryptor.java:95)
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:556)
at com.innolabmm.software.luckydraw.utils.StringDecryptor.encrypt(StringDecryptor.java:42)
at com.innolabmm.software.luckydraw.utils.StringDecryptor.main(StringDecryptor.java:95)
Java Result: 1
有没有办法生成一个不会导致AES密钥转换抛出异常的密钥字符串?
答案 0 :(得分:1)
为了能够使用AES算法加密,您需要将密钥基于至少128位字符串。 (其他价值观也是合法的,但我没有这些价值)
要将其转换为您提供的键字符串中所需的字符数,您可以将128除以8
128 / 8 = 16 alpha-numeric characters
这可以解决您的问题。
修改强>
对BASE64的评论回答: BASE64是一种不同的字符串编码方式。 BASE64编码的结果可能是128位字符串,但默认情况下不是。实际上没有BASE64编码结果的默认长度。结果可能是8个字符或512,或者其他符合BASE64编码规则的输出,这一切都取决于您编码的字符串。
答案 1 :(得分:0)
AES需要一个长度为128,192或256位的密钥。尝试使用更长的密钥。
答案 2 :(得分:0)
以下是生成AES密钥的工作示例:
private static SecretKeySpec key;
private static final int ENCRYPTION_KEY_SIZE = 128;
private static SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = null;
keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(ENCRYPTION_KEY_SIZE);
SecretKey key = keyGenerator.generateKey();
return key;
}
public void createNewEncrytionKey() throws NoSuchAlgorithmException, Exception {
SecretKey newKey = generateKey();
saveKey(newKey);
LogUtil.logMessage("createNewEncrytionKey", "New random encryption key was created.", logger);
key = (SecretKeySpec) newKey;
}
然后您可以使用该密钥加密\解密您的代码(在示例中,我将加密值转换为十六进制格式:
/**
* Encrypt a given text
*
* @param value String to encrypt
* @return encrypted String value
*/
public static String encrypt(String value) {
if (null == key) {
throw new RuntimeException("Secret encryption key not found!");
}
Cipher c;
String result = null;
try {
c = Cipher.getInstance(ENCRYPTION_ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
// 1. convert value to byte array
byte[] bvalue = value.getBytes();
// 2. convert to encrypted byte array
byte[] encrypted = c.doFinal(bvalue);
// 3. convert to hexadecimal representation
result = toHexString(encrypted);
} catch (Exception e) {
LogUtil.logError("encrypt", e, logger);
}
return result;
}
/**
* Decrypt a given text
*
* @param value encrypted String value
* @return Decrypted value
*/
public static String decrypt(String value) {
if (null == key) {
throw new RuntimeException("Secret encryption key not found!");
}
Cipher c;
String result = null;
try {
// 1. convert hex to encrypted byte array
byte[] encrypted = hexToByteArray(value);
// 2. convert to decrypted byte array
c = Cipher.getInstance(ENCRYPTION_ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = c.doFinal(encrypted);
// 3. convert to plain string
result = bytesToString(decrypted);
} catch (Exception e) {
LogUtil.logError("decrypt", e, logger);
}
return result;
}
答案 3 :(得分:0)
您的问题与AES或加密无关。但是,您尝试将随机字节序列解释为UTF-8编码字符(b
是AES密钥):
String decoded = new String(b, "UTF-8");
这不会起作用,因为你的字节数组很可能包含几个字节序列,这些字节序列对UTF-8无效。如果需要字节数组内容的字符串表示,则必须使用例如数据编码数据。 base64或十六进制编码。