In job interviews, we are often asked, how to design a secure external interface? In fact, you can answer this point by adding and verifying signatures, which will make your interface more secure. Next, this article will work with you to learn the addition and verification of signatures. From theory to practice, come on~
 Cryptography related concepts
 Concept of signature verification
 Why is it necessary to add and verify signatures
 Introduction to encryption algorithm
 API related to signature verification
 Implementation of signature verification code
This article has been included in personal github. If the article is useful, you can give it to a star:
❝https://github.com/whx123/JavaHome
❞Cryptography related concepts
Plaintext, ciphertext, key, encryption and decryption
 Plaintext: refers to information / data that has not been encrypted.
 Ciphertext: after the plaintext is encrypted by the encryption algorithm, it will become ciphertext to ensure data security.
 Key: a parameter that is input in the algorithm of converting plaintext to ciphertext or ciphertext to plaintext. The key is divided into symmetric key and asymmetric key.
 Encryption: the process of transforming plaintext into ciphertext.
 Decryption: the process of restoring ciphertext to plaintext.
Symmetric encryption, asymmetric encryption

Symmetric encryption: an encryption algorithm that uses the same key for encryption and decryption.

Asymmetric encryption: asymmetric encryption algorithm requires two keys (public key and private key). The public key and the private key exist in pairs. If the public key is used to encrypt the data, only the corresponding private key can be decrypted.
What is a public or private key?
 The public key and private key exist in pairs. If the public key is used to encrypt the data, only the corresponding private key can be used to decrypt.
 In fact, the public key is the public secret key, and the private key is the secret key you need to keep privately.
 Asymmetric encryption algorithm needs a pair of public and private keys~
Suppose you have a file, you encrypt it with the letter A, and only the letter b can decrypt it; Or if you encrypt with b and only a can decrypt, then a and b are a pair of public and private keys. If key a is public, you should keep key b privately. At this time, key a is the public key and key b is the private key. On the contrary, if b is public, a must keep it. At this time, secret key b is the public key and secret key a is the private key.
❞Concept of signature verification

"Signature": use the Hash function to generate a message summary from the original message, and then encrypt the summary with the private key to obtain the corresponding digital signature of the message. Generally speaking, the requesting party will send the "digital signature and original message" to the receiving party.

"Signature verification": after receiving the original message and digital signature, the receiver uses "the same Hash function" to generate summary A from the message. In addition, decrypt the digital signature with the public key provided by the other party to obtain Abstract B. compare whether A and B are the same, and you can know whether the message has been tampered with.
Why do I need to sign for verification
In the last section, we already know the concept of signature addition and signature verification. Then, why do we need signature addition and signature verification? Some friends may think that we should use "public key encryption and private key decryption"?
Next, let's give a demo.
❝Suppose there is company A now, which needs to access the transfer system of company C. At the beginning, company C sent its public key to company A and collected its private key. When the merchant on the side of company A initiates the transfer, company A first encrypts the request message with the public key of company C. when the encrypted message reaches the transfer system of company C, company C will uncover the message with its own private key. Assuming that the encrypted message is obtained by the intermediary Actor during transmission, he is also depressed because he has no private key and can't eat swan meat. Originally, I wanted to modify the message and transfer one hundred million to my account. Ha ha. This implementation seems seamless and stable.
❞
However, at the beginning, when company C sends the public key to company A, it is obtained by the intermediary Actor, and there is A problem with maozi.
❝The intermediary Actor intercepted C's public key. He sent his public key to company A. a mistakenly thought that this was the public key of company C. When a initiates the transfer, he encrypts the request message with the Actor's public key. When the encrypted message is transmitted, the Actor intercepts it again. At this time, he decrypts the message with his own private key, then modifies the message (transfer one hundred million to himself), encrypts it with C's public key and sends it to company C. After receiving the message, company C continues to decrypt it with his own private key. Finally, did the transfer account of company a lose 100 million~
❞
How does company C distinguish whether the message comes from A or has been modified by an intermediary? In order to show the identity and authenticity of the message, it is necessary to "add signature and verify signature"!
❝Company A also sends its public key to company C, and the private key is kept by itself. When initiating the transfer, first sign the request message with your own private key, and then get your own digital signature. Then send the digital signature and request message to company C. After receiving the message, company C takes A's public key for signature verification. If the original message is inconsistent with the summary of the digital signature, it means that the message has been tampered with~
❞Some friends may have questions. Suppose A is intercepted by the intermediary Actor when sending his public key to company C. Uh huh, let's simulate A wave of actors and intercept the public key to see what the actors can do ~ ha ha
❝Suppose the Actor intercepts the public key of A and then intercepts the message from A to C. After intercepting the message, the first thing he wants to do must be to modify the message content. However, it is not allowed to modify the original message only, because company C will not be able to check and sign it. However, it seems that the digital signature cannot be solved, because the message digest algorithm (hash algorithm) cannot be solved inversely and only plays the role of verification
❞Therefore, the public key and private key are used for encryption and encryption, and "signature addition and signature verification are used to prove identity" to avoid being tampered with.
Introduction to common encryption related algorithms
 Message digest algorithm
 Symmetric encryption algorithm
 Asymmetric encryption algorithm
 State secret algorithm
