Fundamentals of Cryptography: coding method, message digest algorithm and encryption algorithm summary

Keywords: cryptology rsa md5 AES

Encoding method of bytecode to text

In the computer, whether memory, disk or network transmission, the data involved are stored or transmitted in binary format.

Each binary bit can only be 0 or 1. Binary bits do not exist alone, but exist in the form of 8 binary bits forming 1 byte, that is, 1 byte = 8 bit s.

Bytecode cannot be directly converted to printable text characters. Sometimes you want to configure, store and transmit a section of binary bytecode through text, such as configuration file, HTML/XML, URL, e-mail body, HTTP Header and other scenarios that only support text, you need to convert the binary byte code into text string.

There are many ways to convert binary bytecode to text characters. The simplest way is to use 0 and 1 directly. But in this case, only 8 0 / 1 characters can represent 1 byte, and the length is too long, which is very inconvenient.

Here are two more compact methods: HEX coding and Base64 coding.

HEX code

HEX is a hexadecimal encoding method, so it is also called Base16.

If the binary value in a byte is converted to hexadecimal and the 16 characters 0-9 and a-e (ignoring case) are used, each character can represent four binary bits (because the fourth power of 2 is equal to 16), so only two printable characters are required to represent a byte.

Using HEX coding (dependency) in Java Apache Commons Codec):

String str = "relativity";
byte[] bytes = str.getBytes("UTF-8");

// Hex coding
String encodeString = Hex.encodeHexString(bytes);
System.out.println(encodeString); // Output: e79bb8e5afb9e8aeba

// Hex decoding
byte[] decodeBytes = Hex.decodeHex(encodeString);
System.out.println(new String(decodeBytes, "UTF-8")); // Output: Relativity

There are many usage scenarios for HEX coding. Here are several common usage scenarios:

RGB color code

RGB color is usually represented by HEX. For example, orange can be represented by #FF4500:

