Application and implementation of Java encryption algorithm (MD5, SHA, DES, 3DES, AES, RSA, ECC)

1. Hash encryption algorithm

1 Overview

Strictly speaking, this is not an encryption, but should be called 信息摘要算法. The algorithm uses a hash function to compress the message or data into a summary, so that the amount of data becomes smaller and the format of the data is fixed. Shuffle the mix by data and recreate a called 散列值.

2. Common algorithms (MD5, SHA)

MD5、SHA(128、256)series

name safety speed
SHA-1 high slow
MD5 middle quick

3. Application

Commonly used for password storage, or file fingerprint verification.

After the website user registers, the value of the password is encrypted by MD5 and stored in the DB. When logging in again, the password entered by the user is encrypted in the same way, and compared with the ciphertext in the database. In this way, even if the database is cracked, or developers can see it, based on the irreversibility of MD5, they still don't know what the password is.

The second is the file verification scenario. For example, for files downloaded from a website (especially large files, such as system image iso), the official website will place a signature (maybe MD5, or SHA). When the user gets the file, the hash algorithm can be executed locally and the official website signature Whether the comparison is consistent to determine whether the file has been tampered with. Such as the image of ubuntu20.04:
insert image description here

4. Java implementation

Citation package:

<dependency>
  <groupId>commons-codec</groupId>
  <artifactId>commons-codec</artifactId>
  <version>1.14</version>
</dependency>
import org.apache.commons.codec.digest.DigestUtils;
import java.math.BigInteger;
import java.security.MessageDigest;

public class Hash {
    
    

    /**
     * jdk的security实现md5
     * 也可以借助commons-codec包
     */
    public static String md5(String src) {
    
    
        byte[] pwd = null;
        try {
    
    
            pwd = MessageDigest.getInstance("md5").digest(src.getBytes("utf-8"));
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
        String code = new BigInteger(1, pwd).toString(16);
        for (int i = 0; i < 32 - code.length(); i++) {
    
    
            code = "0" + code;
        }
        return code;
    }
    public static String commonsMd5(String src){
    
    
        return DigestUtils.md5Hex(src);
    }

    /**
     * jdk实现sha算法
     * 也可以借助commons-codec包
     */
    public static String sha(String src) throws Exception {
    
    
        MessageDigest sha = MessageDigest.getInstance("sha");
        byte[] shaByte = sha.digest(src.getBytes("utf-8"));
        StringBuffer code = new StringBuffer();
        for (int i = 0; i < shaByte.length; i++) {
    
    
            int val = ((int) shaByte[i]) & 0xff;
            if (val < 16) {
    
    
                code.append("0");
            }
            code.append(Integer.toHexString(val));
        }
        return code.toString();
    }
    public static String commonsSha(String src) throws Exception {
    
    
        return DigestUtils.sha1Hex(src);
    }


    public static void main(String[] args) throws Exception {
    
    
        String name = "你好世界,helloworld";
        System.out.println(name);
        System.out.println(md5(name));
        System.out.println(commonsMd5(name));
        System.out.println(sha(name));
        System.out.println(commonsSha(name));
    }
}

Both jdk and commons generate the same hash value.
Run it multiple times, but still generate a fixed value
commons-codec There are many available methods, such as: sha256, sha512...

public class HexUtil {
    
    
    
    /**
     * 将普通字符串用16进制描述
     * 如"WAZX-B55SY6-S6DT5" 描述为:"57415a582d4235355359362d5336445435"
     * */
    public static String strToHex(String str){
    
    
         byte[] bytes = str.getBytes(); 
         return bytesToHex(bytes);
    }
    
    /**将16进制描述的字符串还原为普通字符串
     * 如"57415a582d4235355359362d5336445435" 还原为:"WAZX-B55SY6-S6DT5"
     * */
    public static String hexToStr(String hex){
    
    
        byte[] bytes=hexToBytes(hex);
        return new String(bytes);
    }
    
    
    /**16进制转byte[]*/
    public static byte[] hexToBytes(String hex){
    
    
        int length = hex.length() / 2;
        byte[] bytes=new byte[length];
        for(int i=0;i<length;i++){
    
    
            String tempStr=hex.substring(2*i, 2*i+2);//byte:8bit=4bit+4bit=十六进制位+十六进制位
            bytes[i]=(byte) Integer.parseInt(tempStr, 16);
        }
        return bytes;
    }
    
