RSA encryption signature for Https communication

RSA (public key cryptosystem) is generally used in the digital certificate of Https communication. Add some other knowledge before learning about RSA.

Public-key cryptography

The public key cryptosystem is divided into three parts, public key, private key, and encryption and decryption algorithm. Its encryption and decryption process is as follows:

  1. Encryption: Encrypt the content (or explanatory text) through an encryption algorithm and public key to obtain the cipher text. The public key is required for the encryption process.
  2. Decryption: Decrypt the ciphertext through the decryption algorithm and the private key to obtain the plaintext. The decryption process requires a decryption algorithm and private key.
    公钥密码体制的公钥和算法都是公开的(这是为什么叫公钥密码体制的原因),私钥是保密的。两者都可以加解密数据,公钥加密的内容只能私钥解密,私钥加密的内容只能公钥解密

Symmetric key algorithms

The symmetric encryption algorithm means that the key used for encryption and the key used for decryption are the same. Therefore, if the symmetric encryption algorithm is to ensure security, the key must be kept secret so that only the user can know it.安全系数相对较低

Asymmetric key algorithms

The asymmetric encryption algorithm means that the key used for encryption and the key used for decryption are different. RSA is an asymmetric encryption algorithm.

Secret

The key, generally a string or number, is passed to the encryption/decryption algorithm during encryption or decryption. Both encryption and decryption parties can agree on encryption and decryption methods by themselves, so a variety of encryption and decryption methods have emerged.

Data encryption and decryption

Encryption refers to converting a certain content into base64, hex and other formats through a certain encryption algorithm and secret key. Decryption is to convert encrypted information into original information through a specific decryption algorithm and secret key. Data encryption and decryption are for the safety of data transmission and prevent interception by others. Encryption and decryption algorithms are generally symmetric encryption and asymmetric encryption.

Data signature

The signature is to add a piece of content after the information, which can prove that the information has not been modified. Signature schemes generally used:

  1. It is to do a hash calculation on the information to obtain a hash value, and then send the hash value (after encryption) as a signature and the message.
  2. After receiving the information, the receiver will recalculate the hash value of the information and compare it with the hash value attached to the information (after decryption). If they are consistent, the content of the information has not been modified.
    1. 这个过程是不可逆的,也就是说无法通过hash值得出原来的信息内容。
    2.不同的内容一定会得到不同的hash值,hash的加解密是为了防止传输过程中被更改,造成信息是否被篡改无法准确验证。

RSA

RSA uses a public key cryptosystem. RSA is an algorithm designed by three mathematicians Rivest, Shamir and Adleman, so it is called RSA. It is the cornerstone of computer communication security and the most important encryption algorithm.

This algorithm is very reliable, the longer the key, the harder it is to crack. According to published documents, the longest RSA key that has been cracked is 768 binary bits. In other words, a key longer than 768 bits cannot be cracked (at least no one has publicly announced it). Therefore, it can be considered that the 1024-bit RSA key is basically safe, and the 2048-bit key is extremely safe (in network communication, it is generally 2048-bit ).
For the RSA algorithm principle, it is recommended to view the RSA algorithm principle

In practical applications, we use Https communication as an example to analyze the use of RSA, and now simulate the common dialogue between client and server in https communication:

  • client >>server: hello, this is clientA
  • server>>client: Hello, this is server.
  • client >>server: Please prove that you are Server, str [str是随机字符串]
  • server>>client:str{XXX-hash} [{}中是私钥RSA加密后内容,hash为str的has,后面都如此表示]
    [client 收到str原文,计算str的hash1,通过证书中RSA公钥解密XXX-hash,获得密文中的内容与hash2,比较解密内容与原内容是否一致,解密的hash和原文计算的hash是否一致,都一致说明服务器是真的,可以进行下一步]
  • client >>server: You are indeed the server, this is the secret key of the x encryption algorithm {XXXX}, let’s use the X encryption algorithm for communication in the future
  • server>>client:{Yes, I am ready for communication}[内容经x算法加密]
  • client >>server:{check my account balance}[内容经x算法加密]

**注意**
1. After verifying the authenticity of the identities of both parties, the two parties can agree to use a new symmetric encryption algorithm to communicate. This is relatively free and highly expandable. Different client and server communication encryption methods may be different.
2. After verifying the identities of both parties, the client can also pass the asymmetric public key generated by itself to the server, and communicate between the two parties through asymmetric encryption.

Communication premise: the client has obtained the server's digital certificate. The certificate contains the server RSA public key. For the principle of digital certificates and other information, please read this blog digital certificate .
Generally, when we develop applications, we put a digital certificate in the program for the first time. When it is about to expire, we can download a new certificate through the server to save it and put it into use.

doubt:

1. Why use RSA to encrypt and decrypt communication content?
Answer: For data security, the direct communication between client and server can be attacked by hackers at multiple levels. Data theft and data tampering can be carried out by disguising as server or client.

2. Why not get the server certificate during the first call? Or download it on a website?
Answer: The website you visit at the beginning may not be a real website, and the downloaded or transmitted certificate can also be a fake certificate.

3. Why use both encryption and signature for communication content?
Answer: Although "hackers" cannot know the encrypted content, they can modify the encrypted content, such as adding a section of content to the first position, replacing part of the information, and causing information interference. The information is worth signing through encryption and content hash, and it can be judged whether the communication content has been modified and damaged, and whether it is complete.

4. Why does the client verify the server signature through the hash of a random string instead of directly through encryption and decryption?
Answer: Because "hackers" can find the encryption law by sending simple and regular strings, such as "0,1,2,3,4", etc., and crack the encryption method. This is not safe. By encrypting the hash value of the string, after the client receives the content, it decrypts the hash value of the string and compares it with the hash calculated from the passed string to verify the server's signature.