.orangered { color: #FF4500; }

RGB refers to the three primary colors of red, green and blue. After the three colors are superimposed in different proportions, various colors can be obtained. The value range of each intensity of the three colors is 0 ~ 255, which requires 1 byte each, a total of 3 bytes.

HEX encoded indicates a certain RGB color. It is a string with a length of 6 bits (usually prefixed with # and the length is 7 bits). For example, #FF4500 indicates that the intensities of the three primary colors of red, green and blue are 255, 69 and 0 respectively.

URL encoding

Since only letters, numbers and some special symbols are allowed in the URL, when there are Chinese characters in the URL, it needs to be encoded by the URL.

For example, the page URL of Baidu Encyclopedia "relativity" is: https://baike.baidu.com/item/...

Among them,% E7%9B%B8%E5%AF%B9%E8%AE%BA is actually the result of encoding the three words' relativity 'with UTF-8 to obtain 9 bytes, and then using HEX encoding and prefixing the 9 bytes with'% '.

IPv6 address

As the IPv4 address will soon be insufficient, IPv6 will be replaced. IPv6 uses 128 binary addresses, which are usually represented by HEX coding, for example:

2001:0db8:0000:0000:0000:ff00:0042:8329

Base64 encoding

If you think HEX coding is not compact enough, there is a more compact coding method: Base64 coding.

Base64 encoding uses a total of 64 characters to represent binary bits: 26 uppercase A-Z, 26 lowercase A-Z, 10 digits 0-9, and 2 special symbols + and /. This means that each character can represent 6 binary bits because 64 is equal to the 6th power of 2.

Since each byte is 8 binary bits and each character encoded by Base64 represents 6 binary bits, 3 bytes (i.e. 24 binary bits) can be rounded up , it can be encoded into 4 characters. If the number of original data bytes encoded by Base64 is not a multiple of 3, 1 or 2 bytes with a value of 0 will be added at the end, and Base64 encoding will be carried out after rounding up to a multiple of 3. After encoding, 1 or 2 = symbols will be added at the end to indicate how many bytes have been added, which will be used in decoding.

Base64 encoding in Java:

String str = "relativity";
byte[] bytes = str.getBytes("UTF-8");

// Base64 encoding
String encodeString = Base64.getEncoder().encodeToString(bytes);
System.out.println(encodeString); // Output: 55u45a+56K66

// Base64 decoding
byte[] decodeBytes = Base64.getDecoder().decode(encodeString);
System.out.println(new String(decodeBytes, "UTF-8")); // Output: Relativity

There are also many usage scenarios for Base64 encoding. For example, since the picture file is not a text file, it is impossible to write it directly into HTML, and the result of Base64 encoding is a string of text, which can be directly put into HTML:

<img src="data:image/jpg;base64,/9j/4QMZR..." />

It should be noted that Base64 is not an encryption algorithm. Some developers use Base64 as an encryption algorithm, which is extremely unsafe, because Base64 can be decoded by anyone without any key.

Message digest algorithm

Message digest algorithm, also known as cryptographic hash function (CHF), can calculate a fixed size result of bytecode data of any length through hash algorithm. The commonly used message digest algorithms include MD5, SHA-1, SHA-2 series (including SHA-256, SHA-512, etc.).

Taking MD5 as an example, the result of MD5 operation on any data is a hash value of 128 binary bits (16 bytes). The 32-bit MD5 string we see everyday is actually the result of HEX encoding the hash value of 128 binary bits.

For example, when MD5 is used to calculate the string "relativity" to obtain a 32-bit character MD5 value, it actually goes through the following three steps (the following code depends) Apache Commons Codec):

String str = "relativity";
// 1. Convert the string into a byte array through UTF-8 encoding
byte[] bytes = str.getBytes("UTF-8");
// 2. MD5 the original array to get a hash value of 128 binary bits (16 bytes)
byte[] md5Bytes = DigestUtils.md5(bytes);
// 3. Encode the 128 bit hash value HEX to obtain a string with a length of 32
String md5Hex = Hex.encodeHexString(md5Bytes);
System.out.println(md5Hex); // Output: fa913fb181bc1a69513e3d05a367da49

The above code is just to more clearly see the whole process of calculating the MD5 value of a string. In actual development, a more convenient API can be used to combine the above three steps into one step:

String str = "relativity";
// Use the default UTF-8 encoding to convert the string into a byte array, calculate MD5, and then perform HEX encoding
String md5Hex = DigestUtils.md5Hex(str);
System.out.println(md5Hex); // Output: fa913fb181bc1a69513e3d05a367da49

besides, Apache Commons Codec DigestUtils in also provides SHA-1, SHA-256, SHA-384, SHA-512 and other message summarization algorithms.

The message digest algorithm has the following characteristics:

  • For the same message, the results calculated by the message digest algorithm are always the same.
  • The results of different messages calculated by the message digest algorithm should be different as much as possible. If the results of two different data messages are the same, that is, hash collision occurs. The greater the probability of hash collision, the less secure the message digest algorithm is.
  • Irreversible, unable to reverse calculate the original data from the hash result. Therefore, we generally believe that the message digest algorithm is not an encryption algorithm because it cannot be decrypted. In addition, irreversibility here refers to the irreversibility of the operation, but attackers usually use the exhaustive method or rainbow table to find the original data corresponding to the hash value.

Here are some typical usage scenarios of message summarization algorithm:

  • The hash value of the user's login password is obtained by using the message digest algorithm and then stored in the database. Even if the database is attacked by hackers and gets all the data, it is difficult to obtain the original value of the password. This is more secure than storing passwords in plaintext. Of course, it is not safe to store hash values directly. Especially for some weak passwords, hackers can easily find the corresponding original values through the rainbow table. Therefore, the hash value is usually not stored directly, but after some processing, such as adding salt, HMAC, etc.
  • To compare whether the two files are consistent, you only need to compare whether the message summaries of the two files are consistent, without comparing them one by byte. For example, baidu online disk used to use the MD5 of the file to judge whether the newly uploaded file already exists. If it already exists, there is no need to upload and store it repeatedly, so as to save space.
  • Used for Digital Signature, which will be introduced later in this article.

In scenarios with high security requirements, MD5 and SHA-1 are not recommended at present. SHA-2 series algorithms are mostly used now.

HMAC

The full name of HMAC is hash based message authentication code, which adds a secret key to the message digest algorithm.

For example, HMAC-SHA256 adds a key to SHA-256 algorithm. The following is a code example (dependency) Apache Commons Codec):

