[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Time:2022-11-24

Passwords are closely related to our lives, from state secrets to personal accounts, we deal with passwords every day:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

So, where does the password come from? How is common encryption implemented in daily life? How to ensure the security of personal information? This article will briefly discuss these aspects. If there are any mistakes, please correct me.

The code part starts from the second chapter – common encryption algorithms, and those who are more interested in the code can start from the second chapter.

1. History of Cryptography

Cryptography is the foundation of network security, information security, blockchain and other products. Common asymmetric encryption, symmetric encryption, hash functions, etc. all belong to the category of cryptography.

Cryptography has a history of thousands of years. From the initial substitution method to today’s asymmetric encryption algorithm, it has gone through three stages: classical cryptography, modern cryptography and modern cryptography. Cryptography is not only the wisdom of mathematicians, but also an important foundation for today’s cyberspace security.

1.1 Classical Cryptography

The encryption methods of classical ciphers mainly includeSubstitution methodandShift method. Although the classical cipher is very simple, it is the longest encryption method used in the history of cryptography. Until the mathematical method of “probability theory” was discovered, the classical cipher was cracked.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

1.2 Modern Cryptography

The security of classical ciphers has been threatened, and the convenience of use is low. In the industrial age, modern ciphers are widely used.

Enigma machine

The Enigma machine is an encryption machine used by Nazi Germany during World War II. It was later deciphered by the United Kingdom. The personnel involved in the deciphering include Turing, who is known as the father of computer science and artificial intelligence.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

1.3 Modern Cryptography

① Hash function

Hash function, also see hash function, digest function or hash function, can convert a message of any length into a fixed-length value after operation, the common ones are MD5, SHA-1, SHA256, which are mostly used in file verification, digital Signing.

MD5 can generate a 128-bit (16-byte) hash value from an original text of any length

SHA-1 can generate a 160-bit (20-byte) hash value from an original text of any length

② Symmetric encryption

Symmetric ciphers use the same encryption key and decryption key. There are two types of symmetric ciphers: sequence cipher (stream cipher) and block cipher (block cipher). A stream cipher encrypts each element (a letter or a bit) in the information flow as a basic processing unit, and a block cipher first divides the information flow into blocks and then encrypts each block separately.

For example, if the original text is 1234567890, stream encryption first encrypts 1, then encrypts 2, and then encrypts 3… Finally, it is spliced ​​into ciphertext; block encryption is first divided into different blocks, such as 1234 into blocks, 5678 into blocks, 90XX (XX is the complement number) into blocks, and then encrypt different blocks separately, and finally splicing them into ciphertext. The classical cryptography encryption methods mentioned above all belong to stream encryption.

③ Asymmetric encryption

The key security of symmetric cryptography is extremely important. Encryptors and decryptors need to negotiate the key in advance and ensure the security of the key separately. Once the key is leaked, even if the algorithm is secure, the privacy of the original information cannot be guaranteed.

In actual use, remote key negotiation in advance is not easy to achieve. Even if it is well negotiated, it is easy to be obtained by others during the remote transmission process. Therefore, asymmetric keys have highlighted their advantages at this time.

Asymmetric encryption has two keys, the public key (publickey) and the private key (privatekey), and the encryption and decryption operations use different keys. After encrypting the original text with the public key, it needs to be decrypted by the private key; after encrypting the original text with the private key (generally called signature at this time), it needs to be decrypted by the public key (generally called signature verification at this time). The public key can be made public. Everyone uses the public key to encrypt the information, and then sends it to the holder of the private key. The holder of the private key uses the private key to decrypt the information and obtain the original text of the information. Because only one person holds the private key, there is no need to worry about being decrypted by others to obtain the original text of the information.

2. Common encryption algorithms

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Let’s take a look at several common encryption methods in life:

2.1 Symmetric encryption algorithm

Using the encryption method of a single-key cryptosystem, the same key can be used for both encryption and decryption of information. This encryption method is called symmetric encryption, also known as single-key encryption.

example

  • We now have an original 3 to send to B
  • Set the key to 108, 3 * 108 = 324, send 324 as ciphertext to B
  • After B gets the ciphertext 324, use 324/108 = 3 to get the original text

Common Encryption Algorithms

DES :Data Encryption Standard, or Data Encryption Standard, is a block algorithm that uses key encryption. It was identified as the Federal Data Processing Standard (FIPS) by the National Bureau of Standards of the US federal government in 1977 and authorized for use in unclassified government communications. Subsequently, the algorithm was widely circulated internationally.

AES: Advanced Encryption Standard, Advanced Encryption Standard. Also known as Rijndael encryption in cryptography, it is a block encryption standard adopted by the US federal government. This standard is used to replace the original DES, has been analyzed by many parties and is widely used all over the world.

features

  • Encryption speed is fast and can encrypt large files
  • The ciphertext is reversible, once the key file is leaked, it will lead to data exposure
  • After encryption, the corresponding character cannot be found in the code table, and garbled characters appear
  • Generally used in conjunction with Base64

2.1.1 DES encryption

Sample code des encryption algorithm

Cipher: Documentationhttps://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html#getInstance-java.lang.String-

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

run:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

The reason for this bug is that the DES algorithm stipulates that the key must be 8 bytes;

Modify the key key = “12345678” and run again. The garbled characters appear because the corresponding byte has a negative number, but the negative number does not appear in the ascii code table, so there are garbled characters and need to be transcoded with base64

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.1.2 Extension: base64 encoding

In Java 8, Base64 encoding has become the standard for Java class libraries.

Java 8 has a built-in encoder and decoder for Base64 encoding.

The Base64 tool class provides a set of static methods to obtain the following three BASE64 codecs:

– Basic:The output is mapped to a set of characters A-Za-z0-9+/, the encoding does not add any line marks, and the decoding of the output only supports A-Za-z0-9+/.

– URL:The output maps to a set of characters A-Za-z0-9+_, and the output is a URL and a file.

– MIME:The output is mapped to a MIME-friendly format. Output no more than 76 characters per line, and use ‘r’ followed by ‘n’ as separator. The encoded output has no line split at the end.

The above example is encoded with base64 that comes with Java8:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

run:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

In addition to the above encoding methods, there are other encoding methods for base64. Due to the limited time of the author, there is not much research. Here is a demo for your reference:

import org.junit.Test;

import java.io.UnsupportedEncodingException;
import java.util.Base64;
import java.util.UUID;

/**
 * In Java 8, Base64 encoding has become the standard for Java class libraries.
 * Java 8 has a built-in encoder and decoder for Base64 encoding.
 * The Base64 tool class provides a set of static methods to obtain the following three BASE64 codecs:
 * <p>
 * Basic: The output is mapped to a set of characters A-Za-z0-9+/, the encoding does not add any line marks, and the decoding of the output only supports A-Za-z0-9+/.
 * URL: The output is mapped to a set of characters A-Za-z0-9+_, the output is URL and file.
 * MIME: The output is mapped to a MIME-friendly format. Output no more than 76 characters per line, and use 'r' followed by 'n' as separator. The encoded output has no line split at the end.
 */
public class Base64Test {

    private static final String UTF_8 = "utf-8";
    private static final int MAX = 10;

    @Test
    public void base64() throws UnsupportedEncodingException {
//        test();
//        basic();
        url();
//        mime();

    }

    /**
     * Test several special characters
     */
    private void test() throws UnsupportedEncodingException {
        String ss = "Friday?/|";
        System.out.println("ordinal         : " + ss);
        byte[] encode = Base64.getEncoder().encode(ss.getBytes(UTF_8));
        System.out.println("basic encode    : " + new String(encode, UTF_8));

        byte[] decode = Base64.getDecoder().decode(encode);
        System.out.println("Using Basic     : " + new String(decode, UTF_8));

        byte[] decode1 = Base64.getUrlDecoder().decode(encode);
        System.out.println("Using URL       : " + new String(decode1, UTF_8));

        byte[] decode2 = Base64.getMimeDecoder().decode(encode);
        System.out.println("Using MIME      : " + new String(decode2, UTF_8));

        System.out.println();
    }

    /**
     * MIME encoders will produce BASE64 output using basic alphanumerics,
     * And friendly to MIME format: each output line does not exceed 76 characters, and each line ends with "rn" character
     */
    private void mime() throws UnsupportedEncodingException {

        StringBuilder sb = new StringBuilder();
        for (int t = 0; t < MAX; ++t) {
            sb.append(UUID.randomUUID().toString());
        }

        byte[] toEncode = sb.toString().getBytes("utf-8");
        String mimeEncoded = Base64.getMimeEncoder().encodeToString(toEncode);
        System.out.println("Using MIME      : ");
        System.out.println(mimeEncoded);
    }

    /**
     * But because the URL has a special meaning for the backslash "/", URL encoding needs to replace it, using an underscore instead
     * If the basic encoder is used, the output may contain backslash "/" characters,
     * But if a URL encoder is used, then the output is URL-safe.
     */
    private void url() throws UnsupportedEncodingException {

        String ordinal = "subjects?abcd";
        System.out.println("ordinal         : " + ordinal);

        // The output is: Using Basic Alphabet: c3ViamVjdHM/YWJjZA==
        String basicEncoded = Base64.getEncoder().encodeToString(ordinal.getBytes(UTF_8));
        System.out.println("Using Basic     : " + basicEncoded);

        byte[] decode = Base64.getDecoder().decode(basicEncoded);
        System.out.println("basic decode    : " + new String(decode, UTF_8));
        System.out.println();
        System.out.println("ordinal         : " + ordinal);
        String urlEncoded = Base64.getUrlEncoder().encodeToString(ordinal.getBytes(UTF_8));
        System.out.println("Using URL       : " + urlEncoded);

        byte[] decode1 = Base64.getUrlDecoder().decode(urlEncoded);
        System.out.println("url decode      : " + new String(decode1, UTF_8));
        System.out.println();

        String mimeEncoded = Base64.getMimeEncoder().encodeToString(ordinal.getBytes(UTF_8));
        System.out.println("Using mime       : " + mimeEncoded);
        byte[] decode2 = Base64.getMimeDecoder().decode(mimeEncoded);
        System.out.println("mime decode      : " + new String(decode2, UTF_8));
        System.out.println();

    }

    /**
     * Basic encoding is standard BASE64 encoding, which is used to deal with conventional requirements: the output content does not add line breaks, and the output content is composed of letters and numbers.
     */
    private void basic() throws UnsupportedEncodingException {
        String s = "some string";
        System.out.println("ordinal         : " + s);
        // encoding
        String asB64 = Base64.getEncoder().encodeToString(s.getBytes(UTF_8));
        // The output is: c29tZSBzdHJpbmc=
        System.out.println("Using Basic     : " + asB64);

        // decode
        byte[] asBytes = Base64.getDecoder().decode("c29tZSBzdHJpbmc=");
        // The output is: some string
        System.out.println("basic decode    : " + new String(asBytes, UTF_8));
        System.out.println();
    }
}

run:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.1.3 DES decryption

Add the decryption method based on the example in 2.1.1

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class DesDemo {
    // DES encryption algorithm, the size of the key must be 8 bytes


public static void main(String[] args) throws Exception {
    String input = "Huawei";
    // DES encryption algorithm, the size of the key must be 8 bytes
    String key = "12345678";

    String transformation = "DES"; // 9PQXVUIhaaQ=
    // Specify the algorithm to get the key
    String algorithm = "DES";
    String encryptDES = encryptDES(input, key, transformation, algorithm);
    System.out.println("Encrypt:" + encryptDES);
    String s = decryptDES(encryptDES, key, transformation, algorithm);
    System.out.println("Decrypt:" + s);

}

/**
 * Use DES to encrypt data
 *
 * @param input : original text
 * @param key : key (DES, the length of the key must be 8 bytes)
 * @param transformation : get the algorithm of the Cipher object
 * @param algorithm : The algorithm to get the key
 * @return : ciphertext
 * @throws Exception
 */
private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
    // get encrypted object
    Cipher cipher = Cipher.getInstance(transformation);
    // Create encryption rules
    // The byte of the first parameter key
    // The second parameter indicates the encryption algorithm
    SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
    // ENCRYPT_MODE: encryption mode
    // DECRYPT_MODE: decryption mode
    // Initialize the encryption mode and algorithm
    cipher.init(Cipher.ENCRYPT_MODE,sks);
    // encryption
    byte[] bytes = cipher.doFinal(input.getBytes());
    // output encrypted data
    String encode = new String(Base64.getEncoder().encode(bytes), "UTF-8");

//        System.out.println(encode);
        return encode;
    }


/**
 * Decrypt using DES
 *
 * @param input : ciphertext
 * @param key : key
 * @param transformation : get the algorithm of the Cipher object
 * @param algorithm : The algorithm to get the key
 * @throws Exception
 * @return: original text
 */
private static String decryptDES(String input, String key, String transformation, String algorithm) throws Exception {
    // 1, get the Cipher object
    Cipher cipher = Cipher.getInstance(transformation);
    // Specify key rules
    SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
    cipher.init(Cipher.DECRYPT_MODE, sks);
    // 3. Decryption, the base64 encoding used above, the ciphertext directly below
    byte[] bytes = cipher.doFinal(Base64.getDecoder().decode(input));

// System.out.println("Dissolution" + new String(decode, "UTF-8"));
        // Because it is plain text, so return directly
        return new String(bytes);
    }
}

run:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.1.4 AES encryption and decryption

AES encryption and decryption are the same as DES encryption and decryption codes, only the encryption algorithm needs to be modified, so I won’t elaborate here. It is worth noting that the key for AES encryption needs to be passed in 16 bytes.

2.1.5 Encryption mode

The encryption mode of AES is as follows:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Reference link:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html

Here are mainly two encryption modes: ECB and CBC

ECB

Electronic codebook, electronic codebook. The message to be encrypted is divided into several blocks according to the block size of the block cipher, and each block is independently encrypted

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

  • Pros: Can process data in parallel
  • Disadvantages: The same original text generates the same ciphertext, which cannot protect data well
  • Simultaneous encryption, the original text is the same, and the encrypted cipher text is also the same

CBC

Cipher-block chaining, cipher block chaining. Each plaintext block is XORed with the previous ciphertext block before being encrypted. In this approach, each ciphertext block depends on all preceding plaintext blocks

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

  • Advantages: The ciphertext generated by the same original text is different
  • Cons: Process data serially.

2.1.6 Filling mode

When the data needs to be processed in blocks, and the data length does not meet the block processing requirements, the rules for filling the block length according to a certain method are mainly introduced here:

NoPadding

  • Not filled.
  • Under the DES encryption algorithm, the length of the original text must be an integer multiple of 8 bytes
  • Under the AES encryption algorithm, the length of the original text must be an integer multiple of 16 bytes

