Encryption Algorithm
Encryption algorithms are usually divided into symmetric encryption algorithms and asymmetric encryption algorithms:
- Symmetric-key cryptography: The same key is used for encryption and decryption. Commonly used symmetric encryption algorithms are DES and AES.
- Asymmetric-key cryptography: Encryption and decryption use different keys. For example, public-key encrypted content can only be decrypted with a private key, so it is also called public-key cryptography. The most widely used asymmetric encryption algorithm is the RSA algorithm.
The two have different usage scenarios, and they are often used together. For example, the SSL/TLS protocol combines symmetric encryption algorithms and asymmetric encryption algorithms.
This article mainly introduces the most commonly used symmetric encryption algorithm: AES.
AES
AES stands for Advanced Encryption Standard, which is a symmetric encryption algorithm. The emergence of AES is mainly used to replace the DES encryption algorithm, because AES is relatively more secure.
AES is widely used. It can be said that as long as you use the Internet, whether you are using a mobile phone APP or a Web application, you can hardly do without the AES encryption algorithm. Because most websites, including mobile APP back-end interfaces, have already used the HTTPS protocol, and most of the HTTPS uses the AES symmetric encryption algorithm during the data transmission phase.
Before learning AES, you must first know the following rules:
- AES is a block encryption algorithm. When encrypting, the original data is divided into blocks by size for encryption. The block size is fixed at 128 bits (that is, 16 bytes).
- The AES key length can be 128, 192 or 256 bits (ie 16, 25 or 32 bytes). The longer the key length, the higher the security and the lower the performance
AES working mode
The AES encryption algorithm has multiple modes of operation, such as: ECB, CBC, OFB, CFB, CTR, XTS, OCB, GCM. Different mode parameters and encryption processes are different, but the core is still the AES algorithm.
This article mainly introduces three modes of ECB, CBC, and GCM.
AES padding method
Since AES is a block encryption algorithm, when encrypting, the original data will be split into 128-bit (16-byte) blocks for encryption. If the original data to be encrypted is not an integer multiple of 16 bytes , It is necessary to fill the original data to an integer multiple of 16 bytes.
Commonly used padding methods include PKCS5Padding, ISO10126Padding, etc. In addition, if you can ensure that the size of the original data to be encrypted is an integer multiple of 16 bytes, you can also choose not to pad, that is, NoPadding.
AES in Java
The javax.crypto.Cipher
class in Java provides encryption and decryption functions.
Create a Cipher
:
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
Cipher
class getInstance
method needs to pass the name of an encryption algorithm as a parameter to create the corresponding Cipher
, the format is algorithm/mode/padding
, that is, algorithm name/working mode/padding, for example,
AES/CBC/PKCS5Padding
. For specific optional encryption methods, please refer to the document:
https://docs.oracle.com/javase/8/docs/technotes/guides/security/StandardNames.html#Cipher
ECB
ECB is called electronic codebook (Electronic codebook), which splits the data to be encrypted into blocks and encrypts each block independently.
Code:
public static byte[] encryptECB(byte[] data, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
byte[] result = cipher.doFinal(data);
return result;
}
public static byte[] decryptECB(byte[] data, byte[] key) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"));
byte[] result = cipher.doFinal(data);
return result;
}
public static void main(String[] args) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException {
String data = "Hello World"; // 待加密的明文
String key = "12345678abcdefgh"; // key 长度只能是 16、25 或 32 字节
byte[] ciphertext = encryptECB(data.getBytes(), key.getBytes());
System.out.println("ECB 模式加密结果(Base64):" + Base64.getEncoder().encodeToString(ciphertext));
byte[] plaintext = decryptECB(ciphertext, key.getBytes());
System.out.println("解密结果:" + new String(plaintext));
}
Since the encrypted ciphertext is in a binary format rather than a string, the Base64 encoding method is used here to convert it into a string for easy output and viewing. Output:
ECB 模式加密结果(Base64):bB0gie8pCE2RBQoIAAIxeA==
解密结果:Hello World
It should be noted that the AES key length can only be 16, 25 or 32 bytes. If it does not meet the requirements, it will be abnormal:
java.security.InvalidKeyException: Invalid AES key length
CBC mode has a fatal shortcoming. Because this mode encrypts each block independently, it will cause the same plaintext block to be encrypted into the same ciphertext block, which is relatively insecure. The picture below is a good example:
CBC
CBC is called Cipher-block chaining. Its emergence solves the problem that the same plaintext block of ECB will be encrypted into the same ciphertext block.
CBC introduces the concept of initial vector (IV, Initialization Vector). The first plaintext block is XORed with the IV and then encrypted. Each subsequent plaintext block is XORed with the previous ciphertext block and then encrypted.
Code:
public static byte[] encryptCBC(byte[] data, byte[] key, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
byte[] result = cipher.doFinal(data);
return result;
}
public static byte[] decryptCBC(byte[] data, byte[] key, byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(iv));
byte[] result = cipher.doFinal(data);
return result;
}
public static void main(String[] args) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
String data = "Hello World"; // 待加密的原文
String key = "12345678abcdefgh"; // key 长度只能是 16、25 或 32 字节
String iv = "iviviviviviviviv"; // CBC 模式需要用到初始向量参数
byte[] ciphertext = encryptCBC(data.getBytes(), key.getBytes(), iv.getBytes());
System.out.println("CBC 模式加密结果(Base64):" + Base64.getEncoder().encodeToString(ciphertext));
byte[] plaintext = decryptCBC(ciphertext, key.getBytes(), iv.getBytes());
System.out.println("解密结果:" + new String(plaintext));
}
Output:
CBC 模式加密结果(Base64):K7bSB51+KxfqaMjJOsPAQg==
解密结果:Hello World
Since the encryption of each plaintext block of CBC relies on the encryption result of the previous block, its main disadvantage is that the encryption process is serial and cannot be parallelized.
GCM
The full name of GCM is Galois/Counter Mode, which is an authenticated encryption algorithm. It not only provides encryption and decryption, but also provides data integrity verification to prevent tampering.
The AES-GCM mode is currently the most widely used mode. You can try to capture packets and look at the current mainstream https websites, most of which are based on the GCM mode. The following figure shows the encryption algorithm used by the browser to access the https website using the packet capture tool Charles:
It can be seen that the browser generally supports AES-GCM and AES-CBC modes, and the final server chooses to use AES-GCM.
The following parameters are required for AES-GCM authentication and encryption:
- Plaintext to be encrypted
- Key
- Initial vector IV
- additional authenticated data (AAD)
Code:
public static byte[] encryptGCM(byte[] data, byte[] key, byte[] iv, byte[] aad) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
cipher.updateAAD(aad);
byte[] result = cipher.doFinal(data);
return result;
}
public static byte[] decryptGCM(byte[] data, byte[] key, byte[] iv, byte[] aad) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException, InvalidAlgorithmParameterException {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new GCMParameterSpec(128, iv));
cipher.updateAAD(aad);
byte[] result = cipher.doFinal(data);
return result;
}
public static void main(String[] args) throws IllegalBlockSizeException, InvalidKeyException, BadPaddingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException {
String data = "Hello World"; // 待加密的原文
String key = "12345678abcdefgh"; // key 长度只能是 16、25 或 32 字节
String iv = "iviviviviviviviv";
String aad = "aad"; // AAD 长度无限制,可为空
byte[] ciphertext = encryptGCM(data.getBytes(), key.getBytes(), iv.getBytes(), aad.getBytes());
System.out.println("GCM 模式加密结果(Base64):" + Base64.getEncoder().encodeToString(ciphertext));
byte[] plaintext = decryptGCM(ciphertext, key.getBytes(), iv.getBytes(), aad.getBytes());
System.out.println("解密结果:" + new String(plaintext));
}
Output:
GCM 模式加密结果(Base64):1UxXmFpdUwMnpI7rh0XfmFqtdZSHTbNC/08g
解密结果:Hello World
AES-GCM is a Stream cipher algorithm, so the corresponding padding mode is NoPadding, that is, no padding is required.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。