String str = "relativity";
String key = "12345678"; // secret key
HmacUtils hmacUtils = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, key.getBytes("UTF-8"));
String result = hmacUtils.hmacHex(str.getBytes("UTF-8"));
System.out.println(result); // Output: 3bd7bbf58159a6d0bff846016b346a617a588fc1e9c43ebbdf38be53d3fc455a

Compared with the direct use of message summarization algorithm, the advantage of using HMAC is that it can verify the authenticity and integrity of messages.

As long as the key is not compromised, only holding the key can calculate and verify the original data hash value. Without the key, the attacker cannot send forged messages or tamper with messages.

HMAC can be used for interface authentication. For example, for an HTTP interface exposed in the network environment, if you want to authenticate the caller, you can issue the key to the caller. When the caller is required to call the interface, you can use the key to all request parameters. A signature is calculated through HMAC, and the callee verifies the signature to ensure the authenticity and integrity of the request parameters.

In addition, because HMAC adds a key when calculating the hash value, it is more difficult to be cracked by exhaustive method and rainbow table than using the message digest algorithm directly, and the user password is more secure after HMAC.

HMAC in JWT

A typical application scenario of HMAC is JWT. The full name of JWT is JSON Web Token.

The traditional authentication method generally saves the authenticated user information on the server, while JWT directly sends the authenticated user information to the client for saving. Since JWT is saved on the client, anyone can forge or tamper with it. One way to solve this problem is that the server will use HMAC to sign the JWT token and put the signature at the end of the token Tail. The next time the client brings a JWT request, the server will verify whether the signature is correct. As long as the key is not disclosed, the authenticity and integrity of the token can be guaranteed.

JWT token is divided into three parts:

  • Header: header that specifies the signature algorithm
  • Payload: contains the information mainly transmitted by token. This part can contain user information, such as user name, etc
  • Signature: signature, calculated as follows (secret is the key):

    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret)

Finally, these three parts are combined into JWT token s after Base64 coding:

encryption algorithm

Encryption algorithms are divided into symmetric encryption algorithms and asymmetric encryption algorithms:

  • Symmetric key cryptography: the same key is used for encryption and decryption. The most commonly used is AES algorithm.
  • Asymmetric key cryptography: different keys are used for encryption and decryption. For example, the contents encrypted by the public key can only be decrypted by the private key, so it is also called public key cryptography. RSA algorithm is the most widely used.

Symmetric encryption algorithm

Common symmetric encryption algorithms include DES, 3DES and AES. DES and 3DES standards have been gradually replaced by AES due to security problems.

AES has many modes of operation and padding:

  • Working modes: such as ECB, CBC, OFB, CFB, CTR, XTS, OCB and GCM, different mode parameters and encryption processes are different.
  • Filling method: because AES is a block cipher algorithm, the original data will be divided into 128 bits (i.e. 16 bytes) according to the size during encryption For block encryption, if the original data to be encrypted is not an integer multiple of 16 bytes, the original data needs to be filled to make it reach an integer multiple of 16 bytes. The common filling methods include PKCS5Padding, ISO10126Padding, etc. in addition, if the size of the original data to be encrypted can be guaranteed to be an integer multiple of 16 bytes, you can also choose not to fill, that is, NoPadding.

