非对称加密算法 --- RSA签名算法

RSA原理

通过一定的规则,生成公钥和私钥,公钥和私钥总是成对出现。
公钥可以公开出去,任何人都可以知道。
私钥只有自己知道。
RSA算法能保证,公钥加密后的密文,只有对应的私钥才能解密。或者,私钥加密后的密文,只有对应的公钥才能解密。
而且不能通过公钥得到私钥,也不能通过私钥算出公钥。

关于为什么公私钥直接不能互相转换,请看我之前的一篇文章:
非对称加密算法之RSA算法实现

RSA应用场景

RSA加密场景

A给B传一条消息,要保证哪怕消息被截取了,也不能让别人知道消息的真正含义。
1、B生成公钥和私钥,私钥自己保留,把公钥传给A
2、A用公钥加密要传的消息,然后把密文传给B
3、B用私钥解密密文,得到真正的消息。
这样做的好处是,就算有人把中间的密文和公钥都拿到了,他也获取不到明文。
因为RSA的特点就是公钥加密,必须用对应的私钥才能解密。而私钥一直是B保管。

RSA签名场景

同样的,A给B传一条消息,可以明文传输,但要保证,B收到的,就是A发出的,不能被别人恶意修改。
1、B生成公钥和私钥,私钥自己保留,把公钥传给A
2、A用公钥对要传的信息进行签名,形成签名信息。A将签名信息和明文一起传给B
3、B收到明文和签名后,用私钥对签名进行验证,如果验证通过,则证明B收到的明文就是A发出的明文。
这样做的好处是,哪怕中间有人截取到明文和签名,只要修改任意一个,B那里最终都不会验证通过。

RSA加解密和签名算法的java实现


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

import javax.crypto.Cipher;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

public class TestRsa {

    // 私钥对象
    private PrivateKey sk;
    // 公钥对象
    private PublicKey pk;

    // 私钥字符串
    private String privateKeyStr;
    // 公钥字符串
    private String publicKeyStr;

    // 初始化公钥私钥
    public TestRsa() throws NoSuchAlgorithmException {
        KeyPairGenerator rsa = KeyPairGenerator.getInstance("RSA");
        rsa.initialize(1024);
        KeyPair keyPair = rsa.generateKeyPair();
        sk = keyPair.getPrivate();
        pk = keyPair.getPublic();

        privateKeyStr = new String(Base64.encodeBase64(sk.getEncoded()));
        publicKeyStr = new String(Base64.encodeBase64(pk.getEncoded()));
    }

    // 公钥加密
    public String encrypt(String str, String publicKey) throws Exception {
        //base64编码的公钥
        byte[] decoded = Base64.decodeBase64(publicKey);
        RSAPublicKey pubKey = (RSAPublicKey) KeyFactory.getInstance("RSA").generatePublic(new X509EncodedKeySpec(decoded));
        //RSA加密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, pubKey);
        String outStr = Base64.encodeBase64String(cipher.doFinal(str.getBytes("UTF-8")));
        return outStr;
    }

    // 私钥解密
    public String decrypt(String str, String privateKey) throws Exception {
        //64位解码加密后的字符串
        byte[] inputByte = Base64.decodeBase64(str.getBytes("UTF-8"));
        //base64编码的私钥
        byte[] decoded = Base64.decodeBase64(privateKey);
        RSAPrivateKey priKey = (RSAPrivateKey) KeyFactory.getInstance("RSA").generatePrivate(new PKCS8EncodedKeySpec(decoded));
        //RSA解密
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, priKey);
        String outStr = new String(cipher.doFinal(inputByte));
        return outStr;
    }

    // 私钥签名
    public String sign(String str) throws Exception {
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initSign(this.sk);
        signature.update(str.getBytes());
        byte[] sign = signature.sign();
        return new String(Base64.encodeBase64(sign));
    }

    // 公钥验证
    public boolean verify(String str, String sign) throws Exception {
        Signature signature = Signature.getInstance("SHA1withRSA");
        signature.initVerify(this.pk);
        signature.update(str.getBytes());
        return signature.verify(Base64.decodeBase64(sign.getBytes("UTF-8")));
    }


    public static void main(String[] args) throws Exception {
        String str = "这是加密前的明文";

        TestRsa testRsa = new TestRsa();
        String encrypt = testRsa.encrypt(str, testRsa.publicKeyStr);
        System.out.println("加密后的密文:" + encrypt);

        String decrypt = testRsa.decrypt(encrypt, testRsa.privateKeyStr);
        System.out.println("解密后的明文:" + decrypt);

        // 签名
        String sign = testRsa.sign(str);
        System.out.println("签名结果:" + sign);

        // 验证
        boolean verify = testRsa.verify(str, sign);
        System.out.println("验证结果:" + verify);// true

        // 验证反例
        String str2 = "这是被恶意修改过的伪原文";
        boolean verify2 = testRsa.verify(str2, sign);
        System.out.println("验证结果2:" + verify2);// false

    }
}

最终结果:

加密后的密文:Pc/lj5beiojR1BIiEG1O9fooVOmwDgQixN9qX19ofU3Myq5iOViMqEM2lUZ+tmihms3BrLahZze2FeZVR1wrTSk24ZTK5rjKtL1GZLsQI6m/wNXmk9bA5gYbcR6ivZSTEw5a9+77mcAFuAgpeSmSM825NOTAt7epZeUt7i9FPNY=
解密后的明文:这是加密前的明文
签名结果:Oe2XuGCb5mBwE4JTRPcemipOSuXEsw+hxido6r3/FSyDhx371sdg6/iRYQk6C2FuOqOpltWBJ4gA7x+VfJSJoA94+EIu5WxOaupaPumzNrsfhC/ZtYRUw0PfUvR5j232LH5bfA+Dh6pGbo1gu6qMVf8EtS63BoGHi9SYP068uss=
验证结果:true
验证结果2false
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值