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)的基础,遵从“私钥签名,公钥验签”的签名/验证方式。我们可以把数字签名算法近似看成是一种附加了公钥和私钥的消息摘要算法。

  • 2
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
RSA算法是非对称加密算法,可以用来进行数字签名数字签名是一种将数据和私钥结合起来的技术,用于验证该数据的来源和完整性。 以下是JAVA实现RSA算法数字签名的示例代码: ```java import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; public class RSASignatureExample { public static void main(String[] args) throws Exception { // 生成RSA密钥对 KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA"); keyPairGen.initialize(2048); KeyPair keyPair = keyPairGen.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); PublicKey publicKey = keyPair.getPublic(); // 待签名的数据 String data = "Hello, world!"; // 生成数字签名 Signature signature = Signature.getInstance("SHA256withRSA"); signature.initSign(privateKey); signature.update(data.getBytes()); byte[] signatureBytes = signature.sign(); // 验证数字签名 Signature verifySignature = Signature.getInstance("SHA256withRSA"); verifySignature.initVerify(publicKey); verifySignature.update(data.getBytes()); boolean result = verifySignature.verify(signatureBytes); System.out.println("数字签名验证结果:" + result); } } ``` 在此示例中,首先使用RSA算法生成了一个2048位的密钥对。然后,使用私钥对待签名的数据进行签名,并将签名结果存储在字节数组中。接着,使用公钥对签名结果进行验证,以验证签名的正确性。最后,输出签名验证结果。 需要注意的是,签名和验证过程中所使用的算法必须一致,否则会导致验证失败。在此示例中,我们使用SHA256withRSA算法进行签名和验证。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值