In actual work, it is necessary to encrypt and decrypt data across teams and languages. It often happens that one language cannot be decrypted after encryption in another language. This is generally caused by the inconsistency between the working mode and filling mode selected by both sides.

The following code takes the ECB mode combined with PKCS5Padding filling mode as an example to encrypt and decrypt the data:

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"; // Plaintext to be encrypted
    String key = "12345678abcdefgh"; // key length can only be 16, 25 or 32 bytes

    byte[] ciphertext = encryptECB(data.getBytes(), key.getBytes());
    System.out.println("ECB Mode encryption results( Base64): " + Base64.getEncoder().encodeToString(ciphertext));

    byte[] plaintext = decryptECB(ciphertext, key.getBytes());
    System.out.println("Decryption result:" + new String(plaintext));
}

Output:

ECB Mode encryption results( Base64): bB0gie8pCE2RBQoIAAIxeA==
Decryption result: Hello World

Although the above ECB mode is easy to use, its security is not high. Because this mode encrypts each block independently, the same plaintext block will be encrypted into the same ciphertext block. The following figure is a good example:

In CBC mode, the concept of Initialization Vector (IV) is introduced to solve the problem of ECB mode.

The following is a code example of CBC mode combined with PKCS5Padding filling mode. During encryption and decryption, there is one more initial vector iv parameter than ECB mode:

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"; // Original text to be encrypted
    String key = "12345678abcdefgh"; // key length can only be 16, 25 or 32 bytes
    String iv = "iviviviviviviviv"; // CBC mode requires initial vector parameters

    byte[] ciphertext = encryptCBC(data.getBytes(), key.getBytes(), iv.getBytes());
    System.out.println("CBC Mode encryption results( Base64): " + Base64.getEncoder().encodeToString(ciphertext));

    byte[] plaintext = decryptCBC(ciphertext, key.getBytes(), iv.getBytes());
    System.out.println("Decryption result:" + new String(plaintext));
}

Output:

CBC Mode encryption results( Base64): K7bSB51+KxfqaMjJOsPAQg==
Decryption result: Hello World

AES is widely used. It can be said that as long as you surf the Internet, whether you use mobile APP or Web application, it is almost inseparable from AES encryption algorithm. At present, most websites, including the back-end interface of mobile APP, have used HTTPS protocol, and HTTPS mostly uses AES symmetric encryption algorithm in the data transmission stage.

However, the symmetric encryption algorithm represented by AES faces a problem, that is, how to transmit the key safely. Both sides of data exchange in the network need to use the same key for encryption and decryption. Once the key is exposed, the transmitted content is no longer secure. If the key itself needs to be transmitted, how to ensure security? For this problem, we need to use asymmetric encryption algorithm.

Asymmetric encryption algorithm

In 1977, Rivest, Shamir and Adleman designed RSA asymmetric encryption algorithm, which won the Turing Award in 2002 (the international highest award in the computer field, known as the "Nobel Prize in the computer industry"). So far, RSA algorithm has been the most widely used asymmetric encryption algorithm.

RSA has two keys: public key and private key.

The public key can be fully disclosed and can be obtained by anyone. The private key is private and must not be disclosed.

Only the private key can decrypt the contents encrypted by the public key. Only the public key can decrypt the contents encrypted by the private key.

Based on the above rules, RSA has two different uses:

  • Public key encryption and private key decryption: the server exposes the public key, the client obtains the public key, and transmits the data to be transmitted to the server through public key encryption. Then only the server can decrypt the data, because only the server has the private key. Even if any other middleman obtains the data in the transmission process, he can neither decrypt nor tamper with it.
  • Private key signature, public key verification signature: the content publisher uses the message digest algorithm (such as SHA-256) to calculate the hash value of the published content, then encrypts the hash value with the private key to obtain a signature, and adds the signature to the published content to publish together. After others get the content, they can decrypt the signature with the public public key to obtain the hash value, Then compare whether the hash value is consistent with the hash value generated by the content to ensure that the content has not been tampered with.

    Because it only verifies the authenticity and integrity of the data, it is not necessary to encrypt the whole content, but only encrypt the hash value of the content. Therefore, it is usually combined with the message digest algorithm. For example, SHA256 with RSA signature is to calculate the hash value with SHA-256 and then encrypt it with RSA private key.

