Source丨Authorized Reprint from Sanfen E (ID: Fighter3FullStack)
Introduction
In our daily work, we often use encryption and decryption in various scenarios, such as:
-
User passwords should not be stored in plaintext; they must be stored as encrypted ciphertext. -
Sensitive data like bank card numbers and ID numbers need to be transmitted securely. -
For important interfaces, such as payment, the client must generate a signature for the request, which the server then verifies. -
……

So, which encryption algorithms can we use to achieve the capabilities mentioned above? Let’s take a look.
Common Encryption Algorithms
Algorithms can be broadly divided into irreversible encryption and reversible encryption. Reversible encryption can further be divided into symmetric encryption and asymmetric encryption.

Irreversible Algorithms
Irreversible encryption algorithms are such that ciphertext cannot be reverted to plaintext.
The hash algorithm is an example of an irreversible algorithm. In hash algorithms, plaintext is processed to generate a hash value, which is a fixed-length data representation that does not depend on the length of the plaintext.

There are many implementations of hash algorithms, with common ones including MD5, SHA1, SHA-224, SHA-256, etc.
Hash algorithms are commonly used in digital signatures, message authentication, password storage, and other scenarios.
Hash algorithms do not require a key, but some irreversible algorithms do require a key, such as the HMAC algorithm.
MD5
MD5, short for “Message-Digest Algorithm 5”, is an algorithm that can take input of any length and produce a fixed-length hash value. The output length of the MD5 algorithm is 128 bits, usually represented by 32 hexadecimal characters.
Let’s take a look at the Java code implementation of the MD5 algorithm:
public class MD5 {
private static final String MD5_ALGORITHM = "MD5";
public static String encrypt(String data) throws Exception {
// Get MD5 algorithm instance
MessageDigest messageDigest = MessageDigest.getInstance(MD5_ALGORITHM);
// Calculate hash value
byte[] digest = messageDigest.digest(data.getBytes());
Formatter formatter = new Formatter();
// Format with leading zeros
for (byte b : digest) {
formatter.format("%02x", b);
}
return formatter.toString();
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String encryptedData = encrypt(data);
System.out.println("Encrypted data: " + encryptedData);
}
}
MD5 has several advantages, such as fast computation speed, fixed output length, and wide application.
However, as an encryption algorithm, it has a significant drawback: it is not secure
.
The MD5 algorithm has been compromised, and due to its limited output length, attackers can find original data that matches the hash value through brute force or rainbow table attacks.
Although salting, which involves adding some random strings to the original text, can mitigate this, it is recommended to use more secure SHA series algorithms instead.
SHA-256
The SHA (Secure Hash Algorithm) series is a group of cryptographic hash functions designed to map data of any length to a fixed-length hash value. The SHA series was designed by the NSA in 1993 and includes SHA-1, SHA-2, and SHA-3.
Among them, SHA-1 has vulnerabilities and is no longer recommended.
SHA-2 includes SHA-224
, SHA-256
, SHA-384
, and SHA-512
, which map data of any length to hash values of 224 bits, 256 bits, 384 bits, and 512 bits, respectively.
Let’s look at the Java implementation of the most commonly used SHA-256
:
public class SHA256 {
private static final String SHA_256_ALGORITHM = "SHA-256";
public static String encrypt(String data) throws Exception {
// Get SHA-256 algorithm instance
MessageDigest messageDigest = MessageDigest.getInstance(SHA_256_ALGORITHM);
// Calculate hash value
byte[] digest = messageDigest.digest(data.getBytes());
StringBuilder stringBuilder = new StringBuilder();
// Convert byte array to hexadecimal string
for (byte b : digest) {
stringBuilder.append(Integer.toHexString((b & 0xFF) | 0x100), 1, 3);
}
return stringBuilder.toString();
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String encryptedData = encrypt(data);
System.out.println("Encrypted data: " + encryptedData);
}
}
The SHA-2 algorithm is stronger than MD5 for two main reasons:
-
Longer hash value: For example, the hash value length of the SHA-256 algorithm is 256 bits, while that of the MD5 algorithm is 128 bits, making brute force or rainbow table attacks more difficult. -
Stronger collision resistance: The SHA algorithm uses a more complex computation process and more rounds, making it harder for attackers to find collisions through pre-computation or coincidence.
However, SHA-2 is not absolutely secure; all hash algorithms are at risk of brute force or rainbow table attacks, so salting is still essential in practical applications.

Symmetric Encryption Algorithms
Symmetric encryption algorithms use the same key for both encryption and decryption.