Message digest algorithm:
 The same plaintext data will get the same ciphertext result value through the same message digest algorithm.
 After the data is processed by the message summary algorithm, the summary result value obtained cannot be restored to the data before processing.
 Data summarization algorithm is also called Hash algorithm or Hash algorithm.
 Message digest algorithm is generally used for signature verification.
Message Digest algorithms are mainly divided into three categories: MD (Message Digest algorithm), SHA (Secure Hash Algorithm) and MAC (Message Authentication Code algorithm).
MD family algorithm
MD (Message Digest) family, including MD2, MD4 and MD5.
 The result of MD2, MD4 and MD5 calculation is a 128 bit (i.e. 16 byte) hash value, which is used to ensure the integrity and consistency of information transmission.
 MD2's algorithm is slow but relatively safe. MD4's speed is fast, but its security decreases. MD5 is safer and faster than MD4.
 MD5 is widely used in data integrity verification, data (message) summary, data encryption and so on.
 MD5 can be cracked. For data requiring high security, experts generally recommend using other algorithms, such as SHA2. In 2004, it was confirmed that MD5 algorithm can not prevent collision attacks, so it is not suitable for security authentication, such as SSL public key authentication or digital signature.
For example, let's see how to get the MD5 value of a string:
public class MD5Test { public static void main(String[] args) throws UnsupportedEncodingException { String s = "123"; byte[] result = getMD5Bytes(s.getBytes()); StringBuilder stringBuilder = new StringBuilder(); for (byte temp : result) { if (temp >= 0 && temp < 16) { stringBuilder.append("0"); } stringBuilder.append(Integer.toHexString(temp & 0xff)); } System.out.println(s + ",MD5 After encryption:" + stringBuilder.toString()); } private static byte[] getMD5Bytes(byte[] content) { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); return md5.digest(content); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } } }
Operation results:
123,MD5 After encryption:202cb962ac59075b964b07152d234b70
ShA family algorithm
Sha (Secure Hash Algorithm), including SHA0, SHA1, SHA2(SHA256,SHA512,SHA224,SHA384, etc.), SHA3. It is implemented on the basis of MD algorithm. The difference from MD algorithm is "summary length". Sha algorithm has "longer length and higher security".
❝ The security of NSA0 will be reduced soon after it is released because it contains an error.
 SHA1 is widely used in many security protocols, including TLS, GnuPG, SSH, S/MIME and IPsec. It is the successor of MD5.
 SHA512, SHA256, SHA224. Its algorithm is basically similar to SHA1, and there is no obvious weakness at present.
 SHA3 was officially released in 2015. Due to the successful cracking of MD5 and the theoretical cracking method of SHA0 and SHA1, SHA3 came into being. Different from the previous algorithm, it is an alternative encrypted hash algorithm.
SHA1, SHA2(SHA256,SHA512,SHA224,SHA384) and other algorithms are commonly used. Let's see the comparison with MD5
Algorithm type  Summary length (bits)  Maximum input message length (bits)  Collision attack (bits)  Performance example (MiB/s) 

MD5  128  infinite  ≤ 18 (collision found)  335 
SHA1  160  2^64 − 1  < 63 (collision found)  192 
SHA224  224  2^64 − 1  112  139 
SHA256  256  2^64 − 1  128  139 
SHA384  384  2^128 − 1  192  154 
SHA512  512  2^128 − 1  256  154 
MAC algorithm family
MAC algorithm MAC (Message Authentication Code algorithm) is a Hash function with a key. Enter the key and message, and output a message summary. It integrates MD and SHA two series of message summarization algorithms.
 MD series algorithms: HmacMD2, HmacMD4 and HmacMD5;
 SHA series algorithms: HmacSHA1, HmacSHA224, HmacSHA256, HmacSHA384 and HmacSHA512.
