AES对称加密RSA非对称加密和MD5不可逆加密代码示例

加密算法可以分为三大类:

  • 对称加密算法:AES,DES ,国密sm4(ecb模式),加密和解密用的是同一个密钥,加解密速度快,适合大量数据(本地文件加密、VPN、TLS数据部分)
  • 非对称加密算法: RSA,加密和解密用的是一对公钥和私钥,速度慢,适合小数据(数字签名、HTTPS证书、密钥交换)
  • MD5:是一种哈希算法,不是加密算法。它的主要作用是将任意长度的数据转换为固定长度(128位/16字节)的“摘要”,适用于文件上传下载的校验, redis/Memcached中key的生成(原key太长,用md5缩短成固定长度)

登陆密码加密流程:

web端用公钥加密密码,server端用私钥解码,将解出的明文用MD5加密后存入数据库或与数据库的密码比较,这种方式会有中间人攻击的问题,只能用https方式,

如果用http方式,需要在web端生成公钥和私钥,将公钥发给server端,server端生成一串随机字符串并用公钥加密发给web端,web端用私钥解码并拼接上密码组成新的

字符串,将随机字符串作为AES加密算法的密码对密码进行加密发送给server端,server端使用随机字符串对新的字符串进行解密,server端系解析解密后的字符串,校验随机字符串是否一致.

AES:

加密解密工具类:
import org.bouncycastle.crypto.DataLengthException;
import org.bouncycastle.crypto.InvalidCipherTextException;
import org.bouncycastle.crypto.engines.AESFastEngine;
import org.bouncycastle.crypto.modes.GCMBlockCipher;
import org.bouncycastle.crypto.params.AEADParameters;
import org.bouncycastle.crypto.params.KeyParameter;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Base64;

/**
 * AES-GCM-256 工具类 加解密方法中已调用 Base64 方法
 */
public class AesGcm256Util {
    private static final SecureRandom SECURE_RANDOM = new SecureRandom();
    public static final int NONCE_BIT_SIZE = 128;
    public static final int MAC_BIT_SIZE = 128;
    public static final int KEY_BIT_SIZE = 256;

    private AesGcm256Util() {}

   /**
     * 编码
     *
     * @param hexStr 文本
     * @return 字节数组
     */
    public static byte[] hexToByte(String hexStr) {
        int len = hexStr.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] =
                (byte)((Character.digit(hexStr.charAt(i), 16) << 4) + Character.digit(hexStr.charAt(i + 1), 16));
        }
        return data;
    }/**
     * 加密
     *
     * @param plainText 明文文本
     * @param key 密钥
     * @param iv 向量
     * @return 加密字符串
     */
    public static String encrypt(String plainText, byte[] key, byte[] iv) {
        String sr;
        try {
            byte[] plainBytes = plainText.getBytes(StandardCharsets.UTF_8);
            GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
            AEADParameters parameters = new AEADParameters(new KeyParameter(key), MAC_BIT_SIZE, iv, null);
            cipher.init(true, parameters);
            byte[] encryptedBytes = new byte[cipher.getOutputSize(plainBytes.length)];
            int retLen = cipher.processBytes(plainBytes, 0, plainBytes.length, encryptedBytes, 0);
            cipher.doFinal(encryptedBytes, retLen);
            sr = Base64.getEncoder().encodeToString(encryptedBytes);
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage());
        }
        return sr;
    }

    /**
     * 解密
     *
     * @param encryptedText 已加密文本
     * @param key 密钥
     * @param iv 向量
     * @return 已解密文本
     */
    public static String decrypt(String encryptedText, byte[] key, byte[] iv) {
        String sr;
        try {
            byte[] encryptedBytes = Base64.getDecoder().decode(encryptedText);
            GCMBlockCipher cipher = new GCMBlockCipher(new AESFastEngine());
            AEADParameters parameters = new AEADParameters(new KeyParameter(key), MAC_BIT_SIZE, iv, null);
            cipher.init(false, parameters);
            byte[] plainBytes = new byte[cipher.getOutputSize(encryptedBytes.length)];
            int retLen = cipher.processBytes(encryptedBytes, 0, encryptedBytes.length, plainBytes, 0);
            cipher.doFinal(plainBytes, retLen);
            sr = new String(plainBytes, StandardCharsets.UTF_8);
        } catch (IllegalArgumentException | IllegalStateException | DataLengthException
            | InvalidCipherTextException ex) {
            throw new RuntimeException(ex.getMessage());
        }
        return sr;
    }
}
调用工具类对明文加密获得密文:
AesGcm256Util.encrypt(JsonUtils.toJson(list), AesGcm256Util.hexToByte(AesSecretKey), AesGcm256Util.hexToByte(iv))
 

 

RSA:

package login;

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;
import java.util.Base64;

public class RSAUtil {
    static final Base64.Decoder decoder = Base64.getDecoder();
    static final Base64.Encoder encoder = Base64.getEncoder();