The same key is used for both the encryption and decryption processes, so the security of the key is crucial. If the key is leaked, an attacker can easily decrypt the encrypted data.
Common symmetric encryption algorithms include DES, 3DES, and AES. Among them, the AES algorithm is one of the most widely used symmetric encryption algorithms, known for its high security and encryption efficiency.
DES
DES (Data Encryption Standard) is a symmetric encryption algorithm developed by IBM in 1975, and it was one of the first widely used symmetric encryption algorithms.
DES uses a 56-bit key to encrypt data, employing substitution, permutation, and XOR operations during the encryption process, offering relatively high security.
Let’s take a look at the Java implementation of the DES algorithm:
public class DES {
private static final String DES_ALGORITHM = "DES";
/**
* DES Encryption
*
* @param data Data to be encrypted
* @param key Key, must be 8 bytes long
* @return Encrypted data, encoded in Base64
*/
public static String encrypt(String data, String key) throws Exception {
// Generate key specification from the key
KeySpec keySpec = new DESKeySpec(key.getBytes());
// Generate key factory from the key specification
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
// Generate key from the key factory and key specification
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// Get the encryptor based on the encryption algorithm
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
// Initialize the encryptor, setting the encryption mode and key
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
// Encrypt data
byte[] encryptedData = cipher.doFinal(data.getBytes());
// Base64 encode the encrypted data
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* DES Decryption
*
* @param encryptedData Encrypted data, encoded in Base64
* @param key Key, must be 8 bytes long
* @return Decrypted data
*/
public static String decrypt(String encryptedData, String key) throws Exception {
// Generate key specification from the key
KeySpec keySpec = new DESKeySpec(key.getBytes());
// Generate key factory from the key specification
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(DES_ALGORITHM);
// Generate key from the key factory and key specification
SecretKey secretKey = secretKeyFactory.generateSecret(keySpec);
// Base64 decode the encrypted data
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// Get the decryptor based on the encryption algorithm
Cipher cipher = Cipher.getInstance(DES_ALGORITHM);
// Initialize the decryptor, setting the decryption mode and key
cipher.init(Cipher.DECRYPT_MODE, secretKey);
// Decrypt data
byte[] decryptedData = cipher.doFinal(decodedData);
// Convert decrypted data to string
return new String(decryptedData);
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String key = "12345678";
String encryptedData = encrypt(data, key);
System.out.println("Encrypted data: " + encryptedData);
String decryptedData = decrypt(encryptedData, key);
System.out.println("Decrypted data: " + decryptedData);
}
}
DES is relatively fast, but it is not the best choice in terms of security due to its short key length, which is vulnerable to brute force and differential attacks. It is generally recommended to use more secure symmetric encryption algorithms like 3DES or AES.
AES
AES (Advanced Encryption Standard) is a symmetric encryption algorithm widely used in data encryption and protection. The key lengths used by AES can be 128 bits, 192 bits, or 256 bits, which are longer than those used by DES, providing higher security.
Let’s look at the Java implementation of the AES algorithm:
public class AES {
private static final String AES_ALGORITHM = "AES";
// AES encryption mode is CBC, padding method is PKCS5Padding
private static final String AES_TRANSFORMATION = "AES/CBC/PKCS5Padding";
// AES key is 16 bytes
private static final String AES_KEY = "1234567890123456";
// AES initialization vector is 16 bytes
private static final String AES_IV = "abcdefghijklmnop";
/**
* AES Encryption
*
* @param data Data to be encrypted
* @return Encrypted data, encoded in Base64
*/
public static String encrypt(String data) throws Exception {
// Convert AES key to SecretKeySpec object
SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
// Convert AES initialization vector to IvParameterSpec object
IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
// Get the encryptor based on the encryption algorithm
Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
// Initialize the encryptor, setting the encryption mode, key, and initialization vector
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
// Encrypt data
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
// Base64 encode the encrypted data
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* AES Decryption
*
* @param encryptedData Encrypted data, encoded in Base64
* @return Decrypted data
*/
public static String decrypt(String encryptedData) throws Exception {
// Convert AES key to SecretKeySpec object
SecretKeySpec secretKeySpec = new SecretKeySpec(AES_KEY.getBytes(), AES_ALGORITHM);
// Convert AES initialization vector to IvParameterSpec object
IvParameterSpec ivParameterSpec = new IvParameterSpec(AES_IV.getBytes());
// Get the decryptor based on the encryption algorithm
Cipher cipher = Cipher.getInstance(AES_TRANSFORMATION);
// Initialize the decryptor, setting the decryption mode, key, and initialization vector
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec);
// Base64 decode the encrypted data
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
// Decrypt data
byte[] decryptedData = cipher.doFinal(decodedData);
// Return decrypted data
return new String(decryptedData, StandardCharsets.UTF_8);
}
public static void main(String[] args) throws Exception {
String data = "Hello World";
String encryptedData = encrypt(data);
System.out.println("Encrypted data: " + encryptedData);
String decryptedData = decrypt(encryptedData);
System.out.println("Decrypted data: " + decryptedData);
}
}
The AES algorithm uses longer key lengths, resulting in a larger key space and higher security, effectively resisting brute force attacks.
However, due to the longer key lengths, it requires more storage.
The biggest challenge with symmetric encryption algorithms is the difficulty of key management, whereas asymmetric encryption does not have this concern.
Asymmetric Encryption Algorithms
Asymmetric encryption algorithms require two keys that are different but mathematically related: one is called the public key, and the other is called the private key.
Data encrypted with one key can only be decrypted with the other. For instance, if the public key is used for encryption, the private key must be used for decryption.

RSA
RSA is currently the most widely used asymmetric encryption algorithm, invented in 1978 by Ron Rivest, Adi Shamir, and Leonard Adleman, with its name derived from their initials.
Let’s look at the Java implementation of the RSA algorithm:
public class RSA {
private static final String RSA_ALGORITHM = "RSA";
/**
* Generate RSA key pair
*
* @return RSA key pair
*/
public static KeyPair generateKeyPair() throws NoSuchAlgorithmException {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(RSA_ALGORITHM);
keyPairGenerator.initialize(2048); // Key size is 2048 bits
return keyPairGenerator.generateKeyPair();
}
/**
* Encrypt data using public key
*
* @param data Data to be encrypted
* @param publicKey Public key
* @return Encrypted data
*/
public static String encrypt(String data, PublicKey publicKey) throws Exception {
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
return Base64.getEncoder().encodeToString(encryptedData);
}
/**
* Decrypt data using private key
*
* @param encryptedData Encrypted data
* @param privateKey Private key
* @return Decrypted data
*/
public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
byte[] decodedData = Base64.getDecoder().decode(encryptedData);
Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decryptedData = cipher.doFinal(decodedData);
return new String(decryptedData, StandardCharsets.UTF_8);
}
public static void main(String[] args) throws Exception {
KeyPair keyPair = generateKeyPair();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
String data = "Hello World";
String encryptedData = encrypt(data, publicKey);
System.out.println("Encrypted data: " + encryptedData);
String decryptedData = decrypt(encryptedData, privateKey);
System.out.println("Decrypted data: " + decryptedData);
}
}
The advantages of RSA include high security, as the public key can be shared openly while the private key must be kept secret, ensuring data security. It can be used in various applications, including digital signatures and key agreement.
However, its drawbacks include slower encryption and decryption speeds. The longer the key length, the longer the encryption and decryption time; too short a key length makes it vulnerable to brute force attacks, while too long a key length increases computational and storage overhead.
Conclusion
In this article, we briefly reviewed the five most commonly used encryption algorithms.
In fact, when it comes to the application of encryption and decryption algorithms, there is one thing that can be said to be applied to the extreme: what is it?
—— HTTPS