The private key encryption and public key decryption mentioned above are only valid in theory. In fact, they will not be used directly, but only for signature. Because a piece of data encrypted by the private key, the decrypted public key is public, which means that anyone can decrypt, so encryption has no meaning.

Next, experience the RSA algorithm through Java code.

First, you need to generate a pair of public and private keys. The following is to generate a pair of public and private keys through the openssl command:

# Create a PKCS#8 format 2048 bit private key
openssl genpkey -out private_key.pem -algorithm RSA -pkeyopt rsa_keygen_bits:2048
# Generate public key from private key
openssl pkey -in private_key.pem -pubout -out public_key.pem

The generated public and private keys are Base64 encoded text files that can be opened directly with a text editor. Copy to the following code to verify public key encryption, private key decryption, private key signature and public key verification signature:

public static void main(String[] args) throws Exception {
    String publicKeyBase64 = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0XYlulDsTzDWUb6X66Ia\n" +
            "giSn1dKriHvLHYth9hCcaGomdeIQahGnxzE1o76slEyS2HZ164QHqx8Za+LuT6IV\n" +
            "yLhU/ZNLWAZABe/sdNEkhti6vSSOdJE43KS4UVADeSgtN+7uXDuVgm35EPWZjkfV\n" +
            "5hiRX4nT5ALr1niyi1Ax4BWWyG4qX00n1HzY8MvoyiLdNob71qB+amjUNy9bDhcz\n" +
            "CDWtgA/ywOYU5Ec6vMgYfbAXPKGWwo318rS3UH8QtsO8iGcQbZ76q05LNEL8G3fo\n" +
            "0Kssj4fjrVGwSsyGztRRMLfGkW/hOPCDj82+D6dGQlGB3gyB7P1xVbkD67FujQA/\n" +
            "jwIDAQAB";
    String privateKeyBase64 = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDRdiW6UOxPMNZR\n" +
            "vpfrohqCJKfV0quIe8sdi2H2EJxoaiZ14hBqEafHMTWjvqyUTJLYdnXrhAerHxlr\n" +
            "4u5PohXIuFT9k0tYBkAF7+x00SSG2Lq9JI50kTjcpLhRUAN5KC037u5cO5WCbfkQ\n" +
            "9ZmOR9XmGJFfidPkAuvWeLKLUDHgFZbIbipfTSfUfNjwy+jKIt02hvvWoH5qaNQ3\n" +
            "L1sOFzMINa2AD/LA5hTkRzq8yBh9sBc8oZbCjfXytLdQfxC2w7yIZxBtnvqrTks0\n" +
            "Qvwbd+jQqyyPh+OtUbBKzIbO1FEwt8aRb+E48IOPzb4Pp0ZCUYHeDIHs/XFVuQPr\n" +
            "sW6NAD+PAgMBAAECggEABT96joJ8iTdmB0JJOCQlmeElO1w94/uGCUV2vN2JrawL\n" +
            "LqTtWFr84ya+e03JsSWCAF5ncfEq6AStdGCJLAGZnh/QMVJBbwEpFXz/ZaXfzmkb\n" +
            "tKV31D/XNuABpjfk/mIdT+tymWj8w/nRZbVhlYkDOPKgoc4oOuw/0G3Ru1/VABI+\n" +
            "yulNx93A/JNFGk3Bkm4E7jRWyl0BkAqAX2BZkFbXG/u3Jc0eYXrG74JfMH+MEihG\n" +
            "GDMSpBKNyX5zWkUT6XxpG82t2erHPWYEoNSoFzAUu+7rZ4ECEXxazAQclEHTkR3r\n" +
            "duUZ/XF0GL1WB0GC7+qvV/Z0gxjXuwG9oToFO/0MQQKBgQDu4DuTPWcYwSWY0R1f\n" +
            "qZUOuYRwD+5OQnJMIlKAD32QmvYT/jnvigjss5Qf1IUwf1UMynj2FnVF4D7L+kvq\n" +
            "O7LzYvHAeDQwZGGt2xWBlqjfhumlfBqfklkkqUiH2A5DvfvtbX/kkiY3n9C+oYZp\n" +
            "2ejiOtSC+NqQeB74TluxroEkvwKBgQDgehynybpFl4KkmDhgj++BH5RR+xzXIChb\n" +
            "gtIbbspdE1EyXy7Z9iNAJ8PVjHkSwh8iEfAO4EuJFnonF8UNIsWLr3gsKbQytRxR\n" +
            "cewqaBhTL54Vgl5dmODNrYjkZva5HHDsCLioYGgljdrj5e/gPSAWBrgT6kI+HypQ\n" +
            "/5xyp+KJMQKBgQCMxut1P8eliBa/M+YqvYdR8TVC0bCwwGoZwlR6kiZ+9UQ2zimY\n" +
            "qPHPhZmzFI0V4sTdz+lvphahAqIfljftKBezZklxE6Y2KsKCMk4/W+nUKe9Cjpwm\n" +
            "FJqih31uSX9Gnw18hH7N1u/c8juUTR8o/LpJsUASm9Q7Nf+SeKODWINVgwKBgDEx\n" +
            "UXpLsPBzRYQAf8pZgKkRXJWirC1QtMdpIdY1L0+6Xf7l8QR+9janADmaMSY1OFFl\n" +
            "EPCRorwGGvraMKqyRgxYhcNX2E+MdQo8Jv8cFMiWFNSt3zQvvoQUVX2IOuVSIET5\n" +
            "nE354pjoP2HWD/1aJ9/r1Qc4PRAUEFfzzDssI27hAoGAOsYKtvW6iRn/WVduIRcy\n" +
            "UtBRHHX0U16zGv+I7nOOBIYK5Uan6AjgzG2MfPOBj3cUhMMBDPfVg1cTbonw5Y8F\n" +
            "nSO4VLOtqKy0BRxCIUFqltJXUmj1zAJs84IweCBQ3un/OLVUMgE7qGtaIQy2PBsy\n" +
            "M8mwuUjo3Fu7l11E2Vgz/qY=";

    // Base64 decoding
    byte[] publicKeyBytes = Base64.getDecoder().decode(publicKeyBase64.replace("\n", ""));
    byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyBase64.replace("\n", ""));

    // Generate PublicKey and PrivateKey objects
    PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(publicKeyBytes));
    PrivateKey privateKey = KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes));

    // Original text to be encrypted and signed
    String data = "Hello World";

    // Public key encryption, private key decryption
    byte[] ciphertext = encrypt(data.getBytes(), publicKey);
    System.out.println("RSA Public key encryption result( Base64): " + Base64.getEncoder().encodeToString(ciphertext));
    byte[] plaintext = decrypt(ciphertext, privateKey);
    System.out.println("RSA Private key decryption result:" + new String(plaintext));

    // Private key verification signature
    byte[] signature = sign(data.getBytes(), privateKey);
    System.out.println("RSA Private key signature result( Base64): " + Base64.getEncoder().encodeToString(signature));
    boolean verifySuccess = verify(data.getBytes(), signature, publicKey);
    System.out.println("RSA Public key verification signature result:" + verifySuccess);
}