PKCS5Padding

  • The size of the data block is 8 bits, make up if it is not enough

Tips

  • By default, the encryption mode and padding mode are: ECB/PKCS5Padding
  • If you use CBC mode, you need to add parameters when initializing the Cipher object, initialization vector IV: IvParameterSpec iv = new IvParameterSpec(key.getBytes());

Encryption mode and padding mode: the numbers in brackets indicate the number of encryption bits, the higher the number, the more secure

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Examples of Encryption Mode and Padding Mode

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 */

package com.huawei.it.jalor.boot.test;

/**
 * Function description: example of encryption mode and padding mode
 *
 * @author cWX970190
 * @since 2020-10-11
 */
import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

public class DesDemo {
    // DES encryption algorithm, the size of the key must be 8 bytes

    public static void main(String[] args) throws Exception {

        String input = "Huawei";

        // DES encryption algorithm, the size of the key must be 8 bytes
        String key = "12345678";

        // Specify the algorithm for obtaining Cipher. If no encryption mode and padding mode are specified, ECB/PKCS5Padding is the default value
        //     String transformation = "DES"; // 9PQXVUIhaaQ=

        //String transformation = "DES/ECB/PKCS5Padding"; // 9PQXVUIhaaQ=

        // In CBC mode, the initial vector must be specified, and the length of the key in the initial vector must be 8 bytes
//        String transformation = "DES/CBC/PKCS5Padding"; // 9PQXVUIhaaQ=

        // NoPadding mode, the length of the original text must be an integer multiple of 8 bytes, so Silicon Valley must be changed to Silicon Valley 12
        String transformation = "DES/CBC/NoPadding"; // 9PQXVUIhaaQ=

        // Specify the algorithm to get the key
        String algorithm = "DES";

        String encryptDES = encryptDES(input, key, transformation, algorithm);

        System.out.println("Encrypt:" + encryptDES);
        String s = dncryptDES(encryptDES, key, transformation, algorithm);
        System.out.println("Decrypt:" + s);

    }

    /**
     * Use DES to encrypt data
     *
     * @param input : original text
     * @param key : key (DES, the length of the key must be 8 bytes)
     * @param transformation : get the algorithm of the Cipher object
     * @param algorithm : The algorithm to get the key
     * @return : ciphertext
     * @throws Exception
     */
    private static String encryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // get encrypted object
        Cipher cipher = Cipher.getInstance(transformation);
        // Create encryption rules
        // The byte of the first parameter key
        // The second parameter indicates the encryption algorithm
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
        // ENCRYPT_MODE: encryption mode
        // DECRYPT_MODE: decryption mode
        // Initial vector, the parameter indicates who to XOR with, the length of the initial vector must be 8 bits
//        IvParameterSpec iv = new IvParameterSpec(key.getBytes());

        // Initialize the encryption mode and algorithm
        cipher.init(Cipher.ENCRYPT_MODE,sks);
        // encryption

        byte[] bytes = cipher.doFinal(input.getBytes());

        // output encrypted data
        String encode = Base64.encode(bytes);

        return encode;
    }

    /**
     * Decrypt using DES
     *
     * @param input : ciphertext
     * @param key : key
     * @param transformation : get the algorithm of the Cipher object
     * @param algorithm : The algorithm to get the key
     * @throws Exception
     * @return: original text
     */
    private static String dncryptDES(String input, String key, String transformation, String algorithm) throws Exception {
        // 1, get the Cipher object
        Cipher cipher = Cipher.getInstance(transformation);
        // Specify key rules
        SecretKeySpec sks = new SecretKeySpec(key.getBytes(), algorithm);
//        IvParameterSpec iv = new IvParameterSpec(key.getBytes());
        cipher.init(Cipher.DECRYPT_MODE, sks);
        // 3. Decrypt
        byte[] bytes = cipher.doFinal(Base64.decode(input));

        return new String(bytes);
    }
}

run:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

In non-filling mode, the original text must be 8 bytes, modify the encryption mode to:

 String transformation = "DES/CBC/PKCS5Padding";

run again:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

It is found that there is no problem with encryption, but a parameter needs to be added when decrypting, add parameters and modify the initialization rules:

// Initial vector, the parameter indicates who to XOR with, the length of the initial vector must be 8 bits
        IvParameterSpec iv = new IvParameterSpec(key.getBytes());

        // Initialize the encryption mode and algorithm
        cipher.init(Cipher.ENCRYPT_MODE,sks,iv);

run again:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

When testing AES, it should be noted that the key needs 16 bytes, and the encryption vector also needs 16 bytes. The other methods are the same as DES.

2.2 Message digest (one-way hash) function

Message Digest (Message Digest) is also known as Digital Digest (Digital Digest)

It is a fixed-length value that uniquely corresponds to a message or text, and it is generated by a one-way Hash encryption function on the message

The value generated using the digital digest cannot be tampered with, in order to ensure the security of the file or value

2.2.1 Features

No matter how long the input message is, the length of the calculated message digest is always fixed. For example, the message digested by the MD5 algorithm has 128 bits, and the message digested by the SHA-1 algorithm finally has a 160-bit output.

As long as the input message is different, the summary message produced after digesting it must be different; but the same input must produce the same output