Symmetric encryption algorithm
The encryption algorithm that uses the "same key" for encryption and decryption is the symmetric encryption algorithm. Common symmetric encryption algorithms include AES, 3DES, DES, RC5, RC6, etc.
DES
Data Encryption Standard (DES) is a symmetric Key encryption block cipher algorithm. There are three entry parameters of DES algorithm: Key, data and Mode.
 Key: 7 bytes, 56 bits in total, which is the working key of DES algorithm;
 Data: 8 bytes and 64 bits, which are the data to be encrypted or decrypted;
 Mode: encryption or decryption.
3DES
Triple Data Encryption Algorithm, also known as 3DES (Triple DES), is a symmetric key encryption block password, which is equivalent to applying the triple data encryption standard (DES) algorithm to each data block.
AES
AES, Advanced Encryption Standard, also known as Rijndael encryption in cryptography, is a block encryption standard adopted by the federal government of the United States.
 The symmetric block cipher system is adopted. The key length is 128 bits, 192 bits and 256 bits, and the packet length is 128 bits
 Compared with DES, AES has better security, efficiency and flexibility.
Asymmetric encryption algorithm
Asymmetric encryption algorithm requires two keys: public key and private key. The public key and the private key exist in pairs. If the data is encrypted with the public key, only the corresponding private key can be decrypted. The main asymmetric encryption algorithms are RSA, Elgamal, DSA, DH and ECC.
RSA algorithm
 RSA encryption algorithm is an asymmetric encryption algorithm, which is widely used in encryption and digital signature
 RSA algorithm principle: the factorization of the product of two large prime numbers is extremely difficult, so the product can be disclosed as an encryption key.
 RSA is the most widely studied public key algorithm. From its proposal to now, it has experienced the test of various attacks. It is generally considered to be one of the best public key schemes at present.
DSA
 DSA(Digital Signature Algorithm) is also an asymmetric encryption algorithm.
 The difference between DSA and RSA is that DSA is only used for digital signature and cannot be used for data encryption and decryption. Its security is equivalent to RSA, but its performance is better than RSA.
ECC algorithm
 ECC (Elliptic Curves Cryptography), based on elliptic curve encryption.
 The main advantage of Ecc is that in some cases, it uses smaller keys than other methods, such as RSA encryption algorithm, which provides an equivalent or higher level of security.
 One of its disadvantages is that the implementation of encryption and decryption takes longer than other mechanisms (compared with RSA algorithm, this algorithm consumes a lot of CPU).
State secret algorithm
State secret is the domestic cryptographic algorithm recognized by the state cryptographic Bureau. In order to ensure the security of commercial passwords, the state commercial password management office has formulated a series of password standards, namely SM1, SM2, SM3, SM4 and other national secret algorithms.
SM1
 SM1 is a symmetric encryption algorithm with encryption strength of 128 bits, which is implemented based on hardware.
 The encryption strength and performance of SM1 are equivalent to AES.
SM2
 SM2 mainly includes three parts: signature algorithm, key exchange algorithm and encryption algorithm
 SM2 is used to replace RSA encryption algorithm. It is based on ECC and has low efficiency.
SM3
 SM3, the domestic message digest algorithm.
 It is suitable for digital signature and verification in commercial cryptographic applications, generation and verification of message authentication code and generation of random number.
SM4
 SM4 is a grouping algorithm for WLAN products.
 The packet length of the algorithm is 128 bits and the key length is 128 bits.
 Both encryption algorithm and key expansion algorithm adopt 32 rounds of nonlinear iterative structure.
 The structure of the decryption algorithm is the same as that of the encryption algorithm, but the use order of the round key is opposite. The decryption round key is the reverse order of the encryption round key.
 Its function is similar to DES of international algorithm.
Java API related to signature verification
This section first introduces the API used for signature verification~
API related to endorsement
 java.security.Signature.getInstance(String algorithm); //Initialize the signature object according to the corresponding algorithm  KeyFactory.getInstance(String algorithm);// According to the corresponding algorithm,generate KeyFactory object  KeyFactory.generatePrivate(KeySpec keySpec); //Generate private key  java.security.Signature.initSign(PrivateKey privateKey) //Initialize the signing object by the private key  java.security.Signature.update(byte[] data) //Update the original message to the signature object  java.security.Signature.sign();//Countersign
「Signature.getInstance(String algorithm);」
 Initialize the signature object according to the corresponding algorithm
 The algorithm parameter can take parameters such as SHA256WithRSA or MD5WithRSA. SHA256WithRSA indicates that SHA256 algorithm is used to generate summary and RSA algorithm is used to add signature
