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<String, Object> map = JSON.parseObject(reqJson, new TypeReference<HashMap<String, Object>>() {
        });
        List<String> 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<String, String> createKeys() {
        return createKeys(keySize);
    }

    /**
     * 獲取初始的公鑰和私鑰
     * 1024 2048
     */
    private static Map<String, String> 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<String, String> 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<String, String> 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);

    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章