Message digests are one-way, irreversible

Common algorithms:

  • MD5
  • SHA1
  • SHA256
  • SHA512

Search for tomcat in the browser, enter the official website to download, you will often find sha1, sha512, these are digital summaries

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.2.2 Get String Message Digest

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

run:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Using online md5 encryption, we found that the value generated by us is different from the value generated by the code. That is because the message digest is not encoded with base64, so we need to convert the value into hexadecimal.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Digest of numbers converted to hexadecimal

package com.huawei.it.jalor.boot.test;

/**
 * Function description
 *
 * @author cWX970190
 * @since 2020-10-11
 */

import com.sun.org.apache.xml.internal.security.utils.Base64;

import java.security.MessageDigest;

public class DigestDemo1 {

    public static void main(String[] args) throws Exception{
        // original text
        String input = "aa";
        // algorithm
        String algorithm = "MD5";
        // get the number summary object
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        // Get a byte array of the numeric digest of the message
        byte[] digest = messageDigest.digest(input.getBytes("UTF-8"));
        //        System.out.println(new String(digest));
        // base64 encoding
//        System.out.println(Base64.encode(digest));
        // create object for splicing
        StringBuilder sb = new StringBuilder();

        for (byte b : digest) {
            // Convert to hexadecimal
            String s = Integer.toHexString(b & 0xff);
            //System.out.println(s);
            if (s.length() == 1){
                // If there is only one character generated, add 0 in front
                s = "0"+s;
            }
            sb.append(s);
        }
        System.out.println(sb.toString());

    }
}

Running, the result is consistent with online:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.2.3 Other message digest algorithms

/**
 * Function description
 *
 * @author cWX970190
 * @since 2020-10-11
 */
import java.security.MessageDigest;

/**
 * DigestDemo1
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-03-17
 * @Description:
 */
public class DigestDemo1 {

    public static void main(String[] args) throws Exception{
        // 4124bc0a9335c27f086f24ba207a4912 md5 online verification
        // QSS8CpM1wn8IbyS6IHpJEg== The message digest uses hexadecimal
        // original text
        String input = "aa";
        // algorithm
        String algorithm = "MD5";
        // get the number summary object
        String md5 = getDigest(input, "MD5");
        System.out.println(md5);

        String sha1 = getDigest(input, "SHA-1");
        System.out.println(sha1);

        String sha256 = getDigest(input, "SHA-256");
        System.out.println(sha256);

        String sha512 = getDigest(input, "SHA-512");
        System.out.println(sha512);


    }

    private static String toHex(byte[] digest) throws Exception {

//        System.out.println(new String(digest));
        // base64 encoding
//        System.out.println(Base64.encode(digest));
        // create object for splicing
        StringBuilder sb = new StringBuilder();

        for (byte b : digest) {
            // Convert to hexadecimal
            String s = Integer.toHexString(b & 0xff);
            if (s.length() == 1){
                // If there is only one character generated, add 0 in front
                s = "0"+s;
            }
            sb.append(s);
        }
        System.out.println("The length of the hexadecimal data: " + sb.toString().getBytes().length);
        return sb.toString();
    }

    private static String getDigest(String input, String algorithm) throws Exception {
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        // Digest of message numbers
        byte[] digest = messageDigest.digest(input.getBytes());
        System.out.println("The byte length of the ciphertext:" + digest.length);

        return toHex(digest);
    }
}

run:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.2.4 Get file message digest

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.security.MessageDigest;

/**
 * DigestDemo
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-11
 * @Description:
 */
public class DigestDemo {

    public static void main(String[] args) throws Exception{
        String input = "aa";
        String algorithm = "MD5";

        // sha1 can realize the instant transmission function

        String sha1 = getDigestFile("C:Userscwx970190Documentsapache-tomcat-9.0.38.zip", "SHA-1");
        System.out.println(sha1);

        String sha512 = getDigestFile("C:Userscwx970190Documentsapache-tomcat-9.0.38.zip", "SHA-512");
        System.out.println(sha512);

//        String md5 = getDigest("aa", "MD5");
//        System.out.println(md5);
//
//        String md51 = getDigest("aa ", "MD5");
//        System.out.println(md51);
    }

    private static String getDigestFile(String filePath, String algorithm) throws Exception{
        FileInputStream fis = new FileInputStream(filePath);
        int len;
        byte[] buffer = new byte[1024];
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        while ( (len =  fis.read(buffer))!=-1){
            baos.write(buffer,0,len);
        }
        // Get the message summary object
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        // get message digest
        byte[] digest = messageDigest.digest(baos.toByteArray());
        System.out.println("The byte length of the ciphertext: "+digest.length);
        return toHex(digest);
    }

    private static String getDigest(String input, String algorithm) throws Exception{
        MessageDigest messageDigest = MessageDigest.getInstance(algorithm);
        byte[] digest = messageDigest.digest(input.getBytes());
        System.out.println("The byte length of the ciphertext: "+digest.length);
        return toHex(digest);
    }

    private static String toHex(byte[] digest) {
        //        System.out.println(new String(digest));
        // When the message digest is expressed, it is expressed in hexadecimal
        StringBuilder sb = new StringBuilder();
        for (byte b : digest) {
            // Convert to hexadecimal

            String s = Integer.toHexString(b & 0xff);
            // Keep the integrity of the data, if the front part is not enough, fill it with 0
            if (s.length()==1){
                s="0"+s;
            }
            sb.append(s);
        }
        System.out.println("The length of the hexadecimal data: "+ sb.toString().getBytes().length);
        return sb.toString();
    }
}

operation result:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Check the sha512 encryption results on the official website and find that they are consistent:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Using the sha-1 algorithm, the instant transmission function can be realized. As long as the same file is encrypted, no matter how the name of the file is modified, the final value is the same. You can test it yourself.

However, if the original text is different, for example, there are two more spaces in the original text above the picture below:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

After running:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Summarize

  • MD5 algorithm: 16 bytes for the summary result, 32 bytes after converting to hexadecimal
  • SHA1 algorithm: 20 bytes for the summary result, 40 bytes after converting to hexadecimal
  • SHA256 algorithm: 32 bytes for the summary result, 64 bytes after converting to hexadecimal
  • SHA512 algorithm: 64 bytes for the summary result, 128 bytes after converting to hexadecimal

2.3 Asymmetric encryption

Introduction:

① Asymmetric encryption algorithm is also called modern encryption algorithm.

② Asymmetric encryption is the cornerstone of computer communication security, which ensures that encrypted data will not be cracked.

③ Different from symmetric encryption algorithm, asymmetric encryption algorithm requires two keys: public key (publickey) and private key (privatekey)

④ Public key and private key are a pair

