部分解密废话
Part of Decrypt non-sense
我正在 android 聊天,这里我使用下一个方法生成密钥、加密和解密消息。问题是,当我在另一端发送消息时,例如 "hola",我收到 "holgAAAAAAAAAAAAAAA"。你能帮忙解决这个问题吗?
private byte[] K;
public void setK(){
KeyGenerator KeyGen=KeyGenerator.getInstance("AES");
KeyGen.init(128);
SecretKey key=KeyGen.generateKey();
K = key.getEncoded();
}
public String encrypt(byte[] input){
try {
IvParameterSpec iv = new IvParameterSpec(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
SecretKeySpec key = new SecretKeySpec(K, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
return Base64.encodeToString(cipherText, Base64.DEFAULT);
} catch (Exception e) {
Log.e(JUAN, "failed to encrypt ", e);
}
return null;
}
public String decrypt(byte[] input){
try {
IvParameterSpec iv = new IvParameterSpec(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
SecretKeySpec key = new SecretKeySpec(K, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, plainText, 0);
ctLength += cipher.doFinal(plainText, ctLength);
return Base64.encodeToString(plainText, Base64.DEFAULT);
} catch (Exception e) {
Log.e(JUAN, "failed to decrypt ", e);
}
return null;
}
编辑
这是我的要求,例如加密 "Hola".
encrypt(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
decrypt(Base64.decode(ciphertext, Base64.DEFAULT));
假设您的 public String decrypt(byte[] input)
方法中的参数 input
已成功由调用方从密文中进行 Base64 解码(因为您的加密 returns Base64 编码密码字符串).但是,在 decrypt()
方法中,您通过 getOutputSize() 方法创建了一个 byte
数组 plainText
。这使得 plainText
成为一个大小为 AES 块大小 (16) 倍数的数组。对于您的情况,plainText
是一个 16 byte
数组。因此,在解密并从密文中删除填充后,plainText
包含带有一些零的解密文本,然后将这些零编码为 AAA...As
。
所以使用
return Base64.encodeToString(plainText, 0, ctLength, Base64.DEFAULT);
而不是
return Base64.encodeToString(plainText, Base64.DEFAULT);
注意:您使用的是ECB
模式,所以您的IvParameterSpec
没有用。请改用 CBC
模式。
版次:你的电话有问题。试试这个
//Encryption side
String text = "hola, hi, anything u want";
byte[] plainText = text.getBytes("UTF-8");
String base64 = encrypt(plainText);
// Decryption side
byte[] cipherText = Base64.decode(base64, Base64.DEFAULT);
String plainEncodedText = decrypt(cipherText);
byte[] plainTextAsByte = Base64.decode(plainEncodedText, Base64.DEFAULT);
String plainTextAgain = new String(plainTextAsByte , "UTF-8");
现在打印 plainTextAgain
并希望这会起作用!
您的代码存在多个问题:
你的解密函数输入输出类型颠倒了。如果你加密了一个byte[]
,你解密的时候应该会得到一个。如果您的密文是 Base64 String
那么解密方法应该采用这样的 String
而不是 byte[]
.
String encrypt(byte[] plaintext) {
...
return Base64.encodeToString(cipher.doFinal(plaintext), Base64.DEFAULT);
}
byte[] encrypt(String ciphertext) {
...
return cipher.doFinal(Base64.decode(ciphertext.getBytes("UTF-8"), Base64.DEFAULT));
}
您将单个明文和密文传递到它们各自的方法中,但随后使用 cipher.update()
和 cipher.doFinal()
。这是没有必要的。您应该使用没有先前缓冲区的单个 cipher.doFinal()
调用。加密示例:
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = cipher.doFinal(plaintext);
因为 "Hola" 应该是用户输入的内容,所以从 Base 64 解码 没有任何意义。不是某人输入的所有字符串都是有效的 Base 64 编码,因此可以对其进行解码。您根本不应该解码输入,而是将其直接传递给 encrypt()
函数。
使用String#getBytes()
是不安全的,因为它使用了系统默认的Charset。当在接收系统上使用不同的默认字符集时,解密可能不会成功。自己指定Charset,解密后从byte[]
中获取String:
String ciphertext = encrypt(plaintext.getBytes("UTF-8"));
String recoveredPlaintext = new String(decrypt(ciphertext), "UTF-8");
您没有使用静态 IV。
安全问题:
- 您正在使用 ECB 模式。不要这样做!它在语义上不安全。至少使用带有随机 IV 的 CBC 模式。 IV 不必隐藏,因此您可以简单地将其添加到密文中。
- 您没有验证密文。您的系统可能容易受到 padding oracle 攻击。您应该使用像 HMAC-SHA256 这样具有强 MAC 的加密然后 MAC 方法,或者使用像 GCM 或 EAX 这样的 AES 认证操作模式。
使用例如 this library by Isaac Potoczny-Jones 与 Android 兼容。它支持具有随机 IV 和 HMAC-SHA256.
的密文身份验证的 AES-CBC
我正在 android 聊天,这里我使用下一个方法生成密钥、加密和解密消息。问题是,当我在另一端发送消息时,例如 "hola",我收到 "holgAAAAAAAAAAAAAAA"。你能帮忙解决这个问题吗?
private byte[] K;
public void setK(){
KeyGenerator KeyGen=KeyGenerator.getInstance("AES");
KeyGen.init(128);
SecretKey key=KeyGen.generateKey();
K = key.getEncoded();
}
public String encrypt(byte[] input){
try {
IvParameterSpec iv = new IvParameterSpec(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
SecretKeySpec key = new SecretKeySpec(K, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
return Base64.encodeToString(cipherText, Base64.DEFAULT);
} catch (Exception e) {
Log.e(JUAN, "failed to encrypt ", e);
}
return null;
}
public String decrypt(byte[] input){
try {
IvParameterSpec iv = new IvParameterSpec(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
SecretKeySpec key = new SecretKeySpec(K, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, plainText, 0);
ctLength += cipher.doFinal(plainText, ctLength);
return Base64.encodeToString(plainText, Base64.DEFAULT);
} catch (Exception e) {
Log.e(JUAN, "failed to decrypt ", e);
}
return null;
}
编辑 这是我的要求,例如加密 "Hola".
encrypt(Base64.decode("Hola".getBytes(), Base64.DEFAULT));
decrypt(Base64.decode(ciphertext, Base64.DEFAULT));
假设您的 public String decrypt(byte[] input)
方法中的参数 input
已成功由调用方从密文中进行 Base64 解码(因为您的加密 returns Base64 编码密码字符串).但是,在 decrypt()
方法中,您通过 getOutputSize() 方法创建了一个 byte
数组 plainText
。这使得 plainText
成为一个大小为 AES 块大小 (16) 倍数的数组。对于您的情况,plainText
是一个 16 byte
数组。因此,在解密并从密文中删除填充后,plainText
包含带有一些零的解密文本,然后将这些零编码为 AAA...As
。
所以使用
return Base64.encodeToString(plainText, 0, ctLength, Base64.DEFAULT);
而不是
return Base64.encodeToString(plainText, Base64.DEFAULT);
注意:您使用的是ECB
模式,所以您的IvParameterSpec
没有用。请改用 CBC
模式。
版次:你的电话有问题。试试这个
//Encryption side
String text = "hola, hi, anything u want";
byte[] plainText = text.getBytes("UTF-8");
String base64 = encrypt(plainText);
// Decryption side
byte[] cipherText = Base64.decode(base64, Base64.DEFAULT);
String plainEncodedText = decrypt(cipherText);
byte[] plainTextAsByte = Base64.decode(plainEncodedText, Base64.DEFAULT);
String plainTextAgain = new String(plainTextAsByte , "UTF-8");
现在打印 plainTextAgain
并希望这会起作用!
您的代码存在多个问题:
你的解密函数输入输出类型颠倒了。如果你加密了一个
byte[]
,你解密的时候应该会得到一个。如果您的密文是 Base64String
那么解密方法应该采用这样的String
而不是byte[]
.String encrypt(byte[] plaintext) { ... return Base64.encodeToString(cipher.doFinal(plaintext), Base64.DEFAULT); } byte[] encrypt(String ciphertext) { ... return cipher.doFinal(Base64.decode(ciphertext.getBytes("UTF-8"), Base64.DEFAULT)); }
您将单个明文和密文传递到它们各自的方法中,但随后使用
cipher.update()
和cipher.doFinal()
。这是没有必要的。您应该使用没有先前缓冲区的单个cipher.doFinal()
调用。加密示例:cipher.init(Cipher.ENCRYPT_MODE, key); byte[] cipherText = cipher.doFinal(plaintext);
因为 "Hola" 应该是用户输入的内容,所以从 Base 64 解码 没有任何意义。不是某人输入的所有字符串都是有效的 Base 64 编码,因此可以对其进行解码。您根本不应该解码输入,而是将其直接传递给
encrypt()
函数。使用
String#getBytes()
是不安全的,因为它使用了系统默认的Charset。当在接收系统上使用不同的默认字符集时,解密可能不会成功。自己指定Charset,解密后从byte[]
中获取String:String ciphertext = encrypt(plaintext.getBytes("UTF-8")); String recoveredPlaintext = new String(decrypt(ciphertext), "UTF-8");
您没有使用静态 IV。
安全问题:
- 您正在使用 ECB 模式。不要这样做!它在语义上不安全。至少使用带有随机 IV 的 CBC 模式。 IV 不必隐藏,因此您可以简单地将其添加到密文中。
- 您没有验证密文。您的系统可能容易受到 padding oracle 攻击。您应该使用像 HMAC-SHA256 这样具有强 MAC 的加密然后 MAC 方法,或者使用像 GCM 或 EAX 这样的 AES 认证操作模式。
使用例如 this library by Isaac Potoczny-Jones 与 Android 兼容。它支持具有随机 IV 和 HMAC-SHA256.
的密文身份验证的 AES-CBC