Java 将字符串转换为 AES 的 128 位密钥
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22410602/
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
Turn String to 128-bit key for AES
提问by Παναγι?τη? Νικολαρ?πουλο?
I want to enter my own String variable to then turn it into a key for encryption/decryption for AES algorithm. I have tried many known ways such as UTF-8, base64, some methods doing conversion byte-string and vice versa and some other. Although it's true that all of them work even with some of them not working accurately, all of them turn the string in bytes, but what i want is to enter something like "helloWorld" and get back a 128-bit key for AES. Anything i use it goes for "Invalid key length" since the bytes are not accurate. What do i need to do to get the correct bytes? Also i want to clarify that i want String and not an array of char since i want to make it as a function in my programm later so that the user can change the key at will should it be compromised.
我想输入我自己的 String 变量,然后将其转换为 AES 算法加密/解密的密钥。我尝试了许多已知的方法,例如 UTF-8、base64、一些方法进行字节字符串的转换,反之亦然,以及其他一些方法。尽管确实所有这些都可以工作,即使其中一些无法准确工作,但所有这些都以字节为单位转换字符串,但我想要的是输入“helloWorld”之类的内容并取回 AES 的 128 位密钥。我使用它的任何东西都用于“无效的密钥长度”,因为字节不准确。我需要做什么才能获得正确的字节?另外我想澄清一下,我想要 String 而不是 char 数组,因为我想稍后在我的程序中将它作为一个函数,以便用户可以随意更改密钥,以防它受到损害。
UPDATE: i edited the example and this i what i have so far, still throws exception about parameters and key length though
更新:我编辑了这个例子,这是我到目前为止所拥有的,但仍然抛出关于参数和密钥长度的异常
public class SHAHashingExample
{
private static byte[] keyValue;
public static void main(String[] args)throws Exception
{
String password = "123456";
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(password.getBytes());
byte byteData[] = md.digest();
keyValue = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length/2; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
System.out.println("Hex format : " + sb.toString());
//convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length/2;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
System.out.println("Hex format : " + hexString.toString());
String k = "hello world";
String f = encrypt(k);
System.out.println(f);
String j = decrypt(f);
System.out.println(j);
}
public static String encrypt(String Data) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.ENCRYPT_MODE, key);
byte[] encVal = c.doFinal(Data.getBytes());
String encryptedValue = new BASE64Encoder().encode(encVal);
return encryptedValue;
}
public static String decrypt(String encryptedData) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance("AES");
c.init(Cipher.DECRYPT_MODE, key);
byte[] decordedValue = new BASE64Decoder().decodeBuffer(encryptedData);
byte[] decValue = c.doFinal(decordedValue);
String decryptedValue = new String(decValue);
return decryptedValue;
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, "AES");
return key;
}
}
采纳答案by trumpetlicks
UPDATE 2:Turns out your usage of many components of the Java Cipher capabilities are not spot on. Look here at this other SO answer.
更新 2:事实证明,您对 Java Cipher 功能的许多组件的使用并不正确。看看这里的其他 SO 答案。
UPDATE 1:To get the 256 bit value down to 128 bits using the example below, here is what you may want to try:
更新 1:要使用下面的示例将 256 位值降低到 128 位,您可能想尝试以下操作:
// After you already have generated the digest
byte[] mdbytes = md.digest();
byte[] key = new byte[mdbytes.length / 2];
for(int I = 0; I < key.length; I++){
// Choice 1 for using only 128 bits of the 256 generated
key[I] = mdbytes[I];
// Choice 2 for using ALL of the 256 bits generated
key[I] = mdbytes[I] ^ mdbytes[I + key.length];
}
// Now use key as the input key for AES
ORIGINAL:Here is a great example of using the built-in java APIs for performing a SHA hash on some data bytes.
原文:这是使用内置 java API 对某些数据字节执行 SHA 散列的一个很好的例子。
http://www.mkyong.com/java/java-sha-hashing-example/
http://www.mkyong.com/java/java-sha-hashing-example/
Java has built-in capability to perform multiple differing hash types, and you really should try to take advantage of one, instead of trying to write one yourself. Perhaps the most widely used hash functions are the SHA versions. There are versions that can output a 128, 256, and 512 bit hash output.
Java 具有执行多种不同散列类型的内置功能,您确实应该尝试利用其中一种,而不是尝试自己编写一种。也许最广泛使用的哈希函数是 SHA 版本。有些版本可以输出 128、256 和 512 位哈希输出。
What you are asking for, is in all technicality exactly how logging into a system using your password generally works. the system never truly stores your actual textual password, but rather the HASH to it. When you, the user, enters your password, the system performs a live hash of what you entered and compares the live generated hash with the stored hash. This does not go the added step of lets say using that hash as an actual key component for a symmetric encryption. In general a GOOD hash can indeed generate DECENT key material for use in actual symmetric encryption / decryption.
您要问的是,在所有技术上,使用您的密码登录系统通常是如何工作的。系统永远不会真正存储您的实际文本密码,而是存储它的哈希值。当您作为用户输入密码时,系统会对您输入的内容执行实时散列,并将实时生成的散列与存储的散列进行比较。这不是让我们说使用该哈希作为对称加密的实际密钥组件的附加步骤。一般来说,良好的散列确实可以生成用于实际对称加密/解密的 DECENT 密钥材料。
回答by ash_ap
What you are looking for is called a hash function. You will be able to enter an input of arbitrary length, and the hash function will always output a value of fixed bit size -- 128 bits in your case.
您正在寻找的称为散列函数。您将能够输入任意长度的输入,并且哈希函数将始终输出固定位大小的值——在您的情况下为 128 位。
There are many approaches to a hash function. The most simple one would be doing the modulo operationbetween an input number (an integer representation of your string, for example) and the maximum number that can be represented in nbits (in your case, 128); the output result will be an n-bit number that you can convert to whatever form you want (probably hexadecimal) and use it as an AES key.
哈希函数有很多方法。最简单的方法是在输入数字(例如字符串的整数表示)和可以用n位表示的最大数字(在您的情况下为 128)之间进行模运算;输出结果将是一个n位数字,您可以将其转换为您想要的任何形式(可能是十六进制)并将其用作 AES 密钥。
That isn't necessarily efficient (which is to say, the output 128-bit keys may not be very evenly distributed between 0 and 2^128 - 1), though -- more importantly, it would be quite slow for no good reason. Some efficient 128-bit hash functions are CityHash and MurmurHash -- you can look more up (as well as several Java implementations) on Google.
这不一定有效(也就是说,输出的 128 位密钥可能不会在 0 和 2^128 - 1 之间非常均匀地分布),但是——更重要的是,它会毫无理由地很慢。一些有效的 128 位哈希函数是 CityHash 和 MurmurHash —— 您可以在 Google 上查找更多信息(以及一些 Java 实现)。