⑤ If the data is encrypted with the public key, it can only be decrypted with the corresponding private key.

⑥ If the data is encrypted with a private key, it can only be decrypted with the corresponding public key.

⑦ Because encryption and decryption use two different keys, this algorithm is called an asymmetric encryption algorithm.

example

First generate a key pair, the public key is (5,14), the private key is (11,14)

Now A wants to send the original text 2 to B

A uses the public key to encrypt data. 2 to the 5th power mod 14 = 4 , send the ciphertext 4 to B

B uses the private key to decrypt the data. 4 to the 11th power mod14 = 2, get the original text 2

features

  • Encryption and decryption use different keys
  • If encrypted with the private key, it can only be decrypted with the public key
  • If encrypted with the public key, it can only be decrypted with the private key
  • Processing data is slower because of high security level

common algorithm

RSA

ECC

2.3.1 Generate public and private keys

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
/**
 * RSAdemo
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class RSAdemo {
    public static void main(String[] args) throws Exception {
 
        // Encryption Algorithm
        String algorithm = "RSA";
        // create key pair generator object
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // generate key pair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // generate private key
        PrivateKey privateKey = keyPair.getPrivate();
        // generate public key
        PublicKey publicKey = keyPair.getPublic();
        // Get private key byte array
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // Get public key byte array
        byte[] publicKeyEncoded = publicKey.getEncoded();
        // Base64 encode the public and private keys
        String privateKeyString = Base64.encode(privateKeyEncoded);
        String publicKeyString = Base64.encode(publicKeyEncoded);
        // print private key
        System.out.println(privateKeyString);
        // print public key
        System.out.println(publicKeyString);
    }
}

Run the program, first print the private key, and then print the public key:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.3.2 Private key encryption

import com.sun.org.apache.xml.internal.security.utils.Base64;

import javax.crypto.Cipher;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
 * RSAdemo
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class RSAdemo {
    public static void main(String[] args) throws Exception {
        String input = "Huawei";
        // Encryption Algorithm
        String algorithm = "RSA";
        // create key pair generator object
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // generate key pair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // generate private key
        PrivateKey privateKey = keyPair.getPrivate();
        // generate public key
        PublicKey publicKey = keyPair.getPublic();
        // Get private key byte array
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // Get public key byte array
        byte[] publicKeyEncoded = publicKey.getEncoded();
        // Base64 encode the public and private keys
        String privateKeyString = Base64.encode(privateKeyEncoded);
        String publicKeyString = Base64.encode(publicKeyEncoded);


        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // Initialize encryption
        // The first parameter: the encrypted mode
        // The second parameter: use the private key to encrypt
        cipher.init(Cipher.ENCRYPT_MODE,privateKey);
        // private key encryption
        byte[] bytes = cipher.doFinal(input.getBytes());
        System.out.println(Base64.encode(bytes));

    }
}

Run the program:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.3.3 Private key encryption and private key decryption

public class RSAdemo {
    public static void main(String[] args) throws Exception {
        String input = "Huawei";
        // Encryption Algorithm
        String algorithm = "RSA";
        // create key pair generator object
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // generate key pair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // generate private key
        PrivateKey privateKey = keyPair.getPrivate();
        // generate public key
        PublicKey publicKey = keyPair.getPublic();
        // Get private key byte array
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // Get public key byte array
        byte[] publicKeyEncoded = publicKey.getEncoded();
        // Base64 encode the public and private keys
        String privateKeyString = Base64.encode(privateKeyEncoded);
        String publicKeyString = Base64.encode(publicKeyEncoded);
        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // Initialize encryption
        // The first parameter: the encrypted mode
        // The second parameter: use the private key to encrypt
        cipher.init(Cipher.ENCRYPT_MODE,privateKey);
        // private key encryption
        byte[] bytes = cipher.doFinal(input.getBytes());
        System.out.println(Base64.encode(bytes));
        // private key to decrypt
        cipher.init(Cipher.DECRYPT_MODE,privateKey);
        // To decrypt the ciphertext, there is no need to use base64, because the original text will not be garbled
        byte[] bytes1 = cipher.doFinal(bytes);
        System.out.println(new String(bytes1));

    }
}

The running result is error, because the private key is encrypted and can only be decrypted by the public key:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.3.4 Private key encryption and public key decryption

Modify the code in 2.3.3

// public key to decrypt
cipher.init(Cipher.DECRYPT_MODE,publicKey);

run again

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.3.5 Public key encryption and public key decryption

same error

2.3.6 Save public and private keys

In some cases, it is necessary to put all the encryption and decryption methods under the local root directory:

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 */

package com.huawei.it.jalor.boot.test;

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
/**
 * RSAdemo
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class RSAdemo {
    public static void main(String[] args) throws Exception {
        String input = "Silicon Valley";
        // Encryption Algorithm
        String algorithm = "RSA";

        // Generate a key pair and save it in a local file
        generateKeyToFile(algorithm, "a.pub", "a.pri");

        //encryption
//        String s = encryptRSA(algorithm, privateKey, input);
        // decrypt
//        String s1 = decryptRSA(algorithm, publicKey, s);
//        System.out.println(s1);


    }

    /**
     * Generate a key pair and save it in a local file
     *
     * @param algorithm : algorithm
     * @param pubPath : public key storage path
     * @param priPath : private key storage path
     * @throws Exception
     */
    private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
        // get the key pair generator
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // get the key pair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // get the public key
        PublicKey publicKey = keyPair.getPublic();
        // get the private key
        PrivateKey privateKey = keyPair.getPrivate();
        // get byte array
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // Perform Base64 encoding
        String publicKeyString = Base64.encode(publicKeyEncoded);
        String privateKeyString = Base64.encode(privateKeyEncoded);
        // save document
        FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));

    }

    /**
     * Decrypt data
     *
     * @param algorithm : algorithm
     * @param encrypted : ciphertext
     * @param key : key
     * @return : original text
     * @throws Exception
     */
    public static String decryptRSA(String algorithm,Key key,String encrypted) throws Exception{
        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // private key to decrypt
        cipher.init(Cipher.DECRYPT_MODE,key);
        // Since the ciphertext is Base64 encoded, it needs to be decoded here
        byte[] decode = Base64.decode(encrypted);
        // To decrypt the ciphertext, there is no need to use base64, because the original text will not be garbled
        byte[] bytes1 = cipher.doFinal(decode);
        System.out.println(new String(bytes1));
        return new String(bytes1);

    }
    /**
     * Encrypt data using key
     *
     * @param algorithm : algorithm
     * @param input : original text
     * @param key : key
     * @return : ciphertext
     * @throws Exception
     */
    public static String encryptRSA(String algorithm,Key key,String input) throws Exception{
        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // Initialize encryption
        // The first parameter: the encrypted mode
        // The second parameter: use the private key to encrypt
        cipher.init(Cipher.ENCRYPT_MODE,key);
        // private key encryption
        byte[] bytes = cipher.doFinal(input.getBytes());
        // Base64 encode the ciphertext
        System.out.println(Base64.encode(bytes));
        return Base64.encode(bytes);
    }
}

