数字签名算法-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签名算法的简单介绍,如有错误请指出,谢谢!

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