RSA非对称加解密详解

一、RSA简介

RSA加密是一种非对称加密算法,用于在不直接传递密钥的情况下完成解密,确保信息的安全性,避免直接传递密钥可能导致的破解风险。RSA加密使用一对密钥进行加解密,分别称为公钥和私钥,两者之间存在数学相关性。该加密算法的原理基于对极大整数进行因式分解的困难性来保证安全性。通常情况下,个人保存私钥,而公钥是公开的,可能同时由多人持有。

二、RSA加密和签名的区别

加密和签名都是为了保证安全性,但有略微不同。经常有人混淆加密和签名所使用的是私钥还是公钥,实际上这是对加密和签名的作用有所混淆。简单来说,加密是为了防止信息被泄露,而签名是为了防止信息被篡改。

RSA的加密过程如下:

  1. 甲生成一对密钥(公钥和私钥),私钥不公开,由甲自己保留。公钥是公开的,任何人都可以获取。
  2. 甲使用自己的私钥对消息进行签名,生成签名,并将带有签名的消息和消息本身一起传递给乙。
  3. 乙收到消息后,使用甲的公钥进行验签。如果验签结果与消息本身一致,就证明消息是甲发送的。

在这个过程中,只有两次传递过程。第一次是甲将带有签名的消息和消息本身传递给乙,第二次是乙获取甲的公钥。即使这两次传递都被敌方截获,也没有危险性,因为只有甲的私钥才能对消息进行签名,即使知道了消息内容,也无法伪造带有签名的回复给乙,从而防止了消息内容的篡改。在实际应用中,通常会同时使用加密和签名。例如,甲和乙都拥有一套自己的公钥和私钥。当甲要给乙发送消息时,先使用乙的公钥对消息进行加密,然后使用甲的私钥对加密的消息进行签名,从而既防止了消息内容的泄露,又防止了消息内容的篡改,更加保证了信息的安全性。

结论:甲和乙各自拥有一套公私钥,公钥用于加密,私钥用于解密,私钥用于签名,公钥用于验签。

三、加解密工具类

public class RSAUtil {

    /**
     * 数字签名,密钥算法
     */
    private static final String RSA_KEY_ALGORITHM = "RSA";

    /**
     * 数字签名签名/验证算法
     */
    private static final String SIGNATURE_ALGORITHM = "MD5withRSA";

/**
 * 生成秘钥对
 *
 * @return
 * @throws Exception
 */
public static KeyPair getKeyPair() throws Exception {
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(2048);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    return keyPair;
}

     

/**
 * 密钥转成byte[]
 *
 * @param key
 * @return
 */
public static byte[] decodeBase64(String key) {
    return Base64.decodeBase64(key);
}
/**
 * 公钥加密
 *
 * @param data      加密前的字符串
 * @param publicKey 公钥
 * @return 加密后的字符串
 * @throws Exception
 */
public static String encryptByPubKey(String data, String publicKey) throws Exception {
    byte[] pubKeyByte = RSAUtil.decodeBase64(publicKey);
    byte[] enSignByte = RSAUtil.decodeBase64(data);
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(pubKeyByte);
    KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
    PublicKey pubKey = keyFactory.generatePublic(x509KeySpec);
    Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());         
    cipher.init(Cipher.ENCRYPT_MODE, pubKey);
    return Base64.encodeBase64String(cipher.doFinal(enSignByte));
}
/**
 * 私钥解密
 *
 * @param secretText 解密前的字符串
 * @param privateKey 私钥
 * @return 解密后的字符串
 * @throws Exception
 */
public static String decryptByPriKey(String secretText, String privateKey) {
    try {
        byte[] priKey = RSAUtil.decodeBase64(privateKey);
        byte[] data= RSAUtil.decodeBase64(secretText);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(priKey);
        KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
        PrivateKey prKey = keyFactory.generatePrivate(pkcs8KeySpec);
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, prKey);
        return new String(cipher.doFinal(data));
    } catch (Exception e) {
        throw new RRException("解密失败", e);
    }
}
/**
 * RSA签名
 *
 * @param data   待签名数据
 * @param priKey 私钥
 * @return 签名
 * @throws Exception
 */
public static String sign(String data, String priKey) throws Exception {
    // 取得私钥
    PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(RSAUtil.decodeBase64(priKey));
    KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
    // 生成私钥
    PrivateKey privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
    // 实例化Signature
    Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
    // 初始化Signature
    signature.initSign(privateKey);
    // 更新
    signature.update(RSAUtil.decodeBase64(data));
    return Base64.encodeBase64String(signature.sign());
}

/**
 * RSA校验数字签名
 *
 * @param data   待校验数据
 * @param sign   数字签名
 * @param pubKey 公钥
 * @return boolean 校验成功返回true,失败返回false
 */
public static boolean verify(String data,String sign,String pubKey) throws Exception {
    // 实例化密钥工厂
    KeyFactory keyFactory = KeyFactory.getInstance(RSA_KEY_ALGORITHM);
    // 初始化公钥
    X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(RSAUtil.decodeBase64(pubKey));
    // 产生公钥
    PublicKey publicKey = keyFactory.generatePublic(x509KeySpec);
    // 实例化Signature
    Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
    // 初始化Signature
    signature.initVerify(publicKey);
    // 更新
    signature.update(RSAUtil.decodeBase64(data));
    // 验证
    return signature.verify(RSAUtil.decodeBase64(sign));
}

四、业务流程

以系统和第三方服务获取token为例:

系统:系统私钥、服务方公钥

第三方:系统公钥、服务方私钥

     1.第三方注册系统服务后,由系统下发给第三方私钥、系统公钥。

     2.第三方将需要加密的信息使用系统公钥加密,并将密文使用第三方私钥添加签名。

     3.第三方想要获取token,需要第三方将以上步骤中的密文、签名传给系统获取token的服务。

     4.系统使用第三方公钥验签,并使用系统私钥解密。

     5.验证第三方的密文和签名正确后,生成指定有效期的token并返回给第三方。

     6..第三方携带token访问业务数据即可。

 ————————————————
版权声明:本文为CSDN博主「暗夜里的一束光」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

  • 20
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值