After running the program, there are two more files locally, open:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.3.7 Read private key

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
/**
 * RSAdemo
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class RSAdemo {
    public static void main(String[] args) throws Exception {
        String input = "Silicon Valley";
        // Encryption Algorithm
        String algorithm = "RSA";
        PrivateKey privateKey = getPrivateKey("a.pri", algorithm);



    }

    public static PrivateKey getPrivateKey(String priPath,String algorithm) throws Exception{
        // convert file content to string
        String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
        // get the key factory
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // Construct the key specification for Base64 decoding
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
        // generate private key
        return keyFactory.generatePrivate(spec);
    }

    /**
     * Generate a key pair and save it in a local file
     *
     * @param algorithm : algorithm
     * @param pubPath : public key storage path
     * @param priPath : private key storage path
     * @throws Exception
     */
    private static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
        // get the key pair generator
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // get the key pair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // get the public key
        PublicKey publicKey = keyPair.getPublic();
        // get the private key
        PrivateKey privateKey = keyPair.getPrivate();
        // get byte array
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // Perform Base64 encoding
        String publicKeyString = Base64.encode(publicKeyEncoded);
        String privateKeyString = Base64.encode(privateKeyEncoded);
        // save document
        FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));

    }

    /**
     * Decrypt data
     *
     * @param algorithm : algorithm
     * @param encrypted : ciphertext
     * @param key : key
     * @return : original text
     * @throws Exception
     */
    public static String decryptRSA(String algorithm,Key key,String encrypted) throws Exception{
         // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // private key to decrypt
        cipher.init(Cipher.DECRYPT_MODE,key);
        // Since the ciphertext is Base64 encoded, it needs to be decoded here
        byte[] decode = Base64.decode(encrypted);
        // To decrypt the ciphertext, there is no need to use base64, because the original text will not be garbled
        byte[] bytes1 = cipher.doFinal(decode);
        System.out.println(new String(bytes1));
        return new String(bytes1);

    }
    /**
     * Encrypt data using key
     *
     * @param algorithm : algorithm
     * @param input : original text
     * @param key : key
     * @return : ciphertext
     * @throws Exception
     */
    public static String encryptRSA(String algorithm,Key key,String input) throws Exception{
        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // Initialize encryption
        // The first parameter: the encrypted mode
        // The second parameter: use the private key to encrypt
        cipher.init(Cipher.ENCRYPT_MODE,key);
        // private key encryption
        byte[] bytes = cipher.doFinal(input.getBytes());
        // Base64 encode the ciphertext
        System.out.println(Base64.encode(bytes));
        return Base64.encode(bytes);
    }
}

2.3.8 Read public key

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.Charset;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

/**
 * RSAdemo
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class RSAdemo {
    public static void main(String[] args) throws Exception {
        String input = "Silicon Valley";
        // Encryption Algorithm
        String algorithm = "RSA";
        PrivateKey privateKey = getPrivateKey("a.pri", algorithm);
        PublicKey publicKey = getPublicKey("a.pub", algorithm);

        String s = encryptRSA(algorithm, privateKey, input);
        String s1 = decryptRSA(algorithm, publicKey, s);
        System.out.println(s);
        System.out.println(s1);


    }

    public static PublicKey getPublicKey(String pulickPath,String algorithm) throws Exception{
        // convert file content to string
        String publicKeyString = FileUtils.readFileToString(new File(pulickPath), Charset.defaultCharset());
        // get the key factory
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // Construct the key specification for Base64 decoding
        X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
        // generate public key
        return keyFactory.generatePublic(spec);
    }

    public static PrivateKey getPrivateKey(String priPath,String algorithm) throws Exception{
        // convert file content to string
        String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
        // get the key factory
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // Construct the key specification for Base64 decoding
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
        // generate private key
        return keyFactory.generatePrivate(spec);
    }

    /**
     * Generate a key pair and save it in a local file
     *
     * @param algorithm : algorithm
     * @param pubPath : public key storage path
     * @param priPath : private key storage path
     * @throws Exception
     */
    public static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
        // get the key pair generator
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // get the key pair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // get the public key
        PublicKey publicKey = keyPair.getPublic();
        // get the private key
        PrivateKey privateKey = keyPair.getPrivate();
        // get byte array
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // Perform Base64 encoding
        String publicKeyString = Base64.encode(publicKeyEncoded);
        String privateKeyString = Base64.encode(privateKeyEncoded);
        // save document
        FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));

    }

    /**
     * Decrypt data
     *
     * @param algorithm : algorithm
     * @param encrypted : ciphertext
     * @param key : key
     * @return : original text
     * @throws Exception
     */
    public static String decryptRSA(String algorithm,Key key,String encrypted) throws Exception{
         // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // private key to decrypt
        cipher.init(Cipher.DECRYPT_MODE,key);
        // Since the ciphertext is Base64 encoded, it needs to be decoded here
        byte[] decode = Base64.decode(encrypted);
        // To decrypt the ciphertext, there is no need to use base64, because the original text will not be garbled
        byte[] bytes1 = cipher.doFinal(decode);
        return new String(bytes1);

    }
    /**
     * Encrypt data using key
     *
     * @param algorithm : algorithm
     * @param input : original text
     * @param key : key
     * @return : ciphertext
     * @throws Exception
     */
    public static String encryptRSA(String algorithm,Key key,String input) throws Exception{
        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // Initialize encryption
        // The first parameter: the encrypted mode
        // The second parameter: use the private key to encrypt
        cipher.init(Cipher.ENCRYPT_MODE,key);
        // private key encryption
        byte[] bytes = cipher.doFinal(input.getBytes());
        // Base64 encode the ciphertext
        return Base64.encode(bytes);
    }
}

run the program

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.4 Digital signature

We often use digital signatures, but people usually don’t pay much attention to them. For example, when we visit banks, securities companies, fund companies, and financial company websites, all of them use https protocol. If it is https protocol, a certificate is required. The signature can be used to verify whether the data has been tampered with when the network transmits the data.

Simply put, the function of a signature is to prove that the content on a certain document is indeed written by me. Others cannot pretend to be my signature (non-forgeable), and I cannot deny that the above signature is mine (non-repudiation).

We know that the reason why handwritten signatures cannot be forged is because each person’s handwriting is unique, even if it is imitated, it can be distinguished through expert identification. It cannot be denied, because everyone’s handwriting has fixed characteristics, and these characteristics are difficult to get rid of.