5. How to solve the problem of "hackers" intercepting encrypted content and repeatedly sending information?
Answer: Add serial number and random number to the communication content. If the client or server receives the same information, it means that the communication has been interfered and the communication should be stopped for other processing. .

Summary:
1. Encryption of information in communication can be seen as preventing data leakage and being decrypted and stolen
. 2. Data signature is to determine whether the received data is complete to
ensure that the client and server can receive complete encrypted data that cannot be decrypted by irrelevant parties. It is the core point of network communication data security.

Attach an RSA tool class

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.Cipher;
/**
 * 时间:2020/4/20 0020    星期一
 * 邮件:[email protected]
 * 说明:RSA非对称加密
 */
class RSAUtils {
    
    
    private final String CHARSET = "UTF-8";
    private final String RSA_ALGORITHM = "RSA";

    private Map<String, String> createKeys(int keySize) {
    
    
        //为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try {
    
    
            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
    
    
            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
        }

        //初始化KeyPairGenerator对象,密钥长度
        kpg.initialize(keySize);
        //生成密匙对
        KeyPair keyPair = kpg.generateKeyPair();
        //得到公钥
        Key publicKey = keyPair.getPublic();
        String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());

        //得到私钥
        Key privateKey = keyPair.getPrivate();
        String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
        Map<String, String> keyPairMap = new HashMap<>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);
        return keyPairMap;
    }

    /**
     * 得到公钥
     *
     * @param publicKey 密钥字符串(经过base64编码)
     */
    private RSAPublicKey getPublicKey(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    
    
        //通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey));
        return (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
    }

    /**
     * 得到私钥
     * @param privateKey 密钥字符串(经过base64编码)
     */
    private RSAPrivateKey getPrivateKey(String privateKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
    
    
        //通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.getDecoder().decode(privateKey));
        return (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
    }

    /**
     * 公钥加密
     */
    private String publicEncrypt(String data, RSAPublicKey publicKey) {
    
    
        try {
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] bytes = rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), publicKey.getModulus().bitLength());
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
    
    
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 私钥解密
     *
     * @param data    待解密数据
     * @param privateKey    私钥
     */
    private String privateDecrypt(String data, RSAPrivateKey privateKey) {
    
    
        try {
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] bytes = Base64.getDecoder().decode(data);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, bytes, privateKey.getModulus().bitLength()), CHARSET);
        } catch (Exception e) {
    
    
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 私钥加密
     *
     */
    public String privateEncrypt(String data, RSAPrivateKey privateKey) {
    
    
        try {
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.ENCRYPT_MODE, privateKey);
            byte[] bytes = rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET), privateKey.getModulus().bitLength());
            return Base64.getEncoder().encodeToString(bytes);
        } catch (Exception e) {
    
    
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 公钥解密
     */
    public String publicDecrypt(String data, RSAPublicKey publicKey) {
    
    
        try {
    
    
            Cipher cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(Cipher.DECRYPT_MODE, publicKey);
            byte[] bytes = Base64.getDecoder().decode(data);
            return new String(rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, bytes, publicKey.getModulus().bitLength()), CHARSET);
        } catch (Exception e) {
    
    
            throw new RuntimeException("解密字符串[" + data + "]时遇到异常", e);
        }
    }

    private byte[] rsaSplitCodec(Cipher cipher, int opmode, byte[] datas, int keySize) {
    
    
        int maxBlock;
        if (opmode == Cipher.DECRYPT_MODE) {
    
    
            maxBlock = keySize / 8;
        } else {
    
    
            maxBlock = keySize / 8 - 11;
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        int offSet = 0;
        byte[] buff;
        int i = 0;
        try {
    
    
            while (datas.length > offSet) {
    
    
                if (datas.length - offSet > maxBlock) {
    
    
                    buff = cipher.doFinal(datas, offSet, maxBlock);
                } else {
    
    
                    buff = cipher.doFinal(datas, offSet, datas.length - offSet);
                }
                out.write(buff, 0, buff.length);
                i++;
                offSet = i * maxBlock;
            }
        } catch (Exception e) {
    
    
            throw new RuntimeException("加解密阀值为[" + maxBlock + "]的数据时发生异常", e);
        }
        byte[] resultDatas = out.toByteArray();
        try {
    
    
            out.close();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return resultDatas;
    }

    public static void main(String[] args) throws Exception {
    
    
        RSAUtils rsaUtils = new RSAUtils();
        Map<String, String> keyMap = rsaUtils.createKeys(1024);
        String publicKey = keyMap.get("publicKey");
        String privateKey = keyMap.get("privateKey");
        System.out.println("公钥: \n\r" + publicKey);
        System.out.println("私钥: \n\r" + privateKey);

        System.out.println("公钥加密——私钥解密");
        String str = "孙子,我是你爸爸";
        System.out.println("\r明文:\r\n" + str);
        System.out.println("\r明文大小:\r\n" + str.getBytes().length);
        String encodedData = rsaUtils.publicEncrypt(str, rsaUtils.getPublicKey(publicKey));
        System.out.println("密文:\r\n" + encodedData);
        String decodedData = rsaUtils.privateDecrypt(encodedData, rsaUtils.getPrivateKey(privateKey));
        System.out.println("解密后文字: \r\n" + decodedData);
    }
}

该篇博客纯属个人观点和见解,如有错误恳请留言指正,万分感激!

Related Links:

  1. RSA algorithm principle
  2. Digital certificate for Https communication

Guess you like

Origin blog.csdn.net/luo_boke/article/details/106013674