First of all I wanna say thank you...
首先,我想说谢谢……
I wrote a program which one is doing encryption and decryption with Enum. Enum has AES,BlowFish,DESede. My program will support these 3 encryption algorithm.
我编写了一个程序,其中一个是在Enum中进行加密和解密。Enum AES,河豚,DESede。我的程序将支持这3个加密算法。
Then I wanted to Generate a SecretKey with SecretKeyFactory.But I think,I made a mistake to generate a key. (Obviously I loose myself in code.I have no idea about what can I do...)
然后我想要生成一个秘密密钥工厂的秘钥。但我想,我犯了一个错误,要生成一把钥匙。(显然,我在代码中放松了自己。我不知道我能做什么……
My Code is below. This program's purpose is;
我的代码如下。这个项目的目的是;
- Users will write encryption and decryption method parameters. (Text,Encryption Algorithm)
- 用户将编写加密和解密方法参数。(文本、加密算法)
- Algorithm type will choose in Enum type. (Enum has 3 algorithm format)
- 算法类型将选择Enum类型。(Enum有3种算法格式)
- According to the entered Encryption Type,program will encrypt entered text.
- 根据输入的加密类型,程序将加密输入文本。
I know my code is really terrible. It has lots of unnecessary declaration and logical mistakes.
我知道我的代码非常糟糕。它有很多不必要的声明和逻辑错误。
Code is working fine sometimes,sometimes will crash.
代码有时工作得很好,有时会崩溃。
EDIT = Question is my code doesnt work always. Sometimes gives error. Error is = javax.crypto.BadPaddingException: Given final block not properly padded
编辑=问题是我的代码不总是工作。有时会带来误差。错误= javax.crypto。BadPaddingException:给定最终块未适当填充。
Thank you for answering.
谢谢你的回答。
import java.security.SecureRandom;
import java.security.spec.KeySpec;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
public class SymetricAlgorithms {
private static enum algorithms { //Enum declaration 3 encryption types here
AES, BlowFish, DESede;
}
private static String data = "HOWCANISOLVETHIS"; //this will be encrypt and decrypt
public static void main(String[] args) throws Throwable {
SecretKey kgen = GenerateKey(); // Create a key.
String encrypText = encrypt(kgen, data, algorithms.AES); //encrypt method calling here.
String decrypText = dencypt(kgen, encrypText, algorithms.AES);//decrypt method calling here.
System.out.println("plaintext = " + data + " key = " + kgen
+ "\nEncryptedText = " + encrypText
+ "\nDecryptedText = " + decrypText);
}
public static String dencypt(SecretKey inKey, String text, algorithms eValue)throws Throwable {//decryption
try {
byte[] text2 = text.getBytes(); //convert from parameters TEXT to Bytes
Cipher cipher = Cipher.getInstance("AES"); //Cipher initialize and choose encryption method (AES)
cipher.init(Cipher.DECRYPT_MODE, inKey); //cipher process
byte plainTextByte[] = new byte[20]; //Creating byte array
plainTextByte =cipher.doFinal(text2);//using byte array to assign ciphers result
System.out.println(plainTextByte);
return new String(plainTextByte);
} catch (Exception e) {
System.err.println("Data Cant Decrypted !");
e.printStackTrace();
}
return null;
}
public static String encrypt(SecretKey inKey, String text, algorithms eValue)
throws Throwable {
try {
Cipher cipher = null; //cipher declaration
switch (eValue) {//Enum. 3 types here and control structure for Users choosing encryption type is acceptable
case AES:cipher = Cipher.getInstance("AES");
break;
case BlowFish:Cipher cipher2 = Cipher.getInstance("BlowFish");
cipher = cipher2;
break;
case DESede:Cipher cipher3 = Cipher.getInstance("DESede");
cipher=cipher3;
break;
default:
System.out.println("Unexpectable value input.");
break;
}
System.out.println(inKey);
//Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, inKey);
byte[] ciphertext = cipher.doFinal(text.getBytes("UTF-8"));//cipher result is assign to byte array
System.out.println(ciphertext);
return new String(ciphertext);
} catch (Exception e) {
System.err.println("Unexpectable algorithm type !");
e.printStackTrace();
}
return null;
}
public static SecretKey GenerateKey() throws Throwable {//Generate a key for using crypt
//could sb explain these? =D I loose myself. I combined codes from finding internet...Failed...
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecureRandom prng = SecureRandom.getInstance("SHA1PRNG");
byte bytes[] = new byte[20];
prng.nextBytes(bytes);
String passwordTemp = prng.toString();
String saltTemp = passwordTemp;
char[] password = passwordTemp.toCharArray();
byte[] salt = saltTemp.getBytes();
KeySpec spec = new PBEKeySpec(password, salt, 65536, 128);
SecretKey tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
return secret;
} catch (Exception e) {
System.err.println("Key cant be generated !");
e.printStackTrace();
}
return null;
}
}
1 个解决方案
#1
3
The theme of the problem is misunderstanding of the relationship between Strings and bytes. At the end of the encrypt method, what do you think these two lines do:
问题的主题是对字符串和字节之间关系的误解。在加密方法的最后,你认为这两行做了什么:
byte[] ciphertext = cipher.doFinal(...
return new String(ciphertext);
The last line takes the encrypted bytes, which could be almost anything, and attempts to interpret those bytes as encoding some characters of a string. Using what encoding? String constructor with no character encoding argument uses system default encoding, which depends on JVM/OS/Locale. Lets say it is UTF-8. Are you guaranteed that there will actually be some character for the encrypted bytes? Answer: NO. Will you get the same bytes back, when you take the resulting string and call .getBytes("UTF-8"). Answer: No, there are mutliple byte sequences encoding the same characters, thus new String(bytes, "UTF-8").getBytes("UTF-8") is not guaranteed to return the bytes you started with.
最后一行采用加密字节,这几乎可以是任何东西,并试图将这些字节解释为编码字符串的某些字符。使用什么编码?没有字符编码参数的字符串构造函数使用系统默认编码,这依赖于JVM/OS/Locale。我们说它是UTF-8。你能保证加密字节会有一些字符吗?回答:没有。当您使用结果字符串并调用. getbytes(“UTF-8”)时,您会得到相同的字节吗?答:不,有一个编码相同字符的mutliple字节序列,因此新字符串(字节,“UTF-8”). getbytes(“UTF-8”)不能保证返回开始时的字节。
In summary, don't attempt to interpret arbitrary bytes as a string. Make your encrypt method return byte[], and your decryp method take an array of bytes to decode-- then it will work.
总之,不要试图将任意字节解释为字符串。让你的加密方法返回字节[],然后你的解密方法需要一个字节数组来解码——然后它就能工作了。
It is not necessary to make your program work, but if you must represent the encrypted bytes as a string, consider base64 encoding, or hexadecimal encoding -- these encodings uniquely map every possible byte (or sequence of bytes) to a string.
没有必要让程序工作,但是如果必须将加密的字节表示为字符串,考虑base64编码或十六进制编码——这些编码将每个可能的字节(或字节序列)映射到一个字符串。
UPDATE: here is a more concise generateKey() method. It allows you to pass the password in as an argument.
更新:这里有一个更简洁的generateKey()方法。它允许您将密码作为参数传递。
public static SecretKey generateKey(String password) {
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
byte saltBytes[] = new byte[20];
secureRandom.nextBytes(saltBytes);
KeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey secretKey = factory.generateSecret(spec);
return new SecretKeySpec(secretKey.getEncoded(), "AES");
} catch (Exception e) {
throw new IllegalStateException("Key cant be generated !");
}
}
#1
3
The theme of the problem is misunderstanding of the relationship between Strings and bytes. At the end of the encrypt method, what do you think these two lines do:
问题的主题是对字符串和字节之间关系的误解。在加密方法的最后,你认为这两行做了什么:
byte[] ciphertext = cipher.doFinal(...
return new String(ciphertext);
The last line takes the encrypted bytes, which could be almost anything, and attempts to interpret those bytes as encoding some characters of a string. Using what encoding? String constructor with no character encoding argument uses system default encoding, which depends on JVM/OS/Locale. Lets say it is UTF-8. Are you guaranteed that there will actually be some character for the encrypted bytes? Answer: NO. Will you get the same bytes back, when you take the resulting string and call .getBytes("UTF-8"). Answer: No, there are mutliple byte sequences encoding the same characters, thus new String(bytes, "UTF-8").getBytes("UTF-8") is not guaranteed to return the bytes you started with.
最后一行采用加密字节,这几乎可以是任何东西,并试图将这些字节解释为编码字符串的某些字符。使用什么编码?没有字符编码参数的字符串构造函数使用系统默认编码,这依赖于JVM/OS/Locale。我们说它是UTF-8。你能保证加密字节会有一些字符吗?回答:没有。当您使用结果字符串并调用. getbytes(“UTF-8”)时,您会得到相同的字节吗?答:不,有一个编码相同字符的mutliple字节序列,因此新字符串(字节,“UTF-8”). getbytes(“UTF-8”)不能保证返回开始时的字节。
In summary, don't attempt to interpret arbitrary bytes as a string. Make your encrypt method return byte[], and your decryp method take an array of bytes to decode-- then it will work.
总之,不要试图将任意字节解释为字符串。让你的加密方法返回字节[],然后你的解密方法需要一个字节数组来解码——然后它就能工作了。
It is not necessary to make your program work, but if you must represent the encrypted bytes as a string, consider base64 encoding, or hexadecimal encoding -- these encodings uniquely map every possible byte (or sequence of bytes) to a string.
没有必要让程序工作,但是如果必须将加密的字节表示为字符串,考虑base64编码或十六进制编码——这些编码将每个可能的字节(或字节序列)映射到一个字符串。
UPDATE: here is a more concise generateKey() method. It allows you to pass the password in as an argument.
更新:这里有一个更简洁的generateKey()方法。它允许您将密码作为参数传递。
public static SecretKey generateKey(String password) {
try {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
byte saltBytes[] = new byte[20];
secureRandom.nextBytes(saltBytes);
KeySpec spec = new PBEKeySpec(password.toCharArray(), saltBytes, 65536, 128);
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey secretKey = factory.generateSecret(spec);
return new SecretKeySpec(secretKey.getEncoded(), "AES");
} catch (Exception e) {
throw new IllegalStateException("Key cant be generated !");
}
}