It is these two characteristics that make handwritten signatures widely recognized in daily life, such as signing contracts, IOUs, and so on.

The requirement of a digital signature is that only I can sign my name, and others can verify my signature, but they cannot forge my signature.

2.4.1 Web page encryption

Let’s look at an example of applying “digital certificates”: the https protocol. This protocol is mainly used for web encryption

First, the client makes an encrypted request to the server.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

After the server encrypts the webpage with its own private key, it sends it to the client together with its own digital certificate.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

The “Certificate Manager” of the client (browser) has a list of “Trusted Root Certification Authorities”. The client will check whether the public key to unlock the digital certificate is in the list according to this list.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

If the URL recorded in the digital certificate is inconsistent with the URL you are browsing, it means that this certificate may be used fraudulently, and the browser will issue a warning.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

If the digital certificate is not issued by a trusted authority, the browser will issue another warning.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

If the digital certificate is authentic, the client can use the server’s public key in the certificate to encrypt information and then exchange encrypted information with the server.

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.4.2 Where does the certificate come from

“Certificate authority” (CA for short) is used for public key certification. The certificate center uses its own private key to encrypt the public key and some related information to generate a “digital certificate”.

After getting the digital certificate, you can rest assured. In the future, you only need to attach a digital certificate at the same time as signing.

Use the CA’s public key to unlock the digital certificate, you can get the real public key, and then you can prove whether the “digital signature” is really signed by the company.

Modify the previous RSAdemo code:

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 */

package com.huawei.it.jalor.boot.test;

import com.sun.org.apache.xml.internal.security.utils.Base64;
import org.apache.commons.io.FileUtils;

import javax.crypto.Cipher;
import java.io.File;
import java.nio.charset.Charset;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;


/**
 * RSAdemo
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class RSAdemo {
    public static void main(String[] args) throws Exception {
        String input = "Silicon Valley";
        // Encryption Algorithm
        String algorithm = "RSA";
        PrivateKey privateKey = getPrivateKey("a.pri", algorithm);
        PublicKey publicKey = getPublicKey("a.pub", algorithm);
        String s = encryptRSA(algorithm, privateKey, input);
        String s1 = decryptRSA(algorithm, publicKey, s);
        System.out.println(s);
        System.out.println(s1);


    }

    public static PublicKey getPublicKey(String pulickPath,String algorithm) throws Exception{
        // convert file content to string
        String publicKeyString = FileUtils.readFileToString(new File(pulickPath), Charset.defaultCharset());
        // get the key factory
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // Construct the key specification for Base64 decoding
        X509EncodedKeySpec spec = new X509EncodedKeySpec(Base64.decode(publicKeyString));
        // generate public key
        return keyFactory.generatePublic(spec);
    }

    public static PrivateKey getPrivateKey(String priPath,String algorithm) throws Exception{
        // convert file content to string
        String privateKeyString = FileUtils.readFileToString(new File(priPath), Charset.defaultCharset());
        // get the key factory
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // Construct the key specification for Base64 decoding
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(Base64.decode(privateKeyString));
        // generate private key
        return keyFactory.generatePrivate(spec);
    }

    /**
     * Generate a key pair and save it in a local file
     *
     * @param algorithm : algorithm
     * @param pubPath : public key storage path
     * @param priPath : private key storage path
     * @throws Exception
     */
    public static void generateKeyToFile(String algorithm, String pubPath, String priPath) throws Exception {
        // get the key pair generator
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(algorithm);
        // get the key pair
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // get the public key
        PublicKey publicKey = keyPair.getPublic();
        // get the private key
        PrivateKey privateKey = keyPair.getPrivate();
        // get byte array
        byte[] publicKeyEncoded = publicKey.getEncoded();
        byte[] privateKeyEncoded = privateKey.getEncoded();
        // Perform Base64 encoding
        String publicKeyString = Base64.encode(publicKeyEncoded);
        String privateKeyString = Base64.encode(privateKeyEncoded);
        // save document
        FileUtils.writeStringToFile(new File(pubPath), publicKeyString, Charset.forName("UTF-8"));
        FileUtils.writeStringToFile(new File(priPath), privateKeyString, Charset.forName("UTF-8"));

    }

    /**
     * Decrypt data
     *
     * @param algorithm : algorithm
     * @param encrypted : ciphertext
     * @param key : key
     * @return : original text
     * @throws Exception
     */
    public static String decryptRSA(String algorithm,Key key,String encrypted) throws Exception{
        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // private key to decrypt
        cipher.init(Cipher.DECRYPT_MODE,key);
        // Since the ciphertext is Base64 encoded, it needs to be decoded here
        byte[] decode = Base64.decode(encrypted);
        // To decrypt the ciphertext, there is no need to use base64, because the original text will not be garbled
        byte[] bytes1 = cipher.doFinal(decode);
        return new String(bytes1);

    }
    /**
     * Encrypt data using key
     *
     * @param algorithm : algorithm
     * @param input : original text
     * @param key : key
     * @return : ciphertext
     * @throws Exception
     */
    public static String encryptRSA(String algorithm,Key key,String input) throws Exception{
        // create encrypted object
        // The parameter indicates the encryption algorithm
        Cipher cipher = Cipher.getInstance(algorithm);
        // Initialize encryption
        // The first parameter: the encrypted mode
        // The second parameter: use the private key to encrypt
        cipher.init(Cipher.ENCRYPT_MODE,key);
        // private key encryption
        byte[] bytes = cipher.doFinal(input.getBytes());
        // Base64 encode the ciphertext
        return Base64.encode(bytes);
    }

    /**
     * load public key from file
     *
     * @param algorithm : algorithm
     * @param filePath : file path
     * @return : public key
     * @throws Exception
     */
    public static PublicKey loadPublicKeyFromFile(String algorithm, String filePath) throws Exception {
        // convert file content to string
        String keyString = FileUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));

        return loadPublicKeyFromString(algorithm, keyString);

    }

    /**
     * Load public key from string
     *
     * @param algorithm : algorithm
     * @param keyString : public key string
     * @return : public key
     * @throws Exception
     */
    public static PublicKey loadPublicKeyFromString(String algorithm, String keyString) throws Exception {
        // Perform Base64 decoding
        byte[] decode = Base64.decode(keyString);
        // get the key factory
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // build key specification
        X509EncodedKeySpec keyspec = new X509EncodedKeySpec(decode);
        // get the public key
        return keyFactory.generatePublic(keyspec);

    }


    /**
     * load private key from file
     *
     * @param algorithm : algorithm
     * @param filePath : file path
     * @return : private key
     * @throws Exception
     */
    public static PrivateKey loadPrivateKeyFromFile(String algorithm, String filePath) throws Exception {
        // convert file content to string
        String keyString = FileUtils.readFileToString(new File(filePath), Charset.forName("UTF-8"));
        return loadPrivateKeyFromString(algorithm, keyString);

    }

    /**
     * load private key from string
     *
     * @param algorithm : algorithm
     * @param keyString : private key string
     * @return : private key
     * @throws Exception
     */
    public static PrivateKey loadPrivateKeyFromString(String algorithm, String keyString) throws Exception {
        // Perform Base64 decoding
        byte[] decode = Base64.decode(keyString);
        // get the key factory
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        // build key specification
        PKCS8EncodedKeySpec keyspec = new PKCS8EncodedKeySpec(decode);
        // generate private key
        return keyFactory.generatePrivate(keyspec);

    }
}

