使用弱签名算法md5withrsa java 例外_安全第16讲——数字签名

e35d77a70ab56b5af1d0f45577e2efc2.png

1、安全服务的类型

在ISO 7498-2:1989文档中,定义了安全服务的类型,安全服务包括五种类型:

鉴别(Authentication):保证通信的真实性;

访问控制(Access Control):防止网络资源被非授权地访问;

数据保密性(Data Confidentiality):对数据进行加密;

数据完整性(Data Integrity):防止数据被篡改或重放;

不可否认性(No-repudiation):防止发送方抵赖所传输的信息。

使用百度,可以轻松获得ISO 7498-2:1989文档,感兴趣的朋友可以自己学习。

2、数字签名的概念

签名这个词,我们日常生活中使用得比较多,一份文件、单据或合同,我们如果认可其中的条款,就可以签署我们的名字。一般情况下,不同的人笔迹不同,通过签名可以防止签署人否认所签署的内容。

数字签名的英文是Digital Signature。数字签名,就是只有信息发送方才能产生的、别人无法伪造的数字串。

数字签名需要实现鉴别(认证数据来源)、数据完整性、不可否认性三项安全服务。

3、数字签名的原理

假如我们是安全专家,要实现鉴别、数据完整性、不可否认这三项服务,我们可以这样来设计数字签名:

(1)使用消息摘要算法实现数据完整性;

(2)使用提供了公钥和私钥的算法,实现鉴别和不可否认两项服务。

实际上,数字签名也是这样实现的,下面就是数字签名的实现机制:

6e5c5b7dcfe78a614a87d181dee528de.png

简单地说,数字签名,其实就是支持公钥和私钥的消息摘要算法。

此外,上图只是描述了数字签名算法本身的实现。实际商用中,为了保证发送中的数据内容不被其他人获取到,甲方在发送数据前,会使用乙方的公钥对发送的数据加密,乙方收到数据后会首先用自己的私钥对加密数据进行解密。

4、常用的数字签名算法

业界比较常用的数字签名算法有三种:RSA、DSA、ECDSA。

RSA前面讲解过,是一种非对称加密算法。其实RSA也可以用作数字签名算法。

DSA算法是在RSA之后提出的数字签名算法,和RSA相比,DSA只能用于数字签名,不能用于数据的加密和解密。

ECDSA算法则是ECC算法和DSA算法的结合,相比来说,它有计算快、强度高、签名短的优点。

5、使用Java语言实现数字签名功能

5.1 JDK和Bouncy Castle提供的数字签名算法

在JDK中,提供了下面的签名算法:

MD2WithRSAMD5WithRSASHA1WithRSASHA1WithDSA

在Bouncy Castle中还提供了下面的签名算法:

SHA224WithRSASHA256WithRSASHA384WithRSASHA512WithRSASHA224WithDSASHA256WithDSASHA384WithDSASHA512WithDSASHA1WithECDSASHA224WithECDSASHA256WithECDSASHA384WithECDSASHA512WithECDSA

这些算法,从名称就可以看出数字签名算法是RSA、DSA还是ECDSA,以及数字签名算法基于的消息摘要算法。

下面我们使用JDK提供的MD5WithRSA算法,编写一个实验程序。

5.2 使用IDEA建立project_ds工程,然后在project_ds工程下建立digital_signature模块:

09a2199f5b7695a1bfe2a4f7dcc261b5.png

5.3 创建一个Sender类

创建Sender类的对象实例时,提供原始数据信息和私钥,Sender对象则生成签名。

Sender类的代码如下:

package com.flying.digital_signature;import java.security.KeyFactory;import java.security.PrivateKey;import java.security.Signature;import java.security.interfaces.RSAPrivateKey;import java.security.spec.PKCS8EncodedKeySpec;import java.util.Base64;public class Sender {    private RSAPrivateKey rsaPrivateKey;    private byte[] originBytes;    public Sender(RSAPrivateKey rsaPrivateKey, byte[] originBytes){        this.rsaPrivateKey = rsaPrivateKey;        this.originBytes = originBytes;    }    public byte[] getSignature(){        byte[] signatureBytes = null;        try {            PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(rsaPrivateKey.getEncoded());            KeyFactory keyFactory = KeyFactory.getInstance("RSA");            PrivateKey privateKey = keyFactory.generatePrivate(pkcs8EncodedKeySpec);            Signature signature = Signature.getInstance("MD5WithRSA");            signature.initSign(privateKey);            signature.update(originBytes);            signatureBytes = signature.sign();            System.out.println("digital signature is : " + Base64.getEncoder().encodeToString(signatureBytes));        }catch (Exception ex){            ex.printStackTrace();        }        return signatureBytes;    }}

5.4 创建一个Receiver类