    /**byte[]转16进制*/
    public static String bytesToHex(byte[] bytes){
    
    
        StringBuilder sb=new StringBuilder();
        for(int i=0;i<bytes.length;i++){
    
    
            int tempI=bytes[i] & 0xFF;//byte:8bit,int:32bit;高位相与.
            String str = Integer.toHexString(tempI);
            if(str.length()<2){
    
    
                sb.append(0).append(str);//长度不足两位,补齐:如16进制的d,用0d表示。
            }else{
    
    
                sb.append(str);
            }
        }
        return sb.toString();
    }

}

2. Symmetric encryption algorithm

1 Overview

Both encryption and decryption use the same secret key, and the performance is much higher than that of asymmetric encryption.

2. Common algorithms (DES, 3DES, AES)

There are common symmetric encryption algorithms DES、3DES、AES.

The DES algorithm is widely used in POS, ATM, magnetic cards and smart cards (IC cards), gas stations, highway toll stations, etc. Two-way authentication with POS, MAC verification of financial transaction data packets, etc.

3DES is a mode of the DES encryption algorithm and a more secure variant of DES. Transition algorithm from DES to AES.

AES is a next-generation encryption algorithm standard with high speed and higher security level.

name key name running speed safety LF
OF THE 56 bits faster Low middle
3DES 112-bit or 168-bit slow middle high
AES 128, 192, 256 bits quick high Low

3. Application

Often used for higher efficiency requirements 实时数据加密通信.

4. Java implements AES

import org.apache.commons.codec.binary.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;

public class AES {
    
    
    public static void main(String[] args) throws Exception {
    
    
        //生成KEY
        KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
        keyGenerator.init(128);
        //key转换
        Key key = new SecretKeySpec(keyGenerator.generateKey().getEncoded(), "AES");

        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");

        String src = "helloworld你好世界";
        System.out.println("明文:"+src);
        //加密
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] result = cipher.doFinal(src.getBytes());
        System.out.println("加密:" + Base64.encodeBase64String(result));

        //解密
        cipher.init(Cipher.DECRYPT_MODE, key);
        result = cipher.doFinal(result);
        System.out.println("解密:" + new String(result));
    }
}

import org.apache.commons.codec.binary.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

public class AESUtil {
    
    
    private static final String IV_STRING = "sdf4ddfsFD86Vdf2";
    private static final String encoding = "UTF-8";

    public static String encryptAES(String content, String key) throws Exception {
    
    
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(encoding), "AES");
        byte[] initParam = IV_STRING.getBytes(encoding);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
        // 指定加密的算法、工作模式和填充方式
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
        byte[] encryptedBytes = cipher.doFinal(content.getBytes(encoding));
        // 同样对加密后数据进行 base64 编码
        String base64 = new Base64().encodeToString(encryptedBytes);
        return URLEncoder.encode(base64, encoding);
    }

    public static String decryptAES(String content, String key)
            throws InvalidKeyException, NoSuchAlgorithmException,
            NoSuchPaddingException, InvalidAlgorithmParameterException,
            IllegalBlockSizeException, BadPaddingException, IOException {
    
    
        //URL解码
        content = URLDecoder.decode(content, encoding);
        // base64 解码
        byte[] encryptedBytes = Base64.decodeBase64(content);
        byte[] enCodeFormat = key.getBytes(encoding);
        SecretKeySpec secretKey = new SecretKeySpec(enCodeFormat, "AES");
        byte[] initParam = IV_STRING.getBytes(encoding);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(initParam);
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
        byte[] result = cipher.doFinal(encryptedBytes);
        return new String(result, encoding);
    }

    public static void main(String[] args) throws Exception {
    
    
    /*json.put("name", "张三");
    json.put("cityCode", "100001");
    json.put("cityName", "北京市");
    json.put("mobileNo", "13111111111");*/
        String content = "你好世界";
        System.out.println("加密前:" + content);
        String key = "djadiKJdj49dFJLd";
        System.out.println("密钥:" + key);
        String encrypt = encryptAES(content, key);
        System.out.println("加密后:" + encrypt);
        String decrypt = decryptAES(encrypt, key);
        System.out.println("解密后:" + decrypt);
    }
}

