數字簽名算法-RSA

數字簽名(又稱公鑰數字簽名)是一種類似寫在紙上的普通的物理簽名,但是使用了公鑰加密領域的技術實現,用於鑑別數字信息的方法。一套數字簽名通常定義兩種互補的運算,一個用於簽名,另一個用於驗證,但法條中的電子簽章與數字簽名,代表之意義並不相同,電子簽章用以辨識及確認電子文件簽署人身份、資格及電子文件真僞者。而數字簽名則是以數學算法或其他方式運算對其加密,才形成電子簽章,意即使用數字簽名才創造出電子簽章。 ——————— 摘自維基百科


簽名的好處
簽名可以保證數據完整性、不可抵賴性、鑑權

簽名過程
發送方A將需要傳送的數據通過自己的私鑰(Private Key)進行簽名產生摘要,然後將簽名生成的摘要和需要傳送的數據一起傳輸給接收方B,接收方B在接收到數據後通過A的公鑰(Public Key)來對簽名進行校驗。

RSA簽名算法

算法 密鑰長度 默認長度 簽名長度 實現方
MD2withRSA 512~65536(64的整數倍) 1024 與密鑰長度相同 JDK
MD5withRSA
SHA1withRSA
SHA224withRSA 2048 BC
SHA256withRSA
SHA384withRSA
SHA512withRSA
RIPEMD128withRSA
RIPEMD168withRSA


代碼實現:

public class SignatureWithRSA {
    // 公/私鑰生成算法
    private final static String KEY_ALGORITHM = "RSA";

    // 數據簽名算法
    /**
     * JDK實現的RSA簽名算法有  MD2withRSA、MD5withRSA、SHA1withRSA
     * 密鑰長度爲512~65536(要求爲64的整數倍),默認長度爲1024,簽名的長度和密鑰長度相等
     * 
     * 其他的RSA簽名算法有SHA224withRSA、SHA256withRSA、SHA512withRSA等JDK並未實現,
     * 但是bouncycastle都做了支持,默認密鑰爲2048,簽名長度同樣和密鑰長度相等
     * */
    private static final String SIGN_ALGORITHM = "SHA1withRSA";

    private static final String PUBLIC_KEY = "publicKey";

    private static final String PRIVATE_KEY = "privateKey";

    private static final int KEY_LENGTH = 512;

    /**
     * 初始化密鑰
     * @throws Exception 
     * */
    public static Map<String, Key> initKey() throws Exception {
        // 實例化密鑰生成器
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        // 初始化密鑰長度,此處爲512
        keyPairGenerator.initialize(KEY_LENGTH);
        // 獲取密鑰對
        KeyPair keyPair = keyPairGenerator.generateKeyPair();
        // 獲取RSA公鑰
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        // 獲取RSA私鑰
        RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();

        Map<String, Key> keyMap = new HashMap<String, Key>();
        keyMap.put(PUBLIC_KEY, rsaPublicKey);
        keyMap.put(PRIVATE_KEY, rsaPrivateKey);

        return keyMap;
    }

    /**
     * 獲取公鑰
     * */
    public static RSAPublicKey getPublicKey(Map<String, Key> keyMap) {
        return (RSAPublicKey) keyMap.get(PUBLIC_KEY);
    }

    /**
     * 獲取私鑰
     * */
    public static RSAPrivateKey getPrivateKey(Map<String, Key> keyMap) {
        return (RSAPrivateKey) keyMap.get(PRIVATE_KEY);
    }

    /**
     * 使用私鑰對數據進行簽名
     * @throws Exception 
     * @return byte[]
     * */
    public static byte[] signatureWithPrivateKey(String data, RSAPrivateKey rsaPrivateKey) throws Exception {
        PKCS8EncodedKeySpec encodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 獲取私鑰
        PrivateKey privateKey = keyFactory.generatePrivate(encodedKeySpec);

        // 使用簽名算法實例化Signature
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        // 使用簽名私鑰進行初始化
        signature.initSign(privateKey);
        // 更新需要簽名的數據
        signature.update(data.getBytes());
        // 執行簽名
        byte[] signed = signature.sign();

        return signed;
    }

    /**
     * 使用公鑰對簽名的數據進行校驗
     * @throws Exception 
     * */
    public static boolean verifyWithPublicKey(String data, byte[] signed, RSAPublicKey rsaPublicKey) throws Exception {
        X509EncodedKeySpec encodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());
        // 實例化KeyFactory
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 獲取簽名公鑰
        PublicKey publicKey = keyFactory.generatePublic(encodedKeySpec);

        Signature signature = Signature.getInstance(SIGN_ALGORITHM);
        signature.initVerify(publicKey);
        signature.update(data.getBytes());
        boolean verified = signature.verify(signed);

        return verified;
    }

    public static void main(String[] args) throws Exception {
        String msg = "Hello World";
        Map<String, Key> keyMap = initKey();
        RSAPrivateKey priK = getPrivateKey(keyMap);
        RSAPublicKey pubK = getPublicKey(keyMap);
        System.out.println("簽名前的數據---->" + msg);
        // 執行簽名
        byte[] signedMsg = signatureWithPrivateKey(msg, priK);
        System.out.println("密鑰長度---->" + KEY_LENGTH);
        System.out.println("簽名後數據長度---->" + signedMsg.length * 8);
        System.out.println("簽名後的數據---->" + Base64.encodeBase64String(signedMsg));
        // 校驗簽名
        boolean verified = verifyWithPublicKey(msg, signedMsg, pubK);
        System.out.println("校驗---->" + verified);
    }
}

輸出的結果:

這裏寫圖片描述

以上,就是對RSA簽名算法的簡單介紹,如有錯誤請指出,謝謝!

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