整数数组 AES 加密中增加的密码长度
Increased cipher length in Integer array AES encryption
在下面的代码中,我采用了一个整数数组并执行了 AES 加密。输入是一个大小为 16 的整数数组。当我加密数据时,我得到的密码 byte[] 大小为 64。
很明显一个整数占4B,所以16 * 4 = 64,也就是密码长度。但是如果我对图像(512 X 512)实施相同的技术,那么加密图像的大小可能是原始图像的四倍!
在图像的情况下如何使密码长度等于明文长度??
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class StreamDemo2 {
static String IV = "AAAAAAAAAAAAAAAA";
static String encryptionKey = "0123456789abcdef";
public static void main(String ad[])
{
StreamDemo2 st = new StreamDemo2();
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
DataOutputStream dos = new DataOutputStream (baos);
int arr[] = new int[16];
for(int k = 0 ; k < 16; k++)
arr[k] = k + 11;
for(int k = 0 ; k < 16; k++)
System.out.println(" USER Plain text = " + arr[k]);
try{
for(int i = 0; i < 16;i++)
dos.writeInt (arr[i]);
}
catch(Exception e)
{
e.printStackTrace();
}
byte[] data = baos.toByteArray();
// conversion to bytes ends here
// Now follows the mehtod invoking
byte[] c = null;
try{
c = st.encrypt(data, encryptionKey);
}
catch(Exception e )
{
e.printStackTrace();
}
System.out.println("Cipher length = " + c.length);
// Now follows the code to decrypt
byte[] d = null;
try{
d = st.decrypt(c, encryptionKey);
}
catch(Exception e)
{
e.printStackTrace();
}
ByteArrayInputStream bais = new ByteArrayInputStream (d);
DataInputStream dis = new DataInputStream (bais);
int j;
System.out.println("Original data is : ");
try{
for(int k =0; k < 16; k++)
System.out.print(dis.readInt() + "\t");
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static byte[] encrypt(byte[] ciph, String encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(ciph);
}
public static byte[] decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
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"); // changed since the receiveing side expects the byte[]
return cipher.doFinal(cipherText);
}
}
(AES) 加密直接作用于字节。它对您的图像有多大或如何编码一无所知。这是你必须考虑的。如果你有一张 512x512 像素的图片,那么你应该考虑一下它在序列化时是如何表示的。
一个像素通常由三个通道组成。一个示例是 RGB(红-绿-蓝),其他示例是 HSL/HSV/YCrCb。每个通道的常见细节深度是 8 位。所以你可以用 3 个字节来表示每个像素。如果你想正确地读回那些像素,你应该知道尺寸有多大,所以你在图像数据格式的开头添加两个整数(尺寸限制)就完成了。这是最基本的格式,需要
3 * 512 * 512 + 2 * 4 bytes = 786440 bytes
这不是 16 字节的倍数,因此需要填充以进行加密。这可以通过实例化提供填充的 Cipher
来直接实现。否则,您将不得不自己做:
Cipher.getInstance("AES/CBC/PKCS5Padding");
当然,如果您只有灰度图像或不同的通道深度(例如 16 位以获得更高质量),此示例计算看起来会有所不同。
当你说
then the cipher image size may be four times the original image
你是在比较苹果和橙子(像素和字节)。但是,您可以将密文解释为图像数据。这是一个有趣的实验。看一下 ECB penguin。
在测试阶段结束时,请务必使用适当的随机生成的加密密钥。可打印密钥比随机生成的密钥更容易暴力破解。
始终为每次加密使用新的随机生成的 IV。这提供了语义安全性。
使用经过身份验证的加密来防止填充 oracle 攻击和检测(恶意)操纵。这可以通过像 GCM 或 EAX 这样的身份验证模式来完成,或者通过像 HMAC-SHA256.
这样具有强大 MAC 功能的加密然后 MAC 方案来完成
在下面的代码中,我采用了一个整数数组并执行了 AES 加密。输入是一个大小为 16 的整数数组。当我加密数据时,我得到的密码 byte[] 大小为 64。 很明显一个整数占4B,所以16 * 4 = 64,也就是密码长度。但是如果我对图像(512 X 512)实施相同的技术,那么加密图像的大小可能是原始图像的四倍! 在图像的情况下如何使密码长度等于明文长度??
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.security.MessageDigest;
import java.util.Arrays;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class StreamDemo2 {
static String IV = "AAAAAAAAAAAAAAAA";
static String encryptionKey = "0123456789abcdef";
public static void main(String ad[])
{
StreamDemo2 st = new StreamDemo2();
ByteArrayOutputStream baos = new ByteArrayOutputStream ();
DataOutputStream dos = new DataOutputStream (baos);
int arr[] = new int[16];
for(int k = 0 ; k < 16; k++)
arr[k] = k + 11;
for(int k = 0 ; k < 16; k++)
System.out.println(" USER Plain text = " + arr[k]);
try{
for(int i = 0; i < 16;i++)
dos.writeInt (arr[i]);
}
catch(Exception e)
{
e.printStackTrace();
}
byte[] data = baos.toByteArray();
// conversion to bytes ends here
// Now follows the mehtod invoking
byte[] c = null;
try{
c = st.encrypt(data, encryptionKey);
}
catch(Exception e )
{
e.printStackTrace();
}
System.out.println("Cipher length = " + c.length);
// Now follows the code to decrypt
byte[] d = null;
try{
d = st.decrypt(c, encryptionKey);
}
catch(Exception e)
{
e.printStackTrace();
}
ByteArrayInputStream bais = new ByteArrayInputStream (d);
DataInputStream dis = new DataInputStream (bais);
int j;
System.out.println("Original data is : ");
try{
for(int k =0; k < 16; k++)
System.out.print(dis.readInt() + "\t");
}
catch(Exception e)
{
e.printStackTrace();
}
}
public static byte[] encrypt(byte[] ciph, String encryptionKey) throws Exception {
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
SecretKeySpec key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.ENCRYPT_MODE, key,new IvParameterSpec(IV.getBytes("UTF-8")));
return cipher.doFinal(ciph);
}
public static byte[] decrypt(byte[] cipherText, String encryptionKey) throws Exception{
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding", "SunJCE");
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"); // changed since the receiveing side expects the byte[]
return cipher.doFinal(cipherText);
}
}
(AES) 加密直接作用于字节。它对您的图像有多大或如何编码一无所知。这是你必须考虑的。如果你有一张 512x512 像素的图片,那么你应该考虑一下它在序列化时是如何表示的。
一个像素通常由三个通道组成。一个示例是 RGB(红-绿-蓝),其他示例是 HSL/HSV/YCrCb。每个通道的常见细节深度是 8 位。所以你可以用 3 个字节来表示每个像素。如果你想正确地读回那些像素,你应该知道尺寸有多大,所以你在图像数据格式的开头添加两个整数(尺寸限制)就完成了。这是最基本的格式,需要
3 * 512 * 512 + 2 * 4 bytes = 786440 bytes
这不是 16 字节的倍数,因此需要填充以进行加密。这可以通过实例化提供填充的 Cipher
来直接实现。否则,您将不得不自己做:
Cipher.getInstance("AES/CBC/PKCS5Padding");
当然,如果您只有灰度图像或不同的通道深度(例如 16 位以获得更高质量),此示例计算看起来会有所不同。
当你说
then the cipher image size may be four times the original image
你是在比较苹果和橙子(像素和字节)。但是,您可以将密文解释为图像数据。这是一个有趣的实验。看一下 ECB penguin。
在测试阶段结束时,请务必使用适当的随机生成的加密密钥。可打印密钥比随机生成的密钥更容易暴力破解。
始终为每次加密使用新的随机生成的 IV。这提供了语义安全性。
使用经过身份验证的加密来防止填充 oracle 攻击和检测(恶意)操纵。这可以通过像 GCM 或 EAX 这样的身份验证模式来完成,或者通过像 HMAC-SHA256.
这样具有强大 MAC 功能的加密然后 MAC 方案来完成