3. Asymmetric encryption algorithm

1 Overview

Asymmetric means that encryption and decryption are not the same key, but divided 公钥和私钥. The private key is in the hands of the individual, and the public key is public. One pair of keys is used for encryption and the other is used for decryption. After using one of the encryption keys, the original plaintext can only be decrypted with the corresponding other key, even the key originally used for encryption cannot be used for decryption. It is because of this characteristic that it is called asymmetric encryption.

2. Common algorithms (RSA, ElGamal, Rabin, ECC)

RSA, ElGamal, Knapsack Algorithm, Rabin (a special case of RSA), public key encryption algorithm in the Diffie-Hellman key exchange protocol, Elliptic Curve Cryptography (English: Elliptic Curve Cryptography, ECC). The most widely used is the RSA algorithm (inventors Rivest, Shmir and Adleman initials)

name Maturity safety calculating speed LF
RSA high high middle middle
ECC high high slow high

3. Application

The most common, two points: https and digital signature.

Strictly speaking, https does not use asymmetry for all requests. Based on performance considerations, HTTPS first uses an asymmetric agreement on a key, and later uses this key for symmetric encryption and data transmission.
insert image description here
The digital signature is used to verify whether the message is sent by the server, and is used for anti-counterfeiting and authentication. The process is as follows:

Issuance:
The server publishes the public key outside the server, and the private key is kept secret.
The server calculates the digest of the message M (such as MD5 and other public algorithms), and obtains the digest D. The
server signs D with the private key, obtains the signature S, and
sends M and S to the client together.

Verification:
The client calculates the digest using the same digest algorithm for M, obtains digest D and
uses the server public key to decrypt S, and obtains digest D'
If D and D' are the same, it proves that M is indeed sent by the server

4. Java implements RSA

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class RSAUtil {
    
    
    static String privKey ;
    static String publicKey;

    public static void main(String[] args) throws Exception {
    
    
        //生成公钥和私钥
        genKeyPair();
        //加密字符串
        String message = "helloworld";
        System.out.println("明文:"+message);
        System.out.println("随机公钥为:" + publicKey);
        System.out.println("随机私钥为:" + privKey);

        String messageEn = encrypt(message,publicKey);
        System.out.println("公钥加密:" + messageEn);
        String messageDe = decrypt(messageEn,privKey);
        System.out.println("私钥解密:" + messageDe);

    }

    /**
     * 随机生成密钥对
     */
    public static void genKeyPair() throws NoSuchAlgorithmException {
    
    
        // KeyPairGenerator类用于生成公钥和私钥对,基于RSA算法生成对象
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器,密钥大小为96-1024位
        keyPairGen.initialize(1024,new SecureRandom());
        // 生成一个密钥对,保存在keyPair中
        KeyPair keyPair = keyPairGen.generateKeyPair();

        privKey = new String(Base64.encodeBase64((keyPair.getPrivate().getEncoded())));
        publicKey = new String(Base64.encodeBase64(keyPair.getPublic().getEncoded()));

    }
    /**
     * RSA公钥加密
     */
    public static String encrypt( String str, String publicKey ) throws Exception{
    
    
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    /**
     * RSA私钥解密
     */
    public static String decrypt(String str, String privateKey) throws Exception{
    
    
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        return new String(cipher.doFinal(inputByte));
    }

}

Encryption and decryption to achieve complete restoration
must be decrypted with another key, if encrypted with the public key and then decrypted with the public key, it will fail

Guess you like

Origin blog.csdn.net/A_art_xiang/article/details/132056371