Let’s briefly recall the workflow of HTTPS and the encryption algorithms used:
-
The client initiates an HTTPS request: the user enters a URL in the browser to access an HTTPS site, preparing to send an HTTPS request. -
The server provides a certificate: the server returns a public key certificate, which contains the server’s public key, issuer (certificate authority), and other information. -
The client verifies the certificate: the browser verifies the validity, legality, and source of the certificate, a process that uses asymmetric encryption and hash algorithms.
-
The client uses the public key of the certificate authority to verify the certificate, ensuring its authenticity and legality. -
The client uses the public key in the certificate to verify the server’s digital signature, ensuring the server’s identity and data integrity. -
The client calculates the hash value using a hash algorithm and compares it with the hash value in the certificate to ensure the integrity of the certificate.
During data transmission, hash algorithms are also utilized:
-
Message Digest: During data transmission, both the client and server use a hash algorithm to compute the message’s hash value, and upon receiving the message, they compare the hash values to ensure the integrity of the transmitted data.
In summary, HTTPS employs symmetric encryption algorithms, asymmetric encryption algorithms, and hash algorithms to ensure data security and integrity, thereby safeguarding the identities and data of both communication parties.

As for which encryption algorithms to use, it depends on the version of the SSL/TLS protocol and the selected cipher suite during negotiation. In practical network environments, many encryption algorithms may be phased out to meet higher security requirements.
In our daily development, we can also draw from these ideas and flexibly apply various encryption algorithms to make our applications safer and more robust.
References:
1、Service went down for 3 minutes
2、User registration process implemented based on DDD, very elegant!
3、8 Cool Operations for Filtering Data in Pandas
A high-performance memory queue!!
Beware of a pitfall and interview question in MyBatisPlus
Click to share
Click to like
Click to view