Bootstrap

java实现数字签名算法


前言

数字签名是手写签名在计算机软件应用中的一种体现,同样起到了抗否认的作用。本文介绍什么是数字签名,以及如何用java代码实现数字签名。


一、数字签名简述

数字签名算法可以看做是一种带有密钥的消息摘要算法,并且这种密钥包含了公钥和私钥。也就是说,数字签名算法是非对称加密算法消息摘要算法的结合体。
签名操作只能由甲方完成,验证签名操作则由乙方来完成,用于验证操作的相关信息是由甲方公布给乙方。
与摘要值的表示方法相同,签名值也常以十六机制字符串的形式出现。
在这里插入图片描述

二、数字签名算法家谱

在这里插入图片描述

三、代码实现

1.引入jar包

<dependency>
     <groupId>org.bouncycastle</groupId>
     <artifactId>bcprov-jdk15on</artifactId>
     <version>1.67</version>
</dependency>

2.RSA数字签名实现

实现细节

算法密钥长度密钥长度默认值签名长度备注
MD2withRSA512~65536
(64的倍数)
1024与密钥长度相同jdk实现
MD5withRSA
SHA1withRSA
SHA224withRSA2048Bouncy Castle实现
SHA256withRSA
SHA384withRSA
SHA512withRSA
RIPEMD128withRSA
RIPEMD160withRSA

代码

public class SignatureUtils {
    public static final String KEY_ALGORITHM = "RSA";

    // 数字签名算法
    public static final String SIGNATURE_ALGORITHM = "SHA1withRSA";

    private static final String PUBLIC_KEY = "RSAPublicKey";

    private static final String PRIVATE_KEY = "RSAPrivateKey";

    /**
     * RSA密钥长度默认为1024
     * 密钥长度必须是64的倍数
     * 方位在512~65536之间
     */
    private static final int KEY_SIZE = 512;
    
    
    /**
     * 签名
     *
     * @param data       待签名数据
     * @param privateKey 私钥
     * @return 数字签名
     * @throws Exception Exception
     */
    public static byte[] sign(byte[] data, byte[] privateKey) throws Exception {
        // 转换密钥材料
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        PrivateKey priKey = keyFactory.generatePrivate(keySpec);
        // 实例化
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);
        return signature.sign();
    }

    /**
     * 校验
     *
     * @param data      待校验数据
     * @param publicKey 公钥
     * @param sign      数字签名
     * @return 校验成功返回true, 失败返回false
     * @throws Exception Exception
     */
    public static boolean verify(byte[] data, byte[] publicKey, byte[] sign) throws Exception {
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
        KeyFactory factory = KeyFactory.getInstance(KEY_ALGORITHM);
        PublicKey pubKey = factory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);
        return signature.verify(sign);
    }

    /**
     * 获取私钥
     *
     * @param keyMap keyMap
     * @return 私钥
     */
    public static byte[] getPrivateKey(Map<String, Object> keyMap) {
        return ((Key) keyMap.get(PRIVATE_KEY)).getEncoded();
    }

    /**
     * 获取公钥
     *
     * @param keyMap keyMap
     * @return 公钥
     */
    public static byte[] getPublicKey(Map<String, Object> keyMap) {
        return ((Key) keyMap.get(PUBLIC_KEY)).getEncoded();
    }

    /**
     * 初始化密钥
     *
     * @return map
     * @throws Exception Exception
     */
    public static Map<String, Object> initKey() throws Exception {
        // 实例化密钥对生成器
        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(KEY_ALGORITHM);
        // 初始化密钥对生成器
        keyPairGen.initialize(KEY_SIZE);
        // 生成密钥对
        KeyPair keyPair = keyPairGen.generateKeyPair();
        // 公钥
        RSAPublicKey pubKey = (RSAPublicKey) keyPair.getPublic();
        // 私钥
        RSAPrivateKey priKey = (RSAPrivateKey) keyPair.getPrivate();
        Map<String, Object> keyMap = new HashMap<>();
        keyMap.put(PUBLIC_KEY, pubKey);
        keyMap.put(PRIVATE_KEY, priKey);
        return keyMap;
    }

    /**
     * 私钥签名
     *
     * @param data       待签名数据
     * @param privateKey 私钥
     * @return 十六进制签名字符串
     * @throws Exception Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        return Hex.encodeHexString(sign(data, getKey(privateKey)));
    }

    /**
     * 验证签名
     *
     * @param data      待验证数据
     * @param publicKey 公钥
     * @param sign      签名数据
     * @return true or false
     * @throws Exception Exception
     */
    public static boolean verify(byte[] data, String publicKey, String sign) throws Exception {
        return verify(data, getKey(publicKey), Hex.decodeHex(sign.toCharArray()));
    }

    
    /**
     * 获取私钥
     *
     * @param keyMap keyMap
     * @return 十六进制私钥
     */
    public static String getPrivateKeyStr(Map<String, Object> keyMap) {
        return Hex.encodeHexString(getPrivateKey(keyMap));
    }

    /**
     * 获取公钥
     *
     * @param keyMap keyMap
     * @return 十六进制公钥
     */
    public static String getPublicKeyStr(Map<String, Object> keyMap) {
        return Hex.encodeHexString(getPublicKey(keyMap));
    }

    /**
     * 获取密钥
     *
     * @param key 密钥
     * @return 密钥
     */
    public static byte[] getKey(String key) throws DecoderException {
        return Hex.decodeHex(key.toCharArray());
    }
    
}


总结

数字签名算法是公钥基础设施(Public Key Infrastructure,PKI)以及许多网络安全机制(SSL/TLS)的基础,遵从“私钥签名,公钥验签”的签名/验证方式。我们可以把数字签名算法近似看成是一种附加了公钥和私钥的消息摘要算法。

;