AES 加密 IV
AES Encryption IV's
我在下面的 (E.1) 中使用这个作为我的应用程序,显然这里面有一个我认识和理解的巨大明显的安全漏洞。我对加密越来越感兴趣,想更好地理解它,我需要生成一个随机密钥和一个 IV,但不确定如何正确执行) 所以以后能更好的理解和应用我的知识,本质上我只是想让代码更安全,谢谢。
(E.1)
byte[] key = "mykey".getBytes("UTF-8");
private byte[] getKeyBytes(final byte[] key) throws Exception {
byte[] keyBytes = new byte[16];
System.arraycopy(key, 0, keyBytes, 0, Math.min(key.length, keyBytes.length));
return keyBytes;
}
public Cipher getCipherEncrypt(final byte[] key) throws Exception {
byte[] keyBytes = getKeyBytes(key);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher;
}
public void encrypt(File in, File output, byte[] key) throws Exception {
Cipher cipher = getCipherEncrypt(key);
FileOutputStream fos = null;
CipherOutputStream cos = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(in);
fos = new FileOutputStream(output);
cos = new CipherOutputStream(fos, cipher);
byte[] data = new byte[1024];
int read = fis.read(data);
while (read != -1) {
cos.write(data, 0, read);
read = fis.read(data);
System.out.println(new String(data, "UTF-8").trim());
}
cos.flush();
} finally {
System.out.println("performed encrypt method now closing streams:\n" + output.toString());
cos.close();
fos.close();
fis.close();
}
}
public void watchMeEncrypt(){
encrypt(file, new File ("example.txt),key);
AES 密钥仅由随机字节组成。对于 CBC 模式,IV 模式也应该是随机的(至少对于攻击者而言)。所以通常你可以简单地使用一个 SecureRandom
实例来创建密钥和 IV。然后可以将 IV 包含在密文中;通常它只是简单地放在它前面。
使用 Java 时最好使用 KeyGenerator
。如果您查看它在 SUN 提供程序中的实现,它可能相当于同一件事。但是,使用 KeyGenerator
与各种密钥和提供程序更兼容。这很可能是生成密钥的要求,例如智能卡和 HSM。
那么让我们用三个简单的方法展示一个 class:
package nl.owlstead.Whosebug;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.Optional;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class CreateKeyAndIVForAES_CBC {
public static SecretKey createKey(final String algorithm, final int keysize, final Optional<Provider> provider, final Optional<SecureRandom> rng) throws NoSuchAlgorithmException {
final KeyGenerator keyGenerator;
if (provider.isPresent()) {
keyGenerator = KeyGenerator.getInstance(algorithm, provider.get());
} else {
keyGenerator = KeyGenerator.getInstance(algorithm);
}
if (rng.isPresent()) {
keyGenerator.init(keysize, rng.get());
} else {
// not really needed for the Sun provider which handles null OK
keyGenerator.init(keysize);
}
return keyGenerator.generateKey();
}
public static IvParameterSpec createIV(final int ivSizeBytes, final Optional<SecureRandom> rng) {
final byte[] iv = new byte[ivSizeBytes];
final SecureRandom theRNG = rng.orElse(new SecureRandom());
theRNG.nextBytes(iv);
return new IvParameterSpec(iv);
}
public static IvParameterSpec readIV(final int ivSizeBytes, final InputStream is) throws IOException {
final byte[] iv = new byte[ivSizeBytes];
int offset = 0;
while (offset < ivSizeBytes) {
final int read = is.read(iv, offset, ivSizeBytes - offset);
if (read == -1) {
throw new IOException("Too few bytes for IV in input stream");
}
offset += read;
}
return new IvParameterSpec(iv);
}
public static void main(String[] args) throws Exception {
final SecureRandom rng = new SecureRandom();
// you somehow need to distribute this key
final SecretKey aesKey = createKey("AES", 128, Optional.empty(), Optional.of(rng));
final byte[] plaintext = "owlstead".getBytes(UTF_8);
final byte[] ciphertext;
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivForCBC = createIV(aesCBC.getBlockSize(), Optional.of(rng));
aesCBC.init(Cipher.ENCRYPT_MODE, aesKey, ivForCBC);
baos.write(ivForCBC.getIV());
try (final CipherOutputStream cos = new CipherOutputStream(baos, aesCBC)) {
cos.write(plaintext);
}
ciphertext = baos.toByteArray();
}
final byte[] decrypted;
{
final ByteArrayInputStream bais = new ByteArrayInputStream(ciphertext);
final Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivForCBC = readIV(aesCBC.getBlockSize(), bais);
aesCBC.init(Cipher.DECRYPT_MODE, aesKey, ivForCBC);
final byte[] buf = new byte[1_024];
try (final CipherInputStream cis = new CipherInputStream(bais, aesCBC);
final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int read;
while ((read = cis.read(buf)) != -1) {
baos.write(buf, 0, read);
}
decrypted = baos.toByteArray();
}
}
System.out.println(new String(decrypted, UTF_8));
}
}
请注意,您可能并不总是希望生成和分发 AES 密钥 "out-of-band"。这里是 a few other methods of generating a key (part #2 onwards). You may also want to take a look at more advanced exception handling for the cryptographic operation.
我在下面的 (E.1) 中使用这个作为我的应用程序,显然这里面有一个我认识和理解的巨大明显的安全漏洞。我对加密越来越感兴趣,想更好地理解它,我需要生成一个随机密钥和一个 IV,但不确定如何正确执行) 所以以后能更好的理解和应用我的知识,本质上我只是想让代码更安全,谢谢。
(E.1)
byte[] key = "mykey".getBytes("UTF-8");
private byte[] getKeyBytes(final byte[] key) throws Exception {
byte[] keyBytes = new byte[16];
System.arraycopy(key, 0, keyBytes, 0, Math.min(key.length, keyBytes.length));
return keyBytes;
}
public Cipher getCipherEncrypt(final byte[] key) throws Exception {
byte[] keyBytes = getKeyBytes(key);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES");
IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
return cipher;
}
public void encrypt(File in, File output, byte[] key) throws Exception {
Cipher cipher = getCipherEncrypt(key);
FileOutputStream fos = null;
CipherOutputStream cos = null;
FileInputStream fis = null;
try {
fis = new FileInputStream(in);
fos = new FileOutputStream(output);
cos = new CipherOutputStream(fos, cipher);
byte[] data = new byte[1024];
int read = fis.read(data);
while (read != -1) {
cos.write(data, 0, read);
read = fis.read(data);
System.out.println(new String(data, "UTF-8").trim());
}
cos.flush();
} finally {
System.out.println("performed encrypt method now closing streams:\n" + output.toString());
cos.close();
fos.close();
fis.close();
}
}
public void watchMeEncrypt(){
encrypt(file, new File ("example.txt),key);
AES 密钥仅由随机字节组成。对于 CBC 模式,IV 模式也应该是随机的(至少对于攻击者而言)。所以通常你可以简单地使用一个 SecureRandom
实例来创建密钥和 IV。然后可以将 IV 包含在密文中;通常它只是简单地放在它前面。
使用 Java 时最好使用 KeyGenerator
。如果您查看它在 SUN 提供程序中的实现,它可能相当于同一件事。但是,使用 KeyGenerator
与各种密钥和提供程序更兼容。这很可能是生成密钥的要求,例如智能卡和 HSM。
那么让我们用三个简单的方法展示一个 class:
package nl.owlstead.Whosebug;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
import java.security.SecureRandom;
import java.util.Optional;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class CreateKeyAndIVForAES_CBC {
public static SecretKey createKey(final String algorithm, final int keysize, final Optional<Provider> provider, final Optional<SecureRandom> rng) throws NoSuchAlgorithmException {
final KeyGenerator keyGenerator;
if (provider.isPresent()) {
keyGenerator = KeyGenerator.getInstance(algorithm, provider.get());
} else {
keyGenerator = KeyGenerator.getInstance(algorithm);
}
if (rng.isPresent()) {
keyGenerator.init(keysize, rng.get());
} else {
// not really needed for the Sun provider which handles null OK
keyGenerator.init(keysize);
}
return keyGenerator.generateKey();
}
public static IvParameterSpec createIV(final int ivSizeBytes, final Optional<SecureRandom> rng) {
final byte[] iv = new byte[ivSizeBytes];
final SecureRandom theRNG = rng.orElse(new SecureRandom());
theRNG.nextBytes(iv);
return new IvParameterSpec(iv);
}
public static IvParameterSpec readIV(final int ivSizeBytes, final InputStream is) throws IOException {
final byte[] iv = new byte[ivSizeBytes];
int offset = 0;
while (offset < ivSizeBytes) {
final int read = is.read(iv, offset, ivSizeBytes - offset);
if (read == -1) {
throw new IOException("Too few bytes for IV in input stream");
}
offset += read;
}
return new IvParameterSpec(iv);
}
public static void main(String[] args) throws Exception {
final SecureRandom rng = new SecureRandom();
// you somehow need to distribute this key
final SecretKey aesKey = createKey("AES", 128, Optional.empty(), Optional.of(rng));
final byte[] plaintext = "owlstead".getBytes(UTF_8);
final byte[] ciphertext;
{
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
final Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivForCBC = createIV(aesCBC.getBlockSize(), Optional.of(rng));
aesCBC.init(Cipher.ENCRYPT_MODE, aesKey, ivForCBC);
baos.write(ivForCBC.getIV());
try (final CipherOutputStream cos = new CipherOutputStream(baos, aesCBC)) {
cos.write(plaintext);
}
ciphertext = baos.toByteArray();
}
final byte[] decrypted;
{
final ByteArrayInputStream bais = new ByteArrayInputStream(ciphertext);
final Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
final IvParameterSpec ivForCBC = readIV(aesCBC.getBlockSize(), bais);
aesCBC.init(Cipher.DECRYPT_MODE, aesKey, ivForCBC);
final byte[] buf = new byte[1_024];
try (final CipherInputStream cis = new CipherInputStream(bais, aesCBC);
final ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
int read;
while ((read = cis.read(buf)) != -1) {
baos.write(buf, 0, read);
}
decrypted = baos.toByteArray();
}
}
System.out.println(new String(decrypted, UTF_8));
}
}
请注意,您可能并不总是希望生成和分发 AES 密钥 "out-of-band"。这里是 a few other methods of generating a key (part #2 onwards). You may also want to take a look at more advanced exception handling for the cryptographic operation.