「KeyFactory.getInstance(String algorithm);」
 Generate the KeyFactory object according to the corresponding algorithm. For example, if your public and private keys use RSA algorithm, it will be passed into RSA
「KeyFactory.generatePrivate(KeySpec keySpec)」
 The private key is generated and signed with the private key. Therefore, a private key object needs to be constructed through KeyFactory.
「Signature.initSign(PrivateKey privateKey)」
 The private key is used for signing, so the private key is passed in to initialize the signing object
「Signature.update(byte[] data)」
 Update the original message to the signature object
「java.security.Signature.sign();」
 Add signature
API related to signature verification
 java.security.Signature.getInstance(String algorithm); //Initialize the signature object according to the corresponding algorithm  KeyFactory.getInstance(String algorithm);// According to the corresponding algorithm,generate KeyFactory object  KeyFactory.generatePublic(KeySpec keySpec); //Generate public key  java.security.Signature.initVerify(publicKey); //The signature verification object is initialized by the public key  java.security.Signature.update(byte[] data) //Update the original message to the signature verification object  java.security.Signature.verify(byte[] signature);//Signature verification
「Signature.getInstance(String algorithm)」
 Initialize the signature object according to the corresponding algorithm. Note that the same algorithm parameters are required for signature verification and signature addition~
「KeyFactory.getInstance(String algorithm);」
 Generate the KeyFactory object according to the corresponding algorithm
「KeyFactory.generatePublic(KeySpec keySpec);」
 Generate the public key. The public key is used for signature verification. First construct a public key object through KeyFactory
「Signature.initVerify(publicKey);」
 Public key signature verification, so pass in the public key object parameter to initialize the signature verification object
「Signature.update(byte[] data)」
 Update the original message to the signature object
「Signature.verify(byte[] signature);」
 Conduct signature verification