创建Receiver类的对象实例时,提供原始数据信息、公钥和签名,Receiver对象则验证签名。

Receiver类的代码如下:

package com.flying.digital_signature;import java.security.KeyFactory;import java.security.PublicKey;import java.security.Signature;import java.security.interfaces.RSAPublicKey;import java.security.spec.X509EncodedKeySpec;public class Receiver {    private RSAPublicKey rsaPublicKey;    private byte[] originalBytes;    private byte[] signatureBytes;    public Receiver(RSAPublicKey rsaPublicKey, byte[] originalBytes, byte[] signatureBytes){        this.rsaPublicKey = rsaPublicKey;        this.originalBytes = originalBytes;        this.signatureBytes = signatureBytes;    }    public void checkSignature(){        try {            X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(rsaPublicKey.getEncoded());            KeyFactory keyFactory = KeyFactory.getInstance("RSA");            PublicKey publicKey = keyFactory.generatePublic(x509EncodedKeySpec);            Signature signature = Signature.getInstance("MD5WithRSA");            signature.initVerify(publicKey);            signature.update(originalBytes);            System.out.println("Signature verify result: " + signature.verify(signatureBytes));        }catch (Exception ex){            ex.printStackTrace();        }    }}

5.5 修改main方法

在main方法中生成公钥、私钥和原始数据信息,并调用Sender和Receiver类的功能来测试数字签名。

main方法在DigitalSignatureApplication类中定义,DigitalSignatureApplication类的代码如下:

