加解密(AES,RSA)和签名(MD5,HmacSHA256,SHA1WithRSA,SHA256WithRSA)

最近对接各种支付以及数据库连接池加密Druid,里面涉及到许多加密解密,加签验签的过程,这里总结一下(以下代码全部测试通过)

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.security.rsa.RSACore;
import sun.security.rsa.RSAKeyFactory;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Random;

/**
 * @author paul
 * @description
 * @date 2018/12/24
 */
public abstract class SignatureTools {

    public static void main(String[] args) throws Exception {
        String content = "";
        for (int i = 0; i < 100; i++) {
            content = content + "0123456789";
        }

        //生成rsa秘钥
        byte[][] keyPairBytes = genRsaKeyPairBytes(1024);
        String privateKey = new String(Base64.getEncoder().encode(keyPairBytes[0]));
        String publicKey = new String(Base64.getEncoder().encode(keyPairBytes[1]));

        String rsaEncrypt = null;
        String rsaDecrypt = null;

        rsaEncrypt = rsaEncryptByPublicKey(content, publicKey, "UTF-8");
        rsaDecrypt = rsaDecryptByPrivateKey(rsaEncrypt, privateKey, "UTF-8");
        System.out.println("1:rsa私钥分段解密:" + rsaDecrypt.equals(content));
        rsaEncrypt = rsaEncryptByPrivateKey(content, privateKey, "UTF-8");
        rsaDecrypt = rsaDecryptByPublicKey(rsaEncrypt, publicKey, "UTF-8");
        System.out.println("2:rsa公钥分段解密:" + rsaDecrypt.equals(content));

        String sign = rsa256Sign(content, privateKey, "UTF-8");
        boolean b = rsa256CheckContent(content, sign, publicKey, "UTF-8");
        System.out.println("3:SHA256WithRSA验签结果:" + rsaDecrypt.equals(content));

        sign = rsaSign(content, privateKey, "UTF-8");
        b = rsaCheckContent(content, sign, publicKey, "UTF-8");
        System.out.println("3:SHA1WithRSA验签结果:" + rsaDecrypt.equals(content));

        System.out.println("4.1:MD5:" + MD5(content));
        System.out.println("4.2:MD5:" + MD5(content));

        System.out.println("5.1:HmacSHA256:" + HmacSHA256(content,"0123456789"));
        System.out.println("5.2:HmacSHA256:" + HmacSHA256(content,content));
        //256秘钥问题需要安转jce:https://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
        //Exception in thread "main" java.security.InvalidKeyException: Illegal key size or default parameters

        //String key256 = generateNonceStr();
        String key256 = generateNonceStr().substring(0,16);
        String aesEncrypt = AES_ENCRYPT(content, key256);
        String aesDecrypt = AES_DECRYPT(aesEncrypt, key256);
        System.out.println("6:AES解密结果:" + aesDecrypt.equals(content));

    }

    public static final String SIGN_TYPE_RSA = "RSA";

    public static final String SIGN_TYPE_RSA_PAD = "RSA/ECB/PKCS1Padding";
    //int MAX_ENCRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(pubKey)) - 11;  -11与PKCS1Padding有关

    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";

    public static final String SIGN_SHA256RSA_ALGORITHMS = "SHA256WithRSA";

    /**
     * RSA最大加密明文大小,秘钥1024位
     */
    private static final int MAX_ENCRYPT_BLOCK_1024 = 117;

    /**
     * RSA最大解密密文大小,秘钥1024位
     */
    private static final int MAX_DECRYPT_BLOCK_1024 = 128;

    /**
     * RSA最大加密明文大小,秘钥2048位
     */
    private static final int MAX_ENCRYPT_BLOCK_2048 = 245;

    /**
     * RSA最大解密密文大小,秘钥2048位
     */
    private static final int MAX_DECRYPT_BLOCK_2048 = 256;