    public static void main(String[] args) throws Exception {
        // 随机生成一对密钥(包含公钥和私钥)
        KeyPair keyPair = generateKeyPair();
        // 获取 公钥 和 私钥
        RSAPublicKey pubKey = (RSAPublicKey) keyPair.getPublic();
        // 创建 已编码的公钥规格
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pubKey.getEncoded());
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate();
        // 创建 已编码的私钥规格
        PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(priKey.getEncoded());
        PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
        // 原文数据
        String data = "你好, World!";
        // 客户端: 用公钥加密原文, 返回加密后的数据
        byte[] cipherData = encrypt(data.getBytes(), publicKey);
        // 服务端: 用私钥解密数据, 返回原文
        byte[] plainData = decrypt(cipherData, privateKey);
        // 输出密文
        System.out.println(new String(cipherData));
        // 输出查看解密后的原文
        System.out.println(new String(plainData));  // 结果打印: 你好, World
    }



    /**
     * 随机生成密钥对(包含公钥和私钥)
     */
    private static KeyPair generateKeyPair() throws Exception {
        // 获取指定算法的密钥对生成器
        KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
        // 初始化密钥对生成器(密钥长度要适中, 太短不安全, 太长加密/解密速度慢)
        gen.initialize(2048);
        // 随机生成一对密钥(包含公钥和私钥)
        KeyPair keyPair = gen.generateKeyPair();
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
        //公钥私钥base64编码
        String publicKeyString = new String(encoder.encode(rsaPublicKey.getEncoded()));
        String privateKeyString = new String(encoder.encode(rsaPrivateKey.getEncoded()));
        return keyPair;
    }
    /**
     * 公钥加密数据
     */
    private static byte[] encrypt(byte[] plainData, PublicKey pubKey) throws Exception {
        // 获取指定算法的密码器
        Cipher cipher = Cipher.getInstance("RSA");
        // 初始化密码器(公钥加密模型)
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        // 加密数据, 返回加密后的密文
        return cipher.doFinal(plainData);
    }
    /**
     * 私钥解密数据
     */
    private static byte[] decrypt(byte[] cipherData, PrivateKey priKey) throws Exception {
        // 获取指定算法的密码器
        Cipher cipher = Cipher.getInstance("RSA");
        // 初始化密码器(私钥解密模型)
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        // 解密数据, 返回解密后的明文
        return cipher.doFinal(cipherData);
    }

}

MD5加盐:

package login;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class PasswordEncoder {
    private final static String[] hexDigits = { "0", "1", "2", "3", "4", "5",
            "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
 
    private Object salt;
    private String algorithm;
 
    public PasswordEncoder(Object salt, String algorithm) {
        this.salt = salt;
        this.algorithm = algorithm;
    }
 
    public String encode(String rawPass) {
        String result = null;
        try {
            //参数可以是"MD5","SHA"等
            MessageDigest md = MessageDigest.getInstance(algorithm);
            //加密后的字符串
            result = byteArrayToHexString(md.digest(mergePasswordAndSalt(rawPass).getBytes("utf-8")));
        } catch (Exception ex) {
        }
        return result;
    }
 
    public boolean isPasswordValid(String encPass, String rawPass) {
        String pass1 = "" + encPass;
        String pass2 = encode(rawPass);
 
        return pass1.equals(pass2);
    }
 
    private String mergePasswordAndSalt(String password) {
        if (password == null) {
            password = "";
        }
 
        if ((salt == null) || "".equals(salt)) {
            return password;
        } else {
            return password + "{" + salt.toString() + "}";
        }
    }
 
    /**
     * 转换字节数组为16进制字串
     * @param b 字节数组
     * @return 16进制字串
     */
    private static String byteArrayToHexString(byte[] b) {
        StringBuffer resultSb = new StringBuffer();
        for (int i = 0; i < b.length; i++) {
            resultSb.append(byteToHexString(b[i]));
        }
        return resultSb.toString();
    }
 
    private static String byteToHexString(byte b) {
        int n = b;
        if (n < 0)
            n = 256 + n;
        int d1 = n / 16;
        int d2 = n % 16;
        return hexDigits[d1] + hexDigits[d2];
    }
 
 
    public static void main(String[] args) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        String salt = "be5e0323a9195ade5f56695ed9f2eb6b036f3e6417115d0cbe2fb9d74d8740406838dc84f152014b39a2414fb3530a40bc028a9e87642bd03cf5c36a1f70801e";
        PasswordEncoder encoderMd5 = new PasswordEncoder(salt, "MD5");
        String encode = encoderMd5.encode("zxp52077");
        System.out.println(encode);
        boolean passwordValid = encoderMd5.isPasswordValid("c21feb87d79fd42e4336e4c231785ff9", "test");
        System.out.println(passwordValid);
 
        PasswordEncoder encoderSha = new PasswordEncoder(salt, "SHA");
        String pass2 = encoderSha.encode("test");
        System.out.println(pass2);
        boolean passwordValid2 = encoderSha.isPasswordValid("409cf43cbdc92e1979018b2e2fdc60c7f07673e9", "test");
        System.out.println(passwordValid2);


    }
 
}

 对称加密和非对称加密经常结合使用,比如: 客户端从服务器获取公钥,之后用这个公钥加密AES对称加密的密钥,服务端用私钥解密,获得 AES 密钥,之后双方用对称加密(AES)传输数据,高效安全

 
 
posted @ 2023-01-11 15:10  杨吃羊  阅读(301)  评论(0)    收藏  举报