4

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.

ECB 加密
ECB 解密

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:

ECB 模式的问题

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.

CBC 加密
CBC 解密

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.

Reference documents

Follow my public account

扫码关注


叉叉哥
3.8k 声望60 粉丝