    /**
     * RSA公钥和私钥生成
     *
     * @param keySize 秘钥长度 1024 2048 4096
     * @return
     * @throws NoSuchAlgorithmException
     * @throws NoSuchProviderException
     */
    public static byte[][] genRsaKeyPairBytes(int keySize)
            throws NoSuchAlgorithmException, NoSuchProviderException {
        byte[][] keyPairBytes = new byte[2][];

        KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
        gen.initialize(keySize, new SecureRandom());
        KeyPair pair = gen.generateKeyPair();

        keyPairBytes[0] = pair.getPrivate().getEncoded();
        keyPairBytes[1] = pair.getPublic().getEncoded();

        return keyPairBytes;
    }

    /**
     * sha256WithRsa 加签
     */
    public static String rsa256Sign(String content, String privateKey,
                                    String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_SHA256RSA_ALGORITHMS);
            signature.initSign(priKey);

            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }

            byte[] signed = signature.sign();


            java.util.Base64.Encoder encoder = java.util.Base64.getEncoder();
            byte[] encode = encoder.encode(signed);
            return new String(encode);
        } catch (Exception e) {
            throw new ApiException("RSAcontent = " + content + "; charset = " + charset, e);
        }

    }

    /**
     * sha1WithRsa 加签
     */
    public static String rsaSign(String content, String privateKey,
                                 String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));
            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }
            byte[] signed = signature.sign();
            return new String(Base64.getEncoder().encode(signed));
        } catch (InvalidKeySpecException ie) {
            throw new ApiException("RSA私钥格式不正确,请检查是否正确配置了PKCS8格式的私钥", ie);
        } catch (Exception e) {
            throw new ApiException("RSAcontent = " + content + "; charset = " + charset, e);
        }
    }

    /**
     * PrivateKey
     *
     * @param algorithm
     * @param ins
     * @return
     * @throws Exception
     */
    public static PrivateKey getPrivateKeyFromPKCS8(String algorithm,
                                                    InputStream ins) throws Exception {
        if (ins == null || isEmpty(algorithm)) {
            return null;
        }
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        byte[] encodedKey = readText(ins).getBytes();
        encodedKey = Base64.getDecoder().decode(encodedKey);
        return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
    }

    /**
     * PublicKey
     *
     * @param algorithm
     * @param ins
     * @return
     * @throws Exception
     */
    public static PublicKey getPublicKeyFromX509(String algorithm,
                                                 InputStream ins) throws Exception {
        KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
        StringWriter writer = new StringWriter();
        io(new InputStreamReader(ins), writer);
        byte[] encodedKey = writer.toString().getBytes();
        encodedKey = Base64.getDecoder().decode(encodedKey);
        return keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
    }

    /**
     * 验签:SHA256WithRSA
     *
     * @param content
     * @param sign
     * @param publicKey
     * @param charset
     * @return
     * @throws ApiException
     */
    public static boolean rsa256CheckContent(String content, String sign, String publicKey,
                                             String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA",
                    new ByteArrayInputStream(publicKey.getBytes()));
            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_SHA256RSA_ALGORITHMS);
            signature.initVerify(pubKey);
            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }
            return signature.verify(Base64.getDecoder().decode(sign.getBytes()));
        } catch (Exception e) {
            throw new ApiException(
                    "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
        }
    }

    /**
     * 验签:SHA1WithRSA
     *
     * @param content
     * @param sign
     * @param publicKey
     * @param charset
     * @return
     * @throws ApiException
     */
    public static boolean rsaCheckContent(String content, String sign, String publicKey,
                                          String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509("RSA",
                    new ByteArrayInputStream(publicKey.getBytes()));

            java.security.Signature signature = java.security.Signature
                    .getInstance(SIGN_ALGORITHMS);
            signature.initVerify(pubKey);
            if (isEmpty(charset)) {
                signature.update(content.getBytes());
            } else {
                signature.update(content.getBytes(charset));
            }
            return signature.verify(Base64.getDecoder().decode(sign.getBytes()));
        } catch (Exception e) {
            throw new ApiException(
                    "RSAcontent = " + content + ",sign=" + sign + ",charset = " + charset, e);
        }
    }


    /**
     * rsa公钥分段加密
     *
     * @param content   待加密内容
     * @param publicKey 公钥
     * @param charset   字符集,如UTF-8, GBK, GB2312
     * @return 密文内容
     * @throws ApiException
     */
    public static String rsaEncryptByPublicKey(String content, String publicKey,
                                               String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(publicKey.getBytes()));

            int MAX_ENCRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(pubKey)) - 11;

            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] data = isEmpty(charset) ? content.getBytes()
                    : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = Base64.getEncoder().encode(out.toByteArray());
            out.close();

            return isEmpty(charset) ? new String(encryptedData)
                    : new String(encryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncryptContent = " + content + ",charset = " + charset,
                    e);
        }
    }

    /**
     * rsa私钥分段解密
     *
     * @param content    待解密内容
     * @param privateKey 私钥
     * @param charset    字符集,如UTF-8, GBK, GB2312
     * @return 明文内容
     * @throws ApiException
     */
    public static String rsaDecryptByPrivateKey(String content, String privateKey,
                                                String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            int MAX_DECRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(priKey));


            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);
            cipher.init(Cipher.DECRYPT_MODE, priKey);
            byte[] encryptedData = isEmpty(charset)
                    ? Base64.getDecoder().decode(content.getBytes())
                    : Base64.getDecoder().decode(content.getBytes(charset));
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();

            return isEmpty(charset) ? new String(decryptedData)
                    : new String(decryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncodeContent = " + content + ",charset = " + charset, e);
        }
    }

    /**
     * rsa私钥分段加密
     *
     * @param content    待加密内容
     * @param privateKey 私钥
     * @param charset    字符集,如UTF-8, GBK, GB2312
     * @return 密文内容
     * @throws ApiException
     */
    public static String rsaEncryptByPrivateKey(String content, String privateKey,
                                                String charset) throws ApiException {
        try {
            PrivateKey priKey = getPrivateKeyFromPKCS8(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(privateKey.getBytes()));

            int MAX_ENCRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(priKey)) - 11;
            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);
            cipher.init(Cipher.ENCRYPT_MODE, priKey);
            byte[] data = isEmpty(charset) ? content.getBytes()
                    : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = Base64.getEncoder().encode(out.toByteArray());
            out.close();

            return isEmpty(charset) ? new String(encryptedData)
                    : new String(encryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncryptContent = " + content + ",charset = " + charset,
                    e);
        }
    }

    /**
     * rsa公钥分段解密
     *
     * @param content   待解密内容
     * @param publicKey 私钥
     * @param charset   字符集,如UTF-8, GBK, GB2312
     * @return 明文内容
     * @throws ApiException
     */
    public static String rsaDecryptByPublicKey(String content, String publicKey,
                                               String charset) throws ApiException {
        try {
            PublicKey pubKey = getPublicKeyFromX509(SIGN_TYPE_RSA,
                    new ByteArrayInputStream(publicKey.getBytes()));
            Cipher cipher = Cipher.getInstance(SIGN_TYPE_RSA_PAD);

            int MAX_DECRYPT_BLOCK = RSACore.getByteLength(RSAKeyFactory.toRSAKey(pubKey));

            cipher.init(Cipher.DECRYPT_MODE, pubKey);
            byte[] encryptedData = isEmpty(charset)
                    ? Base64.getDecoder().decode(content.getBytes())
                    : Base64.getDecoder().decode(content.getBytes(charset));
            int inputLen = encryptedData.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段解密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_DECRYPT_BLOCK) {
                    cache = cipher.doFinal(encryptedData, offSet, MAX_DECRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(encryptedData, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_DECRYPT_BLOCK;
            }
            byte[] decryptedData = out.toByteArray();
            out.close();

            return isEmpty(charset) ? new String(decryptedData)
                    : new String(decryptedData, charset);
        } catch (Exception e) {
            throw new ApiException("EncodeContent = " + content + ",charset = " + charset, e);
        }
    }

    public static boolean isEmpty(String value) {
        int strLen;
        if (value == null || (strLen = value.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(value.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 支持的Algorithm以及提供者
     */
    public static void support() {
        Security.addProvider(new BouncyCastleProvider());
        for (Provider provider : Security.getProviders()) {
            System.out.println("Provider: " + provider.getName());
            for (Provider.Service service : provider.getServices()) {
                System.out.println("  Algorithm: " + service.getAlgorithm());
            }
        }
    }

    /**
     * AES 加密
     *
     * @param data
     * @param key  长度 128/192/256 bits.256注意jdk问题
     * @return
     * @throws Exception
     */
    public static String AES_ENCRYPT(String data, String key) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);

        byte[] result = cipher.doFinal(data.getBytes("UTF-8"));
        byte[] encode = Base64.getEncoder().encode(result);
        return new String(encode);
    }

    /**
     * AES 解密
     *
     * @param data
     * @param key  128/192/256 bits.256注意jdk问题
     * @return
     * @throws Exception
     */
    public static String AES_DECRYPT(String data, String key) throws Exception {
        Security.addProvider(new BouncyCastleProvider());
        SecretKey secretKey = new SecretKeySpec(key.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);

        byte[] encode = Base64.getDecoder().decode(data);
        byte[] result = cipher.doFinal(encode);

        return new String(result, "UTF-8");
    }



    /**
     * MD5
     *
     * @param data
     * @return
     * @throws Exception
     */
    public static String MD5(String data) throws Exception {
        MessageDigest md = MessageDigest.getInstance("MD5");
        byte[] array = md.digest(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }

    /**
     * HMACSHA256
     *
     * @param data 待处理数据
     * @param key  密钥
     * @return 加密结果
     */
    public static String HmacSHA256(String data, String key) throws Exception {
        Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
        hmacSHA256.init(secret_key);
        byte[] array = hmacSHA256.doFinal(data.getBytes("UTF-8"));
        StringBuilder sb = new StringBuilder();
        for (byte item : array) {
            sb.append(Integer.toHexString((item & 0xFF) | 0x100).substring(1, 3));
        }
        return sb.toString().toUpperCase();
    }


    private static final String SYMBOLS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
    private static final Random RANDOM = new SecureRandom();

    /**
     * 作为MD5和HMACSHA256的随机值
     *
     * @return
     */
    public static String generateNonceStr() {
        char[] nonceChars = new char[32];
        for (int index = 0; index < nonceChars.length; ++index) {
            nonceChars[index] = SYMBOLS.charAt(RANDOM.nextInt(SYMBOLS.length()));
        }
        return new String(nonceChars);
    }

    public static class ApiException extends Exception {
        private String errCode;
        private String errMsg;

        public ApiException() {
            super();
        }

        public ApiException(String message, Throwable cause) {
            super(message, cause);
        }

        public ApiException(String message) {
            super(message);
        }

        public ApiException(Throwable cause) {
            super(cause);
        }

        public ApiException(String errCode, String errMsg) {
            super(errCode + ":" + errMsg);
            this.errCode = errCode;
            this.errMsg = errMsg;
        }

        public String getErrCode() {
            return this.errCode;
        }

        public String getErrMsg() {
            return this.errMsg;
        }

    }


    private static String readText(InputStream in)
            throws IOException {
        return readText(in, null);
    }

    private static String readText(InputStream in, String encoding)
            throws IOException {
        Reader reader = (encoding == null) ? new InputStreamReader(in) : new InputStreamReader(in,
                encoding);
        return readText(reader);
    }

    private static String readText(Reader reader) throws IOException {
        StringWriter writer = new StringWriter();
        io(reader, writer);
        return writer.toString();
    }

    private static void io(Reader in, Writer out) throws IOException {
        int bufferSize = 1024;
        char[] buffer = new char[bufferSize];
        int amount;

        while ((amount = in.read(buffer)) >= 0) {
            out.write(buffer, 0, amount);
        }
    }
}

你可能感兴趣的:(加解密(AES,RSA)和签名(MD5,HmacSHA256,SHA1WithRSA,SHA256WithRSA))