Implementation of signature verification code
After discussing the concept in the previous sections, it's time for code practice. I use SHA256 as the summary algorithm and RSA as the signature verification algorithm, as follows:
package pattern; import sun.misc.BASE64Decoder; import sun.misc.BASE64Encoder; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.*; import java.security.spec.InvalidKeySpecException; import java.security.spec.PKCS8EncodedKeySpec; /** * Signature verification demo * @Author Little boy picking snails */ public class SignatureTest { //Public key string private static final String PUBLIC_KEY_STR = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDaJzVjC5K6kbS2YE2fiDs6H8pB\n" + "JFDGEYqqJJC9I3E0Ebr5FsofdImV5eWdBSeADwcR9ppNbpORdZmcX6SipogKx9PX\n" + "5aAO4GPesroVeOs91xrLEGt/arteW8iSD+ZaGDUVV3+wcEdci/eCvFlc5PUuZJou\n" + "M2XZaDK4Fg2IRTfDXQIDAQAB"; //Private key string private static final String PRIVATE_KEY_STR = "MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBANonNWMLkrqRtLZg\n" + "TZ+IOzofykEkUMYRiqokkL0jcTQRuvkWyh90iZXl5Z0FJ4APBxH2mk1uk5F1mZxf\n" + "pKKmiArH09floA7gY96yuhV46z3XGssQa39qu15byJIP5loYNRVXf7BwR1yL94K8\n" + "WVzk9S5kmi4zZdloMrgWDYhFN8NdAgMBAAECgYA9bz1Bn0i68b2KfqRdgOfs/nbe\n" + "0XNN1DLQp2t7WDfRCg01iI1zPkZgyFVZWtI85f5/uIrLs5ArLosL1oNuqqc0nNne\n" + "CvJK+ZxvA98Hx3ZqYTzDnleR054YhofL5awbhSciYVic204DOG1rhSsYWMqtX7J7\n" + "3geoWL7TYdMfYXcCAQJBAPMMKsz6ZJh98EeQ1tDG5gpAGWFQkYNrxZDelP/LjeO0\n" + "TP3XkQnIpcaZoCs7V/rRGRGMWwQ2BUdc/01in89ZZ5ECQQDlx2oBc1CtOAm2UAhN\n" + "1xWrPkZWENQ53wTrwXO4qbTGDfBKon0AehLlGCSqxQ71aufLkNO7ZlX0IHTAlnk1\n" + "TvENAkAGSEQ69CXxgx/Y2beTwfBkR2/gghKg0QJUUkyLqBlMz3ZGAXJwTE1sqr/n\n" + "HiuSAiGhwH0ByNuuEotO1sPGukrhAkAMK26a2w+nzPL+u+hkrwKPykGRZ1zGH+Cz\n" + "19AYNKzFXJGgclCqiMydY5T1knBDYUEbj/UW1Mmyn1FvrciHoUG1AkAEMEIuDauz\n" + "JabEAU08YmZw6OoDGsukRWaPfjOEiVhH88p00veM1R37nwhoDMGyEGXVeVzNPvk7\n" + "cELg28MSRzCK"; public static void main(String[] args) throws SignatureException, NoSuchAlgorithmException, InvalidKeyException, IOException, InvalidKeySpecException { //Original message String plain = "Welcome to my official account, the little boy who picks up snails"; //Countersign byte[] signatureByte = sign(plain); System.out.println("The original message is:" + plain); System.out.println("Countersignature result:"); System.out.println(new BASE64Encoder().encode(signatureByte)); //Signature verification boolean verifyResult = verify(plain, signatureByte); System.out.println("Signature verification results:" + verifyResult); } /** * Signature method * @param plain * @return * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws UnsupportedEncodingException * @throws SignatureException */ private static byte[] sign(String plain) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException, SignatureException { //Obtain the signature object instance according to the corresponding algorithm Signature signature = Signature.getInstance("SHA256WithRSA"); //The private key is used for obtaining and signing. The private key is generally read in the configuration file. Here, for the convenience of demonstration, the private key object is generated according to the private key string PrivateKey privateKey = getPriveteKey(PRIVATE_KEY_STR); //Initialize signature object signature.initSign(privateKey); //Update the original message to the object signature.update(plain.getBytes("UTF8")); //Countersign return signature.sign(); } /** * Signature verification method * @param plain * @param signatureByte * @return * @throws NoSuchAlgorithmException * @throws InvalidKeyException * @throws IOException * @throws SignatureException * @throws InvalidKeySpecException */ private static boolean verify(String plain, byte[] signatureByte) throws NoSuchAlgorithmException, InvalidKeyException, IOException, SignatureException, InvalidKeySpecException { //Get public key PublicKey publicKey = getPublicKey(PUBLIC_KEY_STR); //Obtain the signature object instance according to the corresponding algorithm Signature signature = Signature.getInstance("SHA256WithRSA"); //Initialize signature object signature.initVerify(publicKey); //Update the original message to the signature object signature.update(plain.getBytes("UTF8")); //Conduct signature verification return signature.verify(signatureByte); } private static PublicKey getPublicKey(String publicKeyStr) throws InvalidKeySpecException, IOException { PublicKey publicKey = null; try { java.security.spec.X509EncodedKeySpec bobPubKeySpec = new java.security.spec.X509EncodedKeySpec( new BASE64Decoder().decodeBuffer(publicKeyStr)); // RSA Symmetric encryption algorithm java.security.KeyFactory keyFactory; keyFactory = java.security.KeyFactory.getInstance("RSA"); // Generate public key object publicKey = keyFactory.generatePublic(bobPubKeySpec); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return publicKey; } private static PrivateKey getPriveteKey(String privateKeyStr) { PrivateKey privateKey = null; PKCS8EncodedKeySpec priPKCS8; try { priPKCS8 = new PKCS8EncodedKeySpec(new BASE64Decoder().decodeBuffer(privateKeyStr)); KeyFactory keyf = KeyFactory.getInstance("RSA"); privateKey = keyf.generatePrivate(priPKCS8); } catch (IOException  NoSuchAlgorithmException  InvalidKeySpecException e) { e.printStackTrace(); } return privateKey; } }
"Operation result:"
The original message is:Welcome to my official account, the little boy who picks up snails Countersignature result: Oz15/aybGe42eGHbc+iMoSYHSCc8tfRskTVjjGSTPD4HjadL0CC5JUWNUW0WxHjUb4MvxWo2oeWE Qw0+m61d+JgBMto/TWcVDcgwL/AbObsbWdQ6E/fVRqG13clkE8MyKsjt9Z7tcbwpycYTv0rUR4co rndAVfBdtv5KeV+OXqM= Signature verification results:true
Reference
[1] Wikipedia: https://zh.wikipedia.org/wiki/Wikipedia:%E9%A6%96%E9%A1%B5
[2] Baidu Encyclopedia: https://baike.baidu.com/
[3] Introduction to common message summarization algorithms: https://cloud.tencent.com/developer/article/1584742
[4] On seven common encryption algorithms and their implementation: https://juejin.im/post/5b48b0d7e51d4519962ea383#heading12
[5] [error prone concept] state secret algorithm SM1 (SCB2), SM2, SM3, SM4, SM7, SM9, ZUC:https://www.jianshu.com/p/8c3657a1769f