package com.flying.digital_signature;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.util.Base64;@SpringBootApplicationpublic class DigitalSignatureApplication {    public static void main(String[] args) {        SpringApplication.run(DigitalSignatureApplication.class, args);        try {            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");            keyPairGenerator.initialize(512);            KeyPair keyPair = keyPairGenerator.generateKeyPair();            RSAPublicKey rsaPublicKey = (RSAPublicKey)keyPair.getPublic();            RSAPrivateKey rsaPrivateKey = (RSAPrivateKey)keyPair.getPrivate();            byte[] originBytes = "abcdefghi".getBytes();            System.out.println("RSA public key is : " + Base64.getEncoder().encodeToString(rsaPublicKey.getEncoded()));            System.out.println("RSA private key is : " + Base64.getEncoder().encodeToString(rsaPrivateKey.getEncoded()));            System.out.println("Original bytes is : " + Base64.getEncoder().encodeToString(originBytes));            Sender sender = new Sender(rsaPrivateKey, originBytes);            byte[] signatureBytes = sender.getSignature();            Receiver receiver = new Receiver(rsaPublicKey, originBytes, signatureBytes);            receiver.checkSignature();        }catch (Exception ex){            ex.printStackTrace();        }    }}

5.6 这是程序某次运行的结果

RSA public key is : MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKB2iMFgDsOjPVi86JLkJaNxjQWinPU4ZOSqjtxUQWKtTo2ckNvi9gVmEQTYLinkjJ+VkD30r2QSM3YeML5jjbUCAwEAAQ==RSA private key is : MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAoHaIwWAOw6M9WLzokuQlo3GNBaKc9Thk5KqO3FRBYq1OjZyQ2+L2BWYRBNguKeSMn5WQPfSvZBIzdh4wvmONtQIDAQABAkBJZ3AP5f1bCaXanjBWYf/F0QAN/+GFXBLreAp6SCDRHnM6cJoKA1un87Wijr3MIFylWgNtSWcGBj8gxE6pmLSBAiEA61s0c7UfV1GRjQ7Txb0GrUBssT8cBnDXs6Jgd4NFBekCIQCuiaSQ6xTc8NaenhigE0G9B7tB6uRfc3lNdI2Iv0ZN7QIhAIMye2HI5KizUrTUQB8piTBJCo4fxQqeGtALQ0U8Ct0JAiEAgA9DrISfUSBwB/9th/25DQ3gKhRDLXmXNepfckcNOV0CIQDT5OHxJU+6yhViiqdoazEP63cIsg4NuunJrBRytwIEsA==Original bytes is : YWJjZGVmZ2hpdigital signature is : Ir1PMMzSEeYq7qgH9KtClBRVPifKxSq9cdYSrL+GX6ztwJztY0t5GCnAo7pHg+GOQdSnHoXXXeZEv4FxK2BMEA==Signature verify result: true

可以看到,程序运行成功。

整个程序只有三个类,上面的代码是完整的,如果你感兴趣,可以自己在电脑上调试运行。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Java实现采用1024bit长度密钥的RSA签名方式,加密算法使用MD5WithRSA,计算签名和验签的时候需要使用GBK编码的示例代码: ```java import java.nio.charset.StandardCharsets; import java.security.KeyFactory; import java.security.PrivateKey; import java.security.PublicKey; import java.security.Signature; import java.security.spec.PKCS8EncodedKeySpec; import java.security.spec.X509EncodedKeySpec; public class RSASignature { // 加载私钥 private static PrivateKey loadPrivateKey(String privateKeyStr) throws Exception { byte[] privateKeyBytes = Base64.decode(privateKeyStr); PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(privateKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePrivate(pkcs8KeySpec); } // 加载公钥 private static PublicKey loadPublicKey(String publicKeyStr) throws Exception { byte[] publicKeyBytes = Base64.decode(publicKeyStr); X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(publicKeyBytes); KeyFactory keyFactory = KeyFactory.getInstance("RSA"); return keyFactory.generatePublic(x509KeySpec); } // MD5WithRSA数字签名 public static byte[] sign(String data, String privateKeyStr) throws Exception { PrivateKey privateKey = loadPrivateKey(privateKeyStr); Signature signature = Signature.getInstance("MD5WithRSA"); signature.initSign(privateKey); signature.update(data.getBytes(StandardCharsets.GBK)); return signature.sign(); } // MD5WithRSA数字签名验证 public static boolean verify(String data, byte[] sign, String publicKeyStr) throws Exception { PublicKey publicKey = loadPublicKey(publicKeyStr); Signature signature = Signature.getInstance("MD5WithRSA"); signature.initVerify(publicKey); signature.update(data.getBytes(StandardCharsets.GBK)); return signature.verify(sign); } public static void main(String[] args) throws Exception { // 待签名的数据 String data = "待签名的数据"; // 私钥 String privateKeyStr = "MIICXQIBAAKBgQDQz8t7jv2J2O3/6K4s5w2o+1rPnXy7Yd9b5T5psT1y9t2JQeN7u8o7FpKk3M0W1LrPa0GZDf9kDzU7JEr4yvIL1FZBnYK6sCp+P7Wt2dG0yq8a8m7ZLYvN1Jj+H4+M2vBNQGJ6uVQh8yKZ6Q/2m+EEJnJp4DjH/0CmK2yFjz7SjQIDAQABAoGBAIr2+UJ8t3iDjugg6d9wq9TjZa+qvg0tIuQvJrP6oXh0DyMIQ1ASlRkYnVpYiM4xi3/2tE5L0GnNSB2f5cP3N6LnoBBWb/0DLwE9k6E3Uz5YyZkzCSfO5I/6xUy/xU+OJ2vJWZi+T+M4b6Vz1NpGUK2QtDSZq9Cvpyj/xpJ8x8CBAkEA/9aMx9xjYBqC2sP6jwJf0C4kIvzOJcV9uXjOyUejg3a/5RG8F+5j69yOIGs2aWxRrC8lH7fRrKJLuR3R4KwKZQJBAMj8/5IN5kL4yJz6vR0z6a5Dy8kQzZrR3HJlW2cVxQg5uH3a8zrjfGf3B+4e1Dn6a8Nq1F9zKztf+Ll5S3j8bZ8CQQCQr4QlJpX4QqoX4W0sNYI1jg3N5X3N9tNjsCJeQzlRQlFQv4Vu4f+/+wWzD+q2hIbJUJU0lC5gq9v6XNDL5zBAkEAt4semjy6bX1v8YRyQkLzXZtGnOeB6r5Z+DQzK6QVfzJnC7Y8H+txbVh1OT1Mjg0iE6sX7r2gkxjm3PjZ1x6v7QJBAJ4dWzrNfKXJY3z8xw6Xq8z3qW8QXhQaP7Iz3x7PnLhW8S2tQqzSfQlZbDj/Tz5dN0V4VjWlT7nYw2mSjKZT7jI="; // 公钥 String publicKeyStr = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQz8t7jv2J2O3/6K4s5w2o+1rPnXy7Yd9b5T5psT1y9t2JQeN7u8o7FpKk3M0W1LrPa0GZDf9kDzU7JEr4yvIL1FZBnYK6sCp+P7Wt2dG0yq8a8m7ZLYvN1Jj+H4+M2vBNQGJ6uVQh8yKZ6Q/2m+EEJnJp4DjH/0CmK2yFjz7SjQIDAQAB"; // 进行MD5WithRSA数字签名 byte[] sign = sign(data, privateKeyStr); System.out.println("数字签名:" + Base64.encode(sign)); // 进行MD5WithRSA数字签名验证 boolean verifyResult = verify(data, sign, publicKeyStr); System.out.println("数字签名验证结果:" + verifyResult); } } ``` 需要注意的是,在进行数字签名和验签的时候,需要使用相同的编码方式,这里使用的是GBK编码。同时,签名和验签的过程中,都需要对待签名的数据先进行MD5哈希计算。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值