廖雪峰Java10加密与安全-5签名算法-1RSA签名算法

1.数字签名

甲在发送加密消息的时候,还要发送自己的签名,而这个签名是用甲的privateKey计算的;而乙要验证这个签名是否是合法的,会用甲的publicKey去验证,如果验证成功,这个消息确实是甲发送的。

数字签名:

  • 发送方用自己的私钥对消息进行签名:sig = signature(privateKey, "message")
  • 接收方用发送方的公钥验证签名是否有效:boolean vaild = verify(publicKey, sig,"message")。如果publicKey,sig,message任何一个发生改变,签名都是无效的。
  • 数字签名≈混入了私钥/公钥的摘要

数字签名的目的:

  • 确认信息是某个发送方发送的。只有发送方用自己的privateKey签名,其他人才能用发送方的publicKey验证签名。
  • 发送方不能抵赖他发送了消息。因为用谁的publicKey成功验证的签名,就说明一定是他用自己的privateKey签名的。所以privateKey相当于用户的身份。
  • 数据在传输过程中没有被修改

常用数字签名方法:

  • MD5withRSA
  • SHA1withRSA
  • SHA256withRSA

2代码示例

package com.testList;

import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Base64;

public class SecRSASignature {
    PrivateKey sk;//定义私钥
    PublicKey pk;//定义公钥
    //构造方法1:获取公钥/私钥对
    public SecRSASignature() throws GeneralSecurityException{
        KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");//使用RSA
        kpGen.initialize(1024);//初始化为1024字节
        KeyPair kp = kpGen.generateKeyPair();//生成公钥、私钥
        this.sk = kp.getPrivate();
        this.pk = kp.getPublic();
    }
    //构造方法2:从保存的字节中提取公钥/私钥
    public SecRSASignature(byte[] pk,byte[] sk) throws GeneralSecurityException{
        KeyFactory kf = KeyFactory.getInstance("RSA");
        X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(pk);
        this.pk = kf.generatePublic(pkSpec);
        PKCS8EncodedKeySpec skSpec = new PKCS8EncodedKeySpec(sk);
        this.sk = kf.generatePrivate(skSpec);
    }
    //返回私钥的byte数组
    public byte[] getPrivateKey(){
        return this.sk.getEncoded();
    }
    //返回公钥的byte数组
    public byte[] getPublicKey(){
        return this.pk.getEncoded();
    }
    //获取签名
    public byte[] sign(byte[] message) throws GeneralSecurityException{
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(this.sk);
        signature.update(message);
        return signature.sign();
    }
    //传入message,使用公钥与签名sign进行校验
    public boolean verify(byte[] message,byte[] sign) throws GeneralSecurityException{
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(this.pk);
        signature.update(message);
        return signature.verify(sign);
    }
    public static void main(String[] args) throws Exception{
        byte[] message = "Hello,使用SHA1withRSA算法进行数字签名".getBytes("utf-8");

        SecRSASignature rsas = new SecRSASignature();
        byte[] sign = rsas.sign(message);
        System.out.println("sign:"+ Base64.getEncoder().encodeToString(sign));

        //使用原有的message、sign进行校验
        boolean verified1 = rsas.verify(message,sign);
        System.out.println("verify:"+verified1);
        //创建新的SecRSASiginature对象,使用原有的sign与新对象进行校验
        boolean verified2 = new SecRSASignature().verify(message,sign);
        System.out.println("verfied with another public key:"+verified2);
        //修改message信息
        message[0]=100;
        boolean verifed3 = rsas.verify(message,sign);
        System.out.println("verified with changed message: "+verifed3);
    }
}

3.总结:

  • 数字签名就是发送方的私钥对原始数据进行签名
  • 只有用发送方公钥才能通过签名验证
    * 防止伪造发送方
    * 防止抵赖发送过信息
    * 防止信息在传输过程中被修改
  • 常用算法:MD5withRSA/SHA1withRSA/SHA256widthRSA
posted on 2019-05-16 22:51  singleSpace  阅读(346)  评论(0编辑  收藏  举报