AES加密IV

我在下面使用这个(E.1)作为我的应用程序,显然有一个巨大的安全漏洞,我认识并理解。 我对加密越来越感兴趣,想要更好地理解它,我需要生成一个随机密钥和一个IV,但我不确定如何正确地做到这一点有人可以向我解释熟悉AES加密的人如何工作(IV&KEY )所以我将来能够更好地理解并且可以运用我的知识,本质上我只是想让代码更安全,谢谢。

(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中生成密钥的要求。

所以让我们用三个简单的方法展示一个类:

 package nl.owlstead.stackoverflow; 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, final Optional 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 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密钥。 以下是一些生成密钥的方法 (第2部分以后)。 您可能还想查看加密操作的更高级exception处理 。