1. Overview
1.概述
In this tutorial, we’ll discuss how to use an Initialization Vector (IV) with encryption algorithms. We’ll also discuss the best practices while using the IV.
在本教程中,我们将讨论如何在加密算法中使用初始化向量(IV)。我们还将讨论在使用IV时的最佳做法。
This article assumes a basic understanding of cryptography.
本文假设对密码学有基本了解。
We’ll be using the AES algorithm in different modes for all our examples.
我们将在所有的例子中使用不同模式的AES算法。
2. Encryption Algorithms
2.加密算法
Any cryptographic algorithm takes some data or plaintext and a key to produce an encrypted text or ciphertext. And, it also takes the generated ciphertext and the same key to produce the decrypted data or original plaintext back.
任何加密算法都需要一些数据或明文和一个密钥来产生一个加密的文本或密码文本。而且,它还需要生成的密码文本和相同的密钥来产生解密的数据或原始明文。
For example, the block cipher algorithm provides security by encrypting and decrypting fixed-length blocks. We use different encryption modes to repeatedly apply an algorithm to the entire data and dictate the type of IV to use.
例如,区块密码算法通过对固定长度的区块进行加密和解密来提供安全性。我们使用不同的加密模式,将一种算法重复应用于整个数据,并决定使用的IV的类型。
In the case of block ciphers, we work with the same size blocks. If the plaintext size is smaller than the block size, we use padding. Some modes don’t use padding as they use block cipher as a stream cipher.
在区块密码的情况下,我们用相同大小的区块工作。如果明文大小小于块大小,我们就使用填充。有些模式不使用填充,因为它们将块密码作为流密码使用。
3. Initialization Vector (IV)
3.初始化向量(IV)
We use an IV in a cryptographic algorithm as a starting state, adding this to a cipher to hide patterns in the encrypted data. This helps avoid the need to re-issue a new key after each invocation.
我们使用加密算法中的IV作为起始状态,将其添加到密码中以隐藏加密数据的模式。这有助于避免在每次调用后重新发布一个新的密钥。
3.1. Properties of an IV
3.1.IV的属性
We use a unique sequence or an IV for most modes of encryption. And, we should never reuse the same IV with the same key. This ensures a distinct ciphertext for the same plaintext encryption, even if we encrypt it multiple times with the same key.
我们在大多数加密模式中使用一个独特的序列或IV。而且,我们不应该用同一个密钥重复使用同一个IV。这确保了同一明文加密有一个独特的密码文本,即使我们用相同的密钥进行多次加密。
Let’s look at some of the characteristics of an IV, depending on the encryption mode:
让我们看看IV的一些特征,这取决于加密模式。
- It has to be non-repeating
- Based on the encryption mode, it needs to be random also
- It need not be secret
- It needs to be a cryptographic nonce
- The IV of AES is always 128-bit regardless of the key length
3.2. Generating the IV
3.2.生成IV
We can get an IV directly from the Cipher class:
我们可以直接从Cipher类中获得一个IV。
byte[] iv = cipher.getIV();
If we’re unsure of the default implementation, we can always write our method to generate the IV. If we don’t provide an explicit IV, then Cipher.getIV() is used to implicitly get the IV. We can use any method to generate an IV as long as it complies with the properties discussed above.
如果我们不确定默认的实现,我们总是可以编写我们的方法来生成IV。如果我们没有提供明确的IV,那么Cipher.getIV()就被用来隐含地获取IV。我们可以使用任何方法来生成IV,只要它符合上面讨论的属性。
First, let’s create a random IV by using SecureRandom:
首先,让我们通过使用SecureRandom创建一个随机IV。
public static IvParameterSpec getIVSecureRandom(String algorithm) throws NoSuchAlgorithmException, NoSuchPaddingException {
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] iv = new byte[Cipher.getInstance(algorithm).getBlockSize()];
random.nextBytes(iv);
return new IvParameterSpec(iv);
}
Next, we’ll create the IV by getting the parameters from the Cipher class:
接下来,我们将通过从Cipher类中获取参数来创建IV。
public static IvParameterSpec getIVInternal(Cipher cipher) throws InvalidParameterSpecException {
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
return new IvParameterSpec(iv);
}
We can use any of the above methods to generate a random, unpredictable IV. However, for some modes like GCM, we use the IV together with a counter. In such cases, we use the first few bytes, mostly 12 for the IV and the next 4 for the counter:
我们可以使用上述任何一种方法来生成一个随机的、不可预测的IV。然而,对于某些模式,如GCM,我们将IV与计数器一起使用。在这种情况下,我们使用前几个字节,主要是12个字节用于IV,后面4个字节用于计数器。
public static byte[] getRandomIVWithSize(int size) {
byte[] nonce = new byte[size];
new SecureRandom().nextBytes(nonce);
return nonce;
}
In this case, we need to ensure that we don’t repeat the counter and that the IV is also unique.
在这种情况下,我们需要确保我们的计数器不重复,而且IV也是唯一的。
Lastly, though not recommended, we can also use a hardcoded IV.
最后,尽管不推荐,我们也可以使用硬编码的IV。
4. Using IV with Different Modes
4.使用不同模式的IV
As we know, the prime function of encryption is to mask plaintext so that attackers can’t guess it. Therefore, we use different cipher modes to mask the patterns within the ciphertext.
我们知道,加密的首要功能是掩盖明文,使攻击者无法猜到它。因此,我们使用不同的密码模式来掩盖密码文本中的模式。
Modes like ECB, CBC, OFB, CFB, CTR, CTS, and XTS provide confidentiality. But these modes don’t protect against tampering and modification. We can add a Message Authentication Code (MAC) or a digital signature for detection. We use various implementations that provide combined modes under authenticated encryption (AE). CCM, GCM, CWC, EAX, IAPM, and OCB are a few examples.
ECB、CBC、OFB、CFB、CTR、CTS和XTS等模式提供了保密性。但这些模式并不能防止篡改和修改。我们可以添加一个消息验证码(MAC)或数字签名来检测。我们使用各种实现,在认证加密(AE)下提供组合模式。CCM、GCM、CWC、EAX、IAPM和OCB是几个例子。
4.1. Electronic Codebook (ECB) Mode
4.1.电子代码簿(ECB)模式
Electronic Codebook mode encrypts each block separately with the key. This always encrypts the identical plaintext into identical ciphertext blocks, thereby not hiding patterns well. Thus, we don’t use it for cryptographic protocols. Decryption is also equally vulnerable to replay attacks.
电子编码本模式用密钥对每个块进行单独加密。这总是将相同的明文加密成相同的密文块,从而不能很好地隐藏模式。因此,我们不把它用于加密协议。解密也同样容易受到重放攻击。
To encrypt data in ECB mode, we use:
为了在ECB模式下加密数据,我们使用。
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
ciphertext = cipher.doFinal(data);
To decrypt data in ECB mode, we write:
为了在ECB模式下解密数据,我们写道。
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
plaintext = cipher.doFinal(cipherText);
We haven’t used any IV, so the same plaintext will result in the same ciphertext, thus making it vulnerable to attacks. Though ECB mode is the most vulnerable, it’s still the default encryption mode for many providers. So, we need to be more vigilant about explicitly setting the encryption mode.
我们没有使用任何IV,所以相同的明文将导致相同的密码文本,从而使其容易受到攻击。虽然ECB模式是最脆弱的,但它仍然是许多供应商的默认加密模式。因此,我们需要对明确设置加密模式提高警惕。
4.2. Cyber Block Chaining (CBC) Mode
4.2.网络块链(CBC)模式
Cyber Block Chaining mode uses an IV to prevent the same plaintexts resulting in the same ciphertext. We need to take care that the IV is reliably random or unique. Otherwise, we’ll have the same vulnerability as ECB Mode.
Cyber Block Chaining模式使用一个IV来防止相同的明文产生相同的密码文本。我们需要注意,IV是可靠的随机或唯一的。否则,我们会有与ECB模式相同的漏洞。
Let’s get the random IV using getIVSecureRandom:
让我们使用getIVSecureRandom获得随机IV。
IvParameterSpec iv = CryptoUtils.getIVSecureRandom("AES");
First, we’ll use the IV to encrypt data using CBC mode:
首先,我们将使用IV,用CBC模式对数据进行加密。
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
Next, let’s pass the same IV using the IvParameterSpec object for decryption:
接下来,让我们使用IvParameterSpec对象传递相同的IV,用于解密。
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
4.3. Cyber Feedback (CFB) Mode
4.3.网络反馈(CFB)模式
Cyber Feedback mode is the most basic streaming mode. It’s like a self-synchronizing stream cipher. Unlike the CBC mode, we don’t need any padding here. In CFB mode, we use IV as the source of the stream generated by the cipher. Again, if we use the same IV for different encryptions, similarities might show up in the ciphertext. Here also, like the CBC mode, IV should be random. In case IV is predictable, then we lose out on confidentiality.
Cyber Feedback模式是最基本的流模式。它就像一个自我同步的流密码。与CBC模式不同,我们在这里不需要任何填充。在CFB模式中,我们使用IV作为密码生成的流的来源。同样,如果我们在不同的加密中使用相同的IV,相似性可能会在密码文本中显示出来。这里也和CBC模式一样,IV应该是随机的。 如果IV是可预测的,那么我们就失去了保密性。
Let’s generate a random IV for CFB mode:
让我们为CFB模式生成一个随机IV。
IvParameterSpec iv = CryptoUtils.getIVSecureRandom("AES/CFB/NoPadding");
Another extreme case is if we use an all-zero IV, then under CFB-8 mode, some keys may generate an all-zero IV and all-zero plaintext. In this case, 1/256 keys will generate no encryption. This will result in returning the plaintext as ciphertext.
另一个极端的情况是,如果我们使用一个全零的IV,那么在CFB-8模式下,一些密钥可能会产生一个全零的IV和全零的明文。在这种情况下,1/256密钥将不产生加密。这将导致将明文作为密码文本返回。
For CBC and CFB modes, reusing an IV reveals information about the common blocks shared by two messages.
对于CBC和CFB模式,重用IV会显示两个信息共享的共同块的信息。
4.4. Counter (CTR) and Output Feedback (OFB) Modes
4.4.计数器(CTR)和输出反馈(OFB)模式
Counter mode and Output Feedback mode make a block cipher into a synchronous stream cipher. Each mode generates keystream blocks. In this case, we initialize the cipher with a particular IV. We do this primarily to allocate 12 bytes to the IV and 4 bytes to the counter. This way, we can encrypt a message of length 2^32 blocks.
计数器模式和输出反馈模式使区块密码成为同步流密码。每种模式都会产生密钥流块。在这种情况下,我们用一个特定的IV来初始化密码。我们这样做主要是为了给IV分配12个字节,给计数器分配4个字节。这样一来,我们就可以对长度为2^32个块的信息进行加密。
Here, let’s create an IV:
在这里,让我们创建一个IV。
IvParameterSpec ivSpec = CryptoUtils.getIVSecureRandom("AES");
For CTR mode, the initial bitstream is dependent on the IV and key. Here also, reusing an IV will cause key bitstream reuse. This, in turn, will result in breaking the security.
对于CTR模式,初始比特流取决于IV和密钥。在这里,重复使用IV也会导致密钥比特流的重复使用。这反过来将导致破坏安全性。
If the IV is not unique, then the counter may fail to provide the expected confidentiality for the blocks that correspond to the repeating counter blocks. However, the other data blocks are not affected.
如果IV不是唯一的,那么计数器可能无法为与重复的计数器块对应的块提供预期的保密性。然而,其他数据块则不受影响。
4.5. Galois/Counter (GCM) Mode
4.5.伽罗瓦/计数器(GCM)模式
Galois/Counter mode is an AEAD mode of encryption. It combines Counter mode encryption with an authentication mechanism. And, it protects both plaintext and additional authenticated data (AAD).
Galois/Counter模式是一种AEAD的加密模式。它将Counter模式加密与认证机制相结合。而且,它同时保护明文和额外的认证数据(AAD)。
However, this authentication in GCM depends on the uniqueness of the IVs. We use a nonce as the IV. In case we repeat even one IV, then our implementation may be vulnerable to the attacks.
然而,GCM中的这种认证取决于IV的唯一性。我们使用一个nonce作为IV。如果我们重复哪怕是一个IV,那么我们的实现就可能会受到攻击。
As GCM uses AES for encryption, the IV or the counter is 16 bytes. Therefore, we use the first 12 bytes as the IV and the last 4 bytes nonce as a counter.
由于GCM使用AES进行加密,IV或计数器是16个字节。因此,我们使用前12个字节作为IV,最后4个字节的nonce作为计数器。
To create an IV in GCM mode, we need to set GCMParameterSpec. Let’s create an IV:
为了在GCM模式下创建一个IV,我们需要设置GCMParameterSpec。让我们来创建一个IV。
byte[] iv = CryptoUtils.getRandomIVWithSize(12);
First, let’s get an instance of the Cipher and initialize it using the IV:
首先,让我们得到一个Cipher的实例,并用IV来初始化它。
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key, new GCMParameterSpec(128, iv));
Now, we’ll create and initialize Cipher with the IV for decryption:
现在,我们将创建并初始化Cipher与解密的IV。
cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));
Here also, we need a unique IV, else one can decipher the plaintext.
在这里,我们也需要一个独特的IV,否则人们可以破译明文。
4.6. Summing up of IVs
4.6.IVs的总结
The following table summarizes the type of IV needed for different modes:
下表总结了不同模式所需的IV的类型。
As we have seen, reusing an IV with the same key results in loss of security. If possible, we should use more advanced modes like GCM. Also, some modes like CCM are not available in the standard JCE distribution. In this case, we can use Bouncy Castle APIs to implement it.
正如我们所看到的,用相同的密钥重复使用IV会导致安全性的损失。如果可能的话,我们应该使用更高级的模式,如GCM。另外,有些模式如CCM在标准的JCE发行中是不可用的。在这种情况下,我们可以使用Bouncy Castle APIs来实现它。
5. Conclusion
5.结论
In this article, we showed how to use an IV in different encryption modes. We also discussed the issues and best practices while using an IV.
在这篇文章中,我们展示了如何在不同的加密模式下使用IV。我们还讨论了使用IV时的问题和最佳做法。
As always, we can find the source code over on GitHub.
一如既往,我们可以在GitHub上找到源代码over。