我正在尝试学习一些加密,但不知何故我被困在了一个问题上。我想对文本执行某种 AES 加密(例如,字符串“密码”)。我有 ff 代码作为我的来源:
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
public class AES {
static String IV = "fedcba9876543210";
static String plaintext = "password"; /*Note null padding*/
//static String encryptionKey = "0123456789abcdef0123456789abcdef";
static String encKey = "cf6000c7452f9487cc03cd721a3f18482e43cdcc37c380e062193c489f968d04";
static String encryptionKey = "";
public static void main(String [] args) {
try {
System.out.print(plaintext.length() + "\n");
if (plaintext.length() < 16) {
int pad = 16 - plaintext.length();
String repeated = new String(new char[pad]).replace("\0", "\0");
plaintext = plaintext + repeated;
}
System.out.println("==Java==");
System.out.println("plain: " + plaintext);
System.out.print(plaintext.length() + "\n");
encryptionKey = hexToAscii(encKey);
//encryptionKey = "0123456789abcdef0123456789abcdef";
byte[] cipher = encrypt(plaintext, encryptionKey);
String a = byteArrayToHex(cipher);
System.out.print(a + "\n");
System.out.print("cipher: ");
for (int i=0; i<cipher.length; i++)
System.out.print(new Integer(cipher[i])+" ");
System.out.println("");
String decrypted = decrypt(cipher, encryptionKey);
System.out.println("decrypt: " + decrypted);
} catch (Exception e) {
e.printStackTrace();
}
}
public static byte[] encrypt(String plainText, String string) throws Exception {
//System.out.println("encrypting" + encryptionKey.length());
// Check length, in characters
System.out.println("Length of string is " + string.length()); // prints "11"
// Check encoded sizes
final byte[] utf8Bytes = string.getBytes("UTF-8");
System.out.println(utf8Bytes.length); // prints "11"
final byte[] utf16Bytes= string.getBytes("UTF-16");
System.out.println(utf16Bytes.length); // prints "24"
final byte[] utf32Bytes = string.getBytes("UTF-32");
System.out.println(utf32Bytes.length); // prints "44"
final byte[] isoBytes = string.getBytes("ISO-8859-1");
System.out.println(isoBytes.length); // prints "11"
final byte[] winBytes = string.getBytes("CP1252");
System.out.println(winBytes.length); // prints "11"
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
System.out.println("enc 2");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
System.out.println("enc 3");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
System.out.println("enc 4");
return cipher.doFinal(plainText.getBytes("UTF-8"));
}
public static String hexToAscii(String s) {
int n = s.length();
StringBuilder sb = new StringBuilder(n / 2);
for (int i = 0; i < n; i += 2) {
char a = s.charAt(i);
char b = s.charAt(i + 1);
sb.append((char) ((hexToInt(a) << 4) | hexToInt(b)));
}
return sb.toString();
}
public static String decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return new String(cipher.doFinal(cipherText),"UTF-8");
}
public static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder(a.length * 2);
for(byte b: a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}
private static int hexToInt(char ch) {
if ('a' <= ch && ch <= 'f') { return ch - 'a' + 10; }
if ('A' <= ch && ch <= 'F') { return ch - 'A' + 10; }
if ('0' <= ch && ch <= '9') { return ch - '0'; }
throw new IllegalArgumentException(String.valueOf(ch));
}
}
字符串 "cf6000c7452f9487cc03cd721a3f18482e43cdcc37c380e062193c489f968d04"
是一个由 64 个十六进制数字组成的序列,我希望在转换为字符串时相当于 32 个字符。使用这 32 个字符作为我的 key ,我无法如上面的代码所示进行加密,因为对 key 的 getBytes 调用以某种方式将其设置为 46 字节。
在长度为 32 个字符的 0123456789abcdef0123456789abcdef
等纯字符串(非十六进制)上,整个加密过程就像使用此字符串调用 getBytes 一样,因为 key 的长度为 32 字节.
有什么想法吗?理想情况下,我想知道如何使用第一个十六进制数字序列(要转换为字符串)作为 key 来加密文本。我已经在 python 中成功地做到了这一点,但是这在 Java 中可能吗?
最佳答案
永远不要假设字符串中的一个字符占用一个字节。
这是真的,在大多数编码中,仅适用于小于 128 的字符。
由于 hexToAscii
返回一个包含 128-255 范围内字符的字符串,这些字符将被编码为一个以上的字节。
解决方案是不将键视为字符串。字符串用于文本;加密 key 不是文本,而是字节序列。而是将加密 key 存储在字节数组中。 hexToAscii
应该返回一个字节数组,encrypt
应该只需要对明文调用getBytes
。
关于java - 一个32个字符的字符串如何变成46个字节?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28034744/