Java AES 并使用我自己的密钥
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3451670/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java AES and using my own Key
提问by Bernie Perez
I want to encrypt a string using AES with my own key. But I'm having trouble with the bit length of the key. Can you review my code and see what I need to fix/change.
我想用我自己的密钥使用 AES 加密一个字符串。但是我对密钥的位长有问题。您能否查看我的代码并查看我需要修复/更改的内容。
public static void main(String[] args) throws Exception {
String username = "[email protected]";
String password = "Password1";
String secretID = "BlahBlahBlah";
String SALT2 = "deliciously salty";
// Get the Key
byte[] key = (SALT2 + username + password).getBytes();
System.out.println((SALT2 + username + password).getBytes().length);
// Need to pad key for AES
// TODO: Best way?
// Generate the secret key specs.
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
// Instantiate the cipher
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] encrypted = cipher.doFinal((secrectID).getBytes());
System.out.println("encrypted string: " + asHex(encrypted));
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
byte[] original = cipher.doFinal(encrypted);
String originalString = new String(original);
System.out.println("Original string: " + originalString + "\nOriginal string (Hex): " + asHex(original));
}
Right now I get an exception "Invalid AES key length: 86 bytes". Do I need to pad my key? How should I do it?
现在我收到一个异常“无效的 AES 密钥长度:86 字节”。我需要垫我的钥匙吗?我该怎么做?
Also do I need to set anything for ECB or CBC?
我还需要为 ECB 或 CBC 设置什么吗?
Thanks
谢谢
采纳答案by mknjc
Edit:
编辑:
As written in the comments the old code is not "best practice". You should use a keygeneration algorithm like PBKDF2 with a high iteration count. You also should use at least partly a non static (meaning for each "identity" exclusive) salt. If possible randomly generated and stored together with the ciphertext.
正如评论中所写,旧代码不是“最佳实践”。您应该使用具有高迭代次数的密钥生成算法,例如 PBKDF2。您还应该至少部分使用非静态(意味着每个“身份”专有)盐。如果可能,随机生成并与密文一起存储。
SecureRandom sr = SecureRandom.getInstanceStrong();
byte[] salt = new byte[16];
sr.nextBytes(salt);
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 1000, 128 * 8);
SecretKey key = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1").generateSecret(spec);
Cipher aes = Cipher.getInstance("AES");
aes.init(Cipher.ENCRYPT_MODE, key);
===========
============
Old Answer
旧答案
You should use SHA-1 to generate a hash from your key and trim the result to 128 bit (16 bytes).
您应该使用 SHA-1 从您的密钥生成散列并将结果修剪为 128 位(16 字节)。
Additionally don't generate byte arrays from Strings through getBytes()it uses the platform default Charset. So the password "bla??" results in different byte array on different platforms.
此外,不要通过getBytes()从字符串生成字节数组,它使用平台默认字符集。所以密码“bla??” 在不同平台上产生不同的字节数组。
byte[] key = (SALT2 + username + password).getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
Edit: If you need 256 bit as key sizes you need to download the "Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files" Oracle download link, use SHA-256 as hash and remove the Arrays.copyOfline. "ECB" is the default Cipher Mode and "PKCS5Padding" the default padding. You could use different Cipher Modes and Padding Modes through the Cipher.getInstancestring using following format: "Cipher/Mode/Padding"
编辑:如果您需要 256 位作为密钥大小,您需要下载“Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files” Oracle 下载链接,使用 SHA-256 作为哈希并删除Arrays.copyOf行。“ECB”是默认密码模式,“PKCS5Padding”是默认填充。您可以使用以下格式通过Cipher.getInstance字符串使用不同的密码模式和填充模式:“密码/模式/填充”
For AES using CTS and PKCS5Padding the string is: "AES/CTS/PKCS5Padding"
对于使用 CTS 和 PKCS5Padding 的 AES,字符串为:“AES/CTS/PKCS5Padding”
回答by Keibosh
You should use a KeyGenerator to generate the Key,
您应该使用 KeyGenerator 来生成密钥,
AES key lengths are 128, 192, and 256 bit depending on the cipher you want to use.
AES 密钥长度为 128、192 和 256 位,具体取决于您要使用的密码。
Take a look at the tutorial here
看看这里的教程
Here is the code for Password Based Encryption, this has the password being entered through System.in you can change that to use a stored password if you want.
这是基于密码的加密的代码,这是通过 System.in 输入的密码,如果需要,您可以将其更改为使用存储的密码。
PBEKeySpec pbeKeySpec;
PBEParameterSpec pbeParamSpec;
SecretKeyFactory keyFac;
// Salt
byte[] salt = {
(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
// Iteration count
int count = 20;
// Create PBE parameter set
pbeParamSpec = new PBEParameterSpec(salt, count);
// Prompt user for encryption password.
// Collect user password as char array (using the
// "readPassword" method from above), and convert
// it into a SecretKey object, using a PBE key
// factory.
System.out.print("Enter encryption password: ");
System.out.flush();
pbeKeySpec = new PBEKeySpec(readPassword(System.in));
keyFac = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);
// Create PBE Cipher
Cipher pbeCipher = Cipher.getInstance("PBEWithMD5AndDES");
// Initialize PBE Cipher with key and parameters
pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);
// Our cleartext
byte[] cleartext = "This is another example".getBytes();
// Encrypt the cleartext
byte[] ciphertext = pbeCipher.doFinal(cleartext);
回答by Shankar Murthy
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.*;
import java.io.BufferedReader;
import java.io.FileReader;
public class AESFile
{
private static String algorithm = "AES";
private static byte[] keyValue=new byte[] {'0','2','3','4','5','6','7','8','9','1','2','3','4','5','6','7'};// your key
// Performs Encryption
public static String encrypt(String plainText) throws Exception
{
Key key = generateKey();
Cipher chiper = Cipher.getInstance(algorithm);
chiper.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = chiper.doFinal(plainText.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
// Performs decryption
public static String decrypt(String encryptedText) throws Exception
{
// generate key
Key key = generateKey();
Cipher chiper = Cipher.getInstance(algorithm);
chiper.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedText);
byte[] decValue = chiper.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
//generateKey() is used to generate a secret key for AES algorithm
private static Key generateKey() throws Exception
{
Key key = new SecretKeySpec(keyValue, algorithm);
return key;
}
// performs encryption & decryption
public static void main(String[] args) throws Exception
{
FileReader file = new FileReader("C://myprograms//plaintext.txt");
BufferedReader reader = new BufferedReader(file);
String text = "";
String line = reader.readLine();
while(line!= null)
{
text += line;
line = reader.readLine();
}
reader.close();
System.out.println(text);
String plainText = text;
String encryptedText = AESFile.encrypt(plainText);
String decryptedText = AESFile.decrypt(encryptedText);
System.out.println("Plain Text : " + plainText);
System.out.println("Encrypted Text : " + encryptedText);
System.out.println("Decrypted Text : " + decryptedText);
}
}
回答by Taran
This wll work.
这会起作用。
public class CryptoUtils {
private final String TRANSFORMATION = "AES";
private final String encodekey = "1234543444555666";
public String encrypt(String inputFile)
throws CryptoException {
return doEncrypt(encodekey, inputFile);
}
public String decrypt(String input)
throws CryptoException {
// return doCrypto(Cipher.DECRYPT_MODE, key, inputFile);
return doDecrypt(encodekey,input);
}
private String doEncrypt(String encodekey, String inputStr) throws CryptoException {
try {
Cipher cipher = Cipher.getInstance(TRANSFORMATION);
byte[] key = encodekey.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
byte[] inputBytes = inputStr.getBytes();
byte[] outputBytes = cipher.doFinal(inputBytes);
return Base64Utils.encodeToString(outputBytes);
} catch (NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | IOException ex) {
throw new CryptoException("Error encrypting/decrypting file", ex);
}
}
public String doDecrypt(String encodekey,String encrptedStr) {
try {
Cipher dcipher = Cipher.getInstance(TRANSFORMATION);
dcipher = Cipher.getInstance("AES");
byte[] key = encodekey.getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
dcipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
// decode with base64 to get bytes
byte[] dec = Base64Utils.decode(encrptedStr.getBytes());
byte[] utf8 = dcipher.doFinal(dec);
// create new string based on the specified charset
return new String(utf8, "UTF8");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
回答by sonnykwe
byte[] seed = (SALT2 + username + password).getBytes();
SecureRandom random = new SecureRandom(seed);
KeyGenerator generator;
generator = KeyGenerator.getInstance("AES");
generator.init(random);
generator.init(256);
Key keyObj = generator.generateKey();
回答by Mykhaylo Adamovych
MD5, AES, no padding
MD5,AES,无填充
import static javax.crypto.Cipher.DECRYPT_MODE;
import static javax.crypto.Cipher.ENCRYPT_MODE;
import static org.apache.commons.io.Charsets.UTF_8;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class PasswordUtils {
private PasswordUtils() {}
public static String encrypt(String text, String pass) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
Key key = new SecretKeySpec(messageDigest.digest(pass.getBytes(UTF_8)), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(text.getBytes(UTF_8));
byte[] encoded = Base64.getEncoder().encode(encrypted);
return new String(encoded, UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException("Cannot encrypt", e);
}
}
public static String decrypt(String text, String pass) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
Key key = new SecretKeySpec(messageDigest.digest(pass.getBytes(UTF_8)), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(DECRYPT_MODE, key);
byte[] decoded = Base64.getDecoder().decode(text.getBytes(UTF_8));
byte[] decrypted = cipher.doFinal(decoded);
return new String(decrypted, UTF_8);
} catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException e) {
throw new RuntimeException("Cannot decrypt", e);
}
}
}