JAVA实现RSA生成公私钥/加解密/签名验签

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class Sha1WithRsaUtil {

    static String reqParam = "{'aa':11,'cc':33,'ee':'','bb':22,'signType':'SHA1WithRSA','signData':'aa'}";
    static String reqParam2 = "{\"aa\":11,\"cc\":33,\"ee\":\"\",\"bb\":22,\"signType\":\"SHA1WithRSA\",\"signData\":\"aa\"}";

    /**
     * 加密算法RSA
     */
    public static final String RSA_ALGORITHM = "RSA";
    /**
     * 签名算法
     * SHA1WithRSA MD5withRSA
     */
    public static final String SIGNATURE_ALGORITHM = "SHA1WithRSA";

    /**
     * 据说1024 加密不安全,默认 走2048加密
     */
    public static final int keySize = 2048;
    /**
     * 字符串编码
     */
    public static final String CHARSET = "UTF-8";
    /**
     * 忽略不参与签名的参数
     */
    private static String signTypeKey = "signType";
    private static String signDataKey = "signData";


    /**
     * 请求参数按照ASCII 码升序排序,并用&连接字符串
     *
     * @Param reqJson: 请求的json 串
     * {'aa':11,'cc':33,'ee':'','bb':22,'signType':'SHA1WithRSA','signData':'aa'}
     * @Return: aa=11&bb=22&cc=3
     */
    public static String preSignDataProcess(String reqJson) {

        if (StringUtils.isEmpty(reqJson)) {
            return null;
        }
        HashMap map = JSON.parseObject(reqJson, new TypeReference>() {
        });
        List keyList = map.keySet().stream().sorted().collect(Collectors.toList());

        StringBuffer sb = new StringBuffer();
        keyList.stream().forEach(k -> {
            Object v = map.get(k);
            if (v != null && !"".equals(v) && !signTypeKey.equals(k) && !signDataKey.equals(k)) {
                sb.append(k.trim()).append("=").append(v).append("&");
            }
        });
        if (sb.toString().endsWith("&")) {
            sb.deleteCharAt(sb.length() - 1);
        }

        return sb.toString();
    }


    /**
     * 创建RSA 原始的公钥私钥
     *
     * @return
     */
    public static Map createKeys() {
        return createKeys(keySize);
    }

    /**
     * 获取初始的公钥和私钥
     * 1024 2048
     */
    private static Map createKeys(int keySize) {
        // 为RSA算法创建一个KeyPairGenerator对象
        KeyPairGenerator kpg;
        try {
            kpg = KeyPairGenerator.getInstance(RSA_ALGORITHM);
        } catch (NoSuchAlgorithmException e) {
            throw new IllegalArgumentException("No such algorithm-->[" + RSA_ALGORITHM + "]");
        }

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


        Map keyPairMap = new HashMap<>();
        keyPairMap.put("publicKey", publicKeyStr);
        keyPairMap.put("privateKey", privateKeyStr);

        return keyPairMap;
    }

    /**
     * 根据RSA初始公钥 转化为 X509公钥
     *
     * @param publicKey 密钥字符串(经过base64编码)
     * @throws Exception
     */
    public static RSAPublicKey getPublicKeyX509(String publicKey) throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 通过X509编码的Key指令获得公钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
        RSAPublicKey key = (RSAPublicKey) keyFactory.generatePublic(x509KeySpec);
        return key;
    }

    /**
     * 根据RSA初始私钥 转化为 PKCS8私钥
     *
     * @param privateKey 密钥字符串(经过base64编码)
     * @throws Exception
     */
    public static RSAPrivateKey getPrivateKeyPkcs8(String privateKey)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        // 通过PKCS#8编码的Key指令获得私钥对象
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
        RSAPrivateKey key = (RSAPrivateKey) keyFactory.generatePrivate(pkcs8KeySpec);
        return key;
    }

    /**
     * 加密操作
     * X509 公钥加密(对应 PKCS8 私钥进行解密) 或者 PKCS8 私钥加密(对应X509公钥解密)
     */
    private static String encrypt(String data, Key key) {

        BigInteger modulus = keyModulus(key);
        try {
            Cipher cipher = cipherInstance(Cipher.ENCRYPT_MODE, key);
            byte[] bytes = rsaSplitCodec(cipher, Cipher.ENCRYPT_MODE, data.getBytes(CHARSET),
                    modulus.bitLength());

            return Base64.encodeBase64URLSafeString(bytes);
        } catch (Exception e) {
            throw new RuntimeException("加密字符串[" + data + "]时遇到异常", e);
        }
    }

    /**
     * 解密操作
     * PKCS8 私钥解密(对应 X509 公钥加密)或者 X509 公钥解密(对应 PKCS8 私钥进行加密)
     */
    private static String decrypt(String data, Key key) {
        BigInteger modulus = keyModulus(key);
        Cipher cipher = cipherInstance(Cipher.DECRYPT_MODE, key);
        byte[] bytes = rsaSplitCodec(cipher, Cipher.DECRYPT_MODE, Base64.decodeBase64(data),
                modulus.bitLength());

        try {
            return new String(bytes, CHARSET);
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("RSA解密失败:", e);
        }
    }


    /**
     * RSA签名
     *
     * @param content    待签名数据
     * @param privateKey 商户私钥
     * @return 签名值
     */
    public static String sign(String content, String privateKey) {
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));

            KeyFactory keyf = KeyFactory.getInstance(RSA_ALGORITHM);
            PrivateKey priKey = keyf.generatePrivate(priPKCS8);

            java.security.Signature signature = java.security.Signature.getInstance(SIGNATURE_ALGORITHM);

            signature.initSign(priKey);
            signature.update(content.getBytes(CHARSET));

            byte[] signed = signature.sign();

            return Base64.encodeBase64URLSafeString(signed);
        } catch (Exception e) {
            throw new RuntimeException("签名发生异常", e);
        }
    }

    /**
     * RSA 验签
     *
     * @param content   待签名数据
     * @param sign      签名值
     * @param publicKey 分配给开发商公钥
     * @return 布尔值
     */
    public static boolean verify(String content, String sign, String publicKey) {
        try {
            KeyFactory keyFactory = KeyFactory.getInstance(RSA_ALGORITHM);
            byte[] encodedKey = Base64.decodeBase64(publicKey);
            PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));

            java.security.Signature signature = java.security.Signature.getInstance(SIGNATURE_ALGORITHM);

            signature.initVerify(pubKey);
            signature.update(content.getBytes(CHARSET));

            boolean bverify = signature.verify(Base64.decodeBase64(sign));
            return bverify;

        } catch (Exception e) {
            throw new RuntimeException("RSA 验签失败", e);
        }
    }


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

        }
        return resultDatas;
    }

    /**
     * 获取加密key的 实例
     */
    private static Cipher cipherInstance(int mode, java.security.Key key) {
        Cipher cipher = null;

        try {
            cipher = Cipher.getInstance(RSA_ALGORITHM);
            cipher.init(mode, key);
        } catch (Exception e) {
            throw new RuntimeException("获取Cipher 实例异常:", e);
        }
        return cipher;
    }

    private static BigInteger keyModulus(Key key) {
        BigInteger modulus = null;
        if (key instanceof RSAPublicKey) {
            modulus = ((RSAPublicKey) key).getModulus();
        } else if (key instanceof RSAPrivateKey) {
            modulus = ((RSAPrivateKey) key).getModulus();
        }
        return modulus;
    }

    public static void main(String[] args) throws Exception {
        Map keyMap = createKeys();
        String publicKey = keyMap.get("publicKey");
        String privateKey = keyMap.get("privateKey");

        System.out.println("原始公钥:\n" + publicKey);
        System.out.println("原始私钥:\n" + privateKey);

        String content = preSignDataProcess(reqParam);

        String sign = sign(content, privateKey);
        System.out.println("签名:\n" + sign);

        boolean verify = verify(content, sign, publicKey);
        System.out.println("验签:" + verify);

        String privateEncrypt = encrypt(content, getPrivateKeyPkcs8(privateKey));
        System.out.println("PKCS8 私钥加密:\n" + privateEncrypt);

        String publicDecrypt = decrypt(privateEncrypt, getPublicKeyX509(publicKey));
        System.out.println("X509 公钥解密:\n" + publicDecrypt);

        String publicEncrypt = encrypt(content, getPublicKeyX509(publicKey));
        System.out.println("X509 公钥加密:\n" + publicEncrypt);

        String privateDecrypt = decrypt(publicEncrypt, getPrivateKeyPkcs8(privateKey));
        System.out.println("PKCS8 私钥解密:\n" + privateDecrypt);

    }
}

 

你可能感兴趣的:(JavaSE,加密安全)