数字签名算法及JAVA实现案例

目录

简述

作用

签名流程

验签流程

常用数字签名算法

经典数字签名算法-RSA


简述

       数字签名算法可以看做是一种带有密钥的消息摘要算法,并且这种密钥包含了公钥、私钥。也就说,数字签名算法是非对称加密算法和消息摘要算法的结合体。

作用

  • 验证数据完整性
  • 认证数据来源
  • 抗否认

签名流程

  • 发送者通过hash算法计算原始消息(m)的消息摘要,记为h(m);
  • 发送者使用非对称私钥对h(m)进行加密,生成数字签名s;
  • 发送者将原始消息和数字签名(m,s)发送给接收者。

验签流程

  • 接收者通过hash算法计算原始消息的消息摘要,记为h(m);
  • 接收者使用发送者提供的非对称公钥对数字签名s进行解密,得到解密后报文H(m);
  • 接收者比较H(m)与h(m),如果一致则验签通过。

常用数字签名算法

  • RSA:基于整数因子分解问题
  • DSA:基于离散对数问题
  • ECDSA:基于离散对数问题

经典数字签名算法-RSA

        RSA数字签名算法是Diffie和Hellman提出数字签名思想后的第一个数字签名算法,是由Rivest、Shamir和Adleman三个人共同完成的,该签名算法源于RSA公钥密码算法的思想,将RSA公钥密码算法按照数字签名的方式运用。RSA数字签名算法是迄今为止应用最为广泛的数字签名算法。具体算法如下表: 

算法密钥长度默认长度签名长度备注
MD2withRSA

512 ~ 65536

(64的整数倍)

1024与密钥长度相同jdk7实现
MD5withRSA
SHA1withRSA
SHA224withRSA2048

Bouncy Castle实现 

SHA256withRSA
SHA384withRSA
SHA512withRSA
RIPEMD128withRSA
RIPEMD160withRSA

java实例:

import org.apache.commons.codec.binary.Base64;
import org.springframework.util.StopWatch;

import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * RSA算法签名实现
 *
 * @author chen.ww
 * @date 2021/10/19 11:02
 */
public class RsaAlgorithm {

    /**
     * 密钥算法
     */
    private static final String KEY_ALGORITHM = "RSA";

    /**
     * 签名算法
     */
    private static final String SIGN_ALGORITHM = "SHA256WithRSA";


    /**
     * 创建签名公、私钥
     *
     * @author chen.ww
     * @date 2021/10/19 11:40
     * @param
     * @return java.util.Map<java.lang.String,java.lang.String>
     */
    public static Map<String, String> createSecretKey() {
        try {
            StopWatch sw = new StopWatch();
            sw.start();
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);
            keyPairGenerator.initialize(512);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
            sw.stop();
            System.out.println(sw.getTotalTimeSeconds());

            Map<String, String> keyMap = new HashMap<String, String>(2);
            keyMap.put("pubKey", Base64.encodeBase64String(rsaPublicKey.getEncoded()));
            keyMap.put("priKey", Base64.encodeBase64String(rsaPrivateKey.getEncoded()));

            return keyMap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 创建签名
     *
     * @author chen.ww
     * @date 2021/10/19 11:40
     * @param data
     * @param signPriKey
     * @return java.lang.String
     */
    public static String createSign(String data, String signPriKey) {
        try {
            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(signPriKey));
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PrivateKey priKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);
            Signature signature = Signature.getInstance(SIGN_ALGORITHM);
            signature.initSign(priKey);
            signature.update(data.getBytes());
            return Base64.encodeBase64String(signature.sign());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 验证签名
     *
     * @author chen.ww
     * @date 2021/10/19 11:53
     * @param data
     * @param signData
     * @param signPubKey
     * @return boolean
     */
    public static boolean verifySign(String data, String signData, String signPubKey) {
        try {
            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(signPubKey));
            KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);
            Signature signature = Signature.getInstance(SIGN_ALGORITHM);
            signature.initVerify(publicKey);
            signature.update(data.getBytes());
            return signature.verify(Base64.decodeBase64(signData));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

}

数字签名标准算法-DSA