/**
 * Public key encryption
 */
public static byte[] encrypt(byte[] data, PublicKey publicKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.ENCRYPT_MODE, publicKey);
    byte[] result = cipher.doFinal(data);
    return result;
}

/**
 * Private key decryption
 */
public static byte[] decrypt(byte[] data, PrivateKey privateKey) throws Exception {
    Cipher cipher = Cipher.getInstance("RSA");
    cipher.init(Cipher.DECRYPT_MODE, privateKey);
    byte[] result = cipher.doFinal(data);
    return result;
}

/**
 * Private key signature, SHA256 with RSA signature
 */
public static byte[] sign(byte[] data, PrivateKey privateKey) throws Exception {
    Signature signature = Signature.getInstance("SHA256withRSA");
    signature.initSign(privateKey);
    signature.update(data);
    byte[] result = signature.sign();
    return result;
}

/**
 * Public key verification signature
 */
public static boolean verify(byte[] data, byte[] sign, PublicKey publicKey) throws Exception {
    Signature signature = Signature.getInstance("SHA256withRSA");
    signature.initVerify(publicKey);
    signature.update(data);
    return signature.verify(sign);
}

Output:

RSA Public key encryption result( Base64): zoY6KM/RdCjAs7upJ9SIwqfXsSn3hAPu/z/ZPHbKgWN6+X0PpyVJVYT8jacEkzB7S2sJe/wLkO2TqXB2gqvL1AuDRgepVlxV2f6Uwx4DxM2/5RE0fAdTiICV5JEEIw81oLix0GGQ7nLjOhJxN9LaTJ2cXtwgR8gUtLtJ0tdWrxSMuN8FHLA45Nv8Ea1EAUQCvfanYZ2L39l++3/zBdg2wYQwCE6XGFnWnayUsGKYjC7JIufnq5f9VDL/kguLKceLmeTHqq31ccRTOQyhuoZjHCsbfXPlW2AT9ejgAcXy7LkXhYCfma50DBM+KUCfC4YrKBg6wKRqdZee90ZPcUKTkw==
RSA Private key decryption result: Hello World
RSA Private key signature result( Base64): AbP5zSV/qvkF8fCseVkEaZMscvznQBUDtO3g0U/FIXVmzeR6WXFwPsMd3cC3oCHtnnqsL/aRQrpW6pHU6EzSJ5w6FgY6kD4kWREq9f8LOnyQm7CoS6CK0tUiAjIgG16rtmS+oPbG+mYaZkLzo1Cpkpz2MzuMMbWNivvXRMbj3wLiXyIMqUefawipvm+GPwrWRxesRot2sGtuZcxtMMZs3NHpJ0CXV/mQlYJWEzIiHUY4mqfqpMDL/djPf9td74ABpjk38O6r1Jt75TLnMvkwRdh7pHBQLZ0Tn/6Vx2cVD2D+sE9BuhinO66B6I0QOGVcl3a5C2whp+85zEovvdGlSg==
RSA Public key verification signature result: true

At present, the ubiquitous HTTPS protocol is based on SSL/TLS protocol. In SSL/TLS protocol, there is a handshake process before establishing an encrypted transmission channel. In the handshake process, the client will generate a random value and use the public key to encrypt it and then transmit it to the server. This random value is used to generate the key of the symmetric encryption algorithm. Only the private key of the server can be decrypted, No third party can decrypt, which solves the security problem in the key transmission process of the symmetric encryption algorithm mentioned above. In the communication stage after the successful handshake, the symmetric encryption algorithm is used for communication. Because the asymmetric encryption algorithm is more complex and inefficient compared with the symmetric encryption algorithm, it is not suitable for encryption and decryption of a large amount of data.

In addition, in order to prevent forgery, the digital certificate used in SSL/TLS will also be digitally signed by CA. at present, the digital certificate used in most HTTPS websites is signed by SHA256 with RSA.

For example, open on a browser https://xxgblog.com/ , click the small lock button on the left side of the address bar to view the certificate used by the website. Its digital signature algorithm is SHA256 with RSA:

Posted by scs on Fri, 03 Dec 2021 15:26:01 -0800