Write a class that verifies digital signatures:

/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved.
 */

package com.huawei.it.jalor.boot.test;

import com.sun.org.apache.xml.internal.security.utils.Base64;

import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;

/**
 * Function description: Verify digital signature
 *
 * @author cWX970190
 * @since 2020-10-11
 */
public class SignatureDemo {
    public static void main(String[] args) throws Exception {
        String a = "123";
        PublicKey publicKey =RSAdemo.loadPublicKeyFromFile("RSA", "a.pub");
        PrivateKey privateKey = RSAdemo.loadPrivateKeyFromFile("RSA", "a.pri");
        String signaturedData = getSignature(a, "sha256withrsa", privateKey);
        boolean b = verifySignature(a, "sha256withrsa", publicKey, signaturedData);
        System.out.println(b);
    }

    /**
     * generate signature
     *
     * @param input : original text
     * @param algorithm : algorithm
     * @param privateKey : private key
     * @return : signature
     * @throws Exception
     */
    private static String getSignature(String input, String algorithm, PrivateKey privateKey) throws Exception {
        // get signature object
        Signature signature = Signature.getInstance(algorithm);
        // Initialize the signature
        signature.initSign(privateKey);
        // Pass in the original text
        signature.update(input.getBytes());
        // start signing
        byte[] sign = signature.sign();
        // Base64 encode the signed data
        return Base64.encode(sign);
    }

    /**
     * Verify signature
     *
     * @param input : original text
     * @param algorithm : algorithm
     * @param publicKey : public key
     * @param signedData : signature
     * @return : Whether the data has been tampered with
     * @throws Exception
     */
    private static boolean verifySignature(String input, String algorithm, PublicKey publicKey, String signaturedData) throws Exception {
        // get signature object
        Signature signature = Signature.getInstance(algorithm);
        // Initialize the signature
        signature.initVerify(publicKey);
        // Pass in the original text
        signature.update(input.getBytes());
        // verify data
        return signature.verify(Base64.decode(signaturedData));

    }
}

Run, verify successfully:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Expansion: 2.5 Byte and bit

Byte :Byte. The basic unit of data storage, such as a mobile hard disk 1T, the unit is byte

bit :Bit, also called bit. A bit is either 0 or 1. The unit of data transmission. For example, the broadband at home is 100MB, and the download speed does not reach 100MB. Generally, it is 12-13MB, so it is because 100 / 8

relation: 1Byte = 8bit

2.5.1 Get the string byte

/**
 * ByteBit
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class ByteBit {
    public static void main(String[] args) {
        String a = "a";
        byte[] bytes = a.getBytes();
        for (byte b : bytes) {
            int c=b;
            // Print and find that the byte is actually the ascii code
            System.out.println(c);
        }
    }
}

operation result:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

Consistent with the ascii code table

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.5.2 byte corresponds to bit

public class ByteBit {
    public static void main(String[] args) {
        String a = "a";
        byte[] bytes = a.getBytes();
        for (byte b : bytes) {
            int c=b;
            // Print and find that the byte is actually the ascii code
            System.out.println(c);
            // Let's take a look at the bit corresponding to each byte, and the byte gets the corresponding bit
            String s = Integer.toBinaryString(c);
            System.out.println(s);
        }
    }
}

operation result

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.5.3 Chinese corresponding bytes

package com.huawei.it.jalor.boot.test;

/**
 * Function description
 *
 * @author cWX970190
 * @since 2020-10-11
 */
public class ByteBitDemo {
    public static void main(String[] args) throws Exception{

        String a = "Hua";
        byte[] bytes = a.getBytes();
        for (byte b : bytes) {
            System.out.print(b + "   ");
            String s = Integer.toBinaryString(b);
            System.out.println(s);
        }
    }


}

Running the program, we found that a Chinese is composed of 3 bytes:

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

We modify the encoding format and change the encoding format to GBK

modify the code

// UTF-8: encoding format occupies 3 bytes
        byte[] bytes = a.getBytes("GBK");

Run it again and find that it becomes 2 bytes

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

2.5.4 The bytes corresponding to English

/**
 * ByteBit
 *
 * @Author: Chen Zhiqiang
 * @CreateTime: 2020-10-12
 * @Description:
 */
public class ByteBit {
    public static void main(String[] args) throws Exception{

        String a = "a";
        byte[] bytes = a.getBytes();
        // In the case of Chinese, different encoding formats correspond to different bytes
//        byte[] bytes = a.getBytes("GBK");
        for (byte b : bytes) {
            System.out.print(b + "   ");
            String s = Integer.toBinaryString(b);
            System.out.println(s);
        }
    }
}

run the program

[Everyone understands cryptography] An easy-to-understand Java cryptography introductory tutorial

3. How to set a password to be safe

Through the above-mentioned introduction to the development history of cryptography and the explanation of common encryption algorithms, I believe that everyone should have a more rational understanding of passwords. Then, how to set a password to be safe? Here is a little suggestion:

  • The password should not be too common, and do not use common passwords similar to 123456.
  • Different application passwords are recommended to avoid one application database being removed from the database and all application passwords collapsing.
  • You can add methods such as registration time, registration location, and application features when setting a password. For example, tianjin123456 means the application registered in Tianjin

references:

Symmetric encryption of modern cryptography – DES and AES algorithms – element ui

http://element-ui.cn/article/show-97007.aspx

Java Base64 encoding and decoding—-code examples of three implementation methods

https://blog.csdn.net/qq_27093465/article/details/93977519

Cryptography for Network Security: Information Security

https://www.bilibili.com/video/av583369085/

Well, the sharing of this issue is here to say goodbye to everyone. Cryptography is profound and profound. This article is just a taste. The knowledge about cryptography is always being updated. I hope that next time I can bring you more cutting-edge and more practical cryptography-related Knowledge, favorite veterans welcome to pay attention to like, refill! ! !

Click to follow and learn about Huawei Cloud’s fresh technologies for the first time~