        1991年,美国国家标准技术协会公布了数字签名标准(Digital Signature Standard,DSS),于1994年正式生效,并作为美国联邦信息处理标准。DSS本质上是EIGamal数字签名算法,DSS使用的算法称为数字签名算法(Digital Signature Algorithm,DSA)。

        DSA算法与RSA算法都是数字证书中不可或缺的两种算法。两者不同的是,DSA算法仅包含数字签名算法,使用DSA算法的数字证书无法进行加密通信,而RSA算法既包含加密/解密算法,同时兼有数字签名算法。具体算法如下表:

算法密钥长度密钥长度默认值签名长度备注
SHA1withDSA

512 ~ 1024位

(密钥长度必须是64的倍数)

1024bit-Java7实现
SHA224withDSA
SHA256withDSA
SHA384withDSA
SHA512withDSA

java实例

import org.apache.commons.codec.binary.Base64;

import java.security.*;
import java.security.interfaces.DSAPrivateKey;
import java.security.interfaces.DSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * DSA算法签名实现
 *
 * @author chen.ww
 * @date 2021/10/19 14:30
 */
public class DsaAlgorithm {

    /**
     * 密钥算法
     */
    private static final String KEY_ALGORITHM = "DSA";

    /**
     * 签名算法
     */
    private static final String SIGN_ALGORITHM = "SHA256WithDSA";


    /**
     * 创建签名公、私钥
     *
     * @author chen.ww
     * @date 2021/10/19 11:40
     * @param
     */
    public static Map<String, String> initSecretKey() throws Exception {
        // 获取密钥对生成器实例
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KEY_ALGORITHM);

        // 初始化密钥长度,默认为1024位
        keyPairGenerator.initialize(1024);

        // 生成密钥对
        KeyPair keyPair = keyPairGenerator.generateKeyPair();

        // 生成DSA公钥、私钥
        DSAPublicKey dsaPublicKey = (DSAPublicKey) keyPair.getPublic();
        DSAPrivateKey dsaPrivateKey = (DSAPrivateKey) keyPair.getPrivate();

        // 将DSA公钥、私钥放入Map
        Map<String, String> keyMap = new HashMap<String, String>(2);
        keyMap.put("pubKey", Base64.encodeBase64String(dsaPublicKey.getEncoded()));
        keyMap.put("priKey", Base64.encodeBase64String(dsaPrivateKey.getEncoded()));

        return keyMap;
    }

    /**
     * 创建签名
     *
     * @author chen.ww
     * @date 2021/10/19 11:40
     * @param data
     * @param signPriKey
     * @return java.lang.String
     */
    public static String sign(String data, String signPriKey) throws Exception {
        // 获取签名密钥规范实例
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(Base64.decodeBase64(signPriKey));

        // 获取密钥工厂实例
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 根据密钥规范生成私钥
        PrivateKey priKey = keyFactory.generatePrivate(keySpec);

        // 获取签名实例
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);

        // 签名初始化
        signature.initSign(priKey);

        // 签名参数初始化
        signature.update(data.getBytes());

        // 签名并进行Base64编码
        return Base64.encodeBase64String(signature.sign());
    }

    /**
     * 验证签名
     *
     * @author chen.ww
     * @date 2021/10/19 11:53
     * @param data
     * @param signData
     * @param signPubKey
     * @return boolean
     */
    public static boolean verifySign(String data, String signData, String signPubKey) throws Exception {

        // 获取签名密钥规范实例
        X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(signPubKey));

        // 获取密钥工厂实例
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);

        // 根据密钥规范生成公钥
        PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);

        // 获取签名实例
        Signature signature = Signature.getInstance(SIGN_ALGORITHM);

        // 验签初始化
        signature.initVerify(publicKey);

        // 验签参数初始化
        signature.update(data.getBytes());

        // 验签
        return signature.verify(Base64.decodeBase64(signData));
    }

}

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值