当前位置: 代码网 > it编程>编程语言>Java > Java RSA加密工具类的设计与实现详解

Java RSA加密工具类的设计与实现详解

2025年02月10日 Java 我要评论
rsa算法是一种常用的非对称加密算法,它具有以下主要特点:1.非对称性:rsa 使用一对密钥——公钥和私钥。公钥用于加密,私钥用于解密,也可以反过来使用私钥签名、公钥验证。相对

rsa算法是一种常用的非对称加密算法,它具有以下主要特点:

1.非对称性:rsa 使用一对密钥——公钥和私钥。公钥用于加密,私钥用于解密,也可以反过来使用私钥签名、公钥验证。相对于对称加密的单一密钥,非对称性提高了安全性。

2.安全性高:rsa 的安全性依赖于大整数分解的数学难题。当前计算能力下,分解足够大的整数非常困难,因此 rsa 算法在合理的密钥长度下非常安全(通常建议使用 2048 位或更高的密钥长度)。

3.密钥长度可调:rsa 算法的密钥长度通常为 1024、2048 或 4096 位。密钥长度越长,安全性越高,但计算速度越慢。

4.加密与签名:rsa 不仅可以用于加密,还可以用于数字签名。用私钥签名的消息可以用公钥验证,确保消息的完整性和真实性,特别适合身份认证等场景。

5.加密速度较慢:与对称加密算法(如 aes)相比,rsa 的加密和解密速度较慢,因此它一般用于加密小数据或加密对称密钥(例如在 tls/ssl 中),然后使用对称加密算法进行数据传输。

6.不可逆性:使用公钥加密的数据只能通过对应的私钥解密,私钥加密(签名)也只能用公钥验证,保障了数据安全传输。

7.抗碰撞性:因为密钥的唯一性和大整数分解的困难,rsa 很难被伪造或碰撞。即使加密内容和公钥被获取,攻击者也很难推导出私钥。

rsa的典型应用场景

1.安全数据传输:如 ssl/tls 协议中,用于安全地传输加密的对称密钥。

2.身份验证和授权:如数字签名、电子签名中,保障签名的真实性和防篡改性。

3.数字证书:数字证书(如 https 中的证书)使用 rsa来提供加密和验证身份。

rsa 由于其高安全性和可靠性,广泛用于现代网络安全通信中。

直接上代码

import javax.crypto.cipher;
import java.security.*;
import java.security.interfaces.rsaprivatekey;
import java.security.spec.pkcs8encodedkeyspec;
import java.security.spec.rsapublickeyspec;
import java.security.spec.x509encodedkeyspec;
import java.util.base64;

/**
 * @author sakura
 * @date 2024/11/11 11:11
 */
public class rsautil {

    // 定义密钥长度
    private static final int key_size = 2048;
    private static final string algorithm = "rsa";

    /**
     * 生成rsa密钥对
     * @return keypair 包含公钥和私钥
     * @throws exception 如果生成失败
     */
    public static keypair generatekeypair() throws exception {
        keypairgenerator keypairgenerator = keypairgenerator.getinstance(algorithm);
        keypairgenerator.initialize(key_size);
        return keypairgenerator.generatekeypair();
    }

    /**
     * 使用公钥加密
     * @param data 待加密的数据
     * @param publickeystr base64编码的公钥字符串
     * @return 加密后的数据(base64编码)
     * @throws exception 如果加密失败
     */
    public static string encrypt(string data, string publickeystr) throws exception {
        publickey publickey = getpublickeyfrombase64(publickeystr);
        cipher cipher = cipher.getinstance(algorithm);
        cipher.init(cipher.encrypt_mode, publickey);
        byte[] encrypteddata = cipher.dofinal(data.getbytes());
        return base64.getencoder().encodetostring(encrypteddata);
    }

    /**
     * 使用私钥解密
     * @param encrypteddata base64编码的加密数据
     * @param privatekeystr base64编码的私钥字符串
     * @return 解密后的数据
     * @throws exception 如果解密失败
     */
    public static string decrypt(string encrypteddata, string privatekeystr) throws exception {
        privatekey privatekey = getprivatekeyfrombase64(privatekeystr);
        cipher cipher = cipher.getinstance(algorithm);
        cipher.init(cipher.decrypt_mode, privatekey);
        byte[] decodeddata = base64.getdecoder().decode(encrypteddata);
        byte[] decrypteddata = cipher.dofinal(decodeddata);
        return new string(decrypteddata);
    }

    /**
     * 将base64编码的公钥字符串转换为publickey对象
     * @param publickeystr base64编码的公钥字符串
     * @return publickey对象
     * @throws exception 如果转换失败
     */
    public static publickey getpublickeyfrombase64(string publickeystr) throws exception {
        byte[] decodedkey = base64.getdecoder().decode(publickeystr);
        x509encodedkeyspec keyspec = new x509encodedkeyspec(decodedkey);
        keyfactory keyfactory = keyfactory.getinstance(algorithm);
        return keyfactory.generatepublic(keyspec);
    }

    /**
     * 将base64编码的私钥字符串转换为privatekey对象
     * @param privatekeystr base64编码的私钥字符串
     * @return privatekey对象
     * @throws exception 如果转换失败
     */
    public static privatekey getprivatekeyfrombase64(string privatekeystr) throws exception {
        byte[] decodedkey = base64.getdecoder().decode(privatekeystr);
        pkcs8encodedkeyspec keyspec = new pkcs8encodedkeyspec(decodedkey);
        keyfactory keyfactory = keyfactory.getinstance(algorithm);
        return keyfactory.generateprivate(keyspec);
    }

    /**
     * 将publickey对象转换为base64编码的字符串
     * @param publickey publickey对象
     * @return base64编码的公钥字符串
     */
    public static string encodepublickeytobase64(publickey publickey) {
        return base64.getencoder().encodetostring(publickey.getencoded());
    }

    /**
     * 将privatekey对象转换为base64编码的字符串
     * @param privatekey privatekey对象
     * @return base64编码的私钥字符串
     */
    public static string encodeprivatekeytobase64(privatekey privatekey) {
        return base64.getencoder().encodetostring(privatekey.getencoded());
    }

    /**
     * 从 rsa 私钥计算出对应的公钥
     * @param privatekey rsa 私钥对象
     * @return publickey 对象
     * @throws exception 如果转换失败
     */
    public static publickey getpublickeyfromprivatekey(privatekey privatekey) throws exception {
        // 检查私钥类型是否为 rsa 私钥
        if (!(privatekey instanceof rsaprivatekey)) {
            throw new illegalargumentexception("the provided key is not an rsa private key.");
        }

        // 从私钥中提取模数和私钥指数
        rsaprivatekey rsaprivatekey = (rsaprivatekey) privatekey;
        java.math.biginteger modulus = rsaprivatekey.getmodulus();
        java.math.biginteger publicexponent = java.math.biginteger.valueof(65537); // 常用的公钥指数

        // 使用模数和公钥指数构造公钥规范
        rsapublickeyspec publickeyspec = new rsapublickeyspec(modulus, publicexponent);
        keyfactory keyfactory = keyfactory.getinstance(algorithm);

        // 根据规范生成公钥
        return keyfactory.generatepublic(publickeyspec);
    }

    public static void main(string[] args) throws exception {
        // 生成私钥和公钥
//        keypair keypair = generatekeypair();
//        string publickeystr = encodepublickeytobase64(keypair.getpublic());
//        string privatekeystr = encodeprivatekeytobase64(keypair.getprivate());
//        system.out.println(publickeystr);
//        system.out.println(privatekeystr);

        // 公钥对外暴露加密用
        string publickeystr = "miibijanbgkqhkig9w0baqefaaocaq8amiibcgkcaqeauggi4mbastlhktbqn6kkidskqfkmkiqvymd6dny5rcx9u8x97pjk/0pgrvu1xks4s8zwo6dgrxjx9tzao/2osxjjbiecj6ix47nx7vz6w30g7d+fou5pnd9iqtu99tcnx+jen5vgqda5nmdho4sg0oqsnquy4+jtx+qeu5x0nesvgho8a+dekabdgpyak6mh7x7n9cwtyryllmh0jqqc2zs0pkujshqtbo7ekpsmi82psbcipwmvibn1z4oxz0bujdgs2785o+91e00ep0ktnsvgqg6rkj2la7ezczmpcipkccxjeymnu+tiirkxijx/qrloonwjnqupxfy6handcwidaqab";
        // 私钥服务器保留解密用
        string privatekeystr = "miievqibadanbgkqhkig9w0baqefaascbkcwggsjageaaoibaqc6cajgxsbjmsernuqfqqogniqouoyskpxkypoodjlfzh1txf3ummr/smbg+7xeqzhlxncjp2bhgnf1pnqj/y6zgmkeh5ypqjfjufhu/ppbfqbsp5867mk132kq27321w3h6n6fm+cp1rk2ymc7iydshcw2ptlj6nph5b5tnhq16y8yc7wd50qobsmanjqtowftfs30jzpjhiuwahsoqpzbozsmrqmweq0e7ssq+yyjzaljsig9aa+ie3vng5fprtql2czbvzk773uttqq/qq2ey+cqdqsonysdsrlzmylykmqjzgmrgydt5mgiureilf9csug6fak2pq/f/lqfo0nzagmbaaecggeafvt+yw+h+99ckgtf/fyh0rk3kipxp4zefcv2cvsbueydzvrzxt67z3twek/dmosdvfvwutosfheae6oc5l7h1yxtthvtmzqddyophwr8kay88rqlkvtdt1wigkoif6kw7laj2ieo1dbvbk0vsmjsrligsu/ew+4lalpqn2cq4fwhtia5yv3vuuscv9/ri9jvyiwp2ltvus92mbkj8ahopmr+zrijjupxowldlsfa91bitksazga2xklrmwet1tnwhmeu4ihztjbfficugdxzduxwgxqm8lvmr0bsueriixryspq/dyobfefggi+lyelscp7dtgu0dwmlvrtdnks2aqkbgqdkwgz6egwkvu3qu3kylt6ggtqxcubfbdzyvjfrtxdda5rifun3nudwxnmzb+bzpr4g42p6ovqon8btmu3tncur/97oitfemrkkiirzcvdormmrxtmus6rmcdkchlzrfb5tzoha1boreefrv7qcoa1chekxemjol7p39tq8bqcnmwkbgqdql2/m2psil7wel5xc+ufrqfd4bl9ljmt9ywy0j1dyy/obrtgifpgnkeprah+o4s7ep2brtbfirg3/fnomghsmk501g3t/wbq3m0jsktn6/atdvcwkte4yszpjdvaajygtzorrz/opo77lbc8e7wxzedixm9efgtfbqcqsqa3ywqkbgeo/vo2152yf/b5snzw7q8fk0pm0cz0rew43fe35pyrlxn9onqsyx+enhgdz+ttb1fez5jsmpi8jwcbvufnq+wtb1vffghfn8b7pe1jctiu5ucapkgxun2vrljplvxi0f7zwntlrexyhzubzof2bcwxfaywdy4vxgzophqfuusxtaogaqels52z5c/5mm5oaiia98evoqv1gzf6b35/vbnapw2jbzznqmyqtqh0bylhobilo1eqc3kstwezkysixjbulydbibkhlhsyodxbjz7s3rm9rjy8dw5vst1anhevolsqi50ryfgfyzu6fwgdlbohebouqnggwxctptze4kzpje8ecgyea0ly49wpa3uqc8d2pehtlerhnkpbgbv+wbdrjolvoxirtzfsk00vnpgf4ocwieagxxmdi51dgxgq0bhu/ry3t1fai1y3yl0wljxutqps0ietcwl/gykgglrasm9cswry+nekx0l5shmt/0ow8ntfrdryokfgtlidlxx4lezhsuay=";
        // 带加密密码
        string password = "123456";

        // 加密后字符串
        string str = encrypt(password, publickeystr);
        system.out.println(str);
        // 解密字符串
        string str1 = decrypt(str, privatekeystr);
        system.out.println(str1);

        // 如果只知道私钥计算公钥
        publickey publickeyfromprivate = rsautil.getpublickeyfromprivatekey(getprivatekeyfrombase64(privatekeystr));

        // 打印公钥
        system.out.println(base64.getencoder().encodetostring(publickeyfromprivate.getencoded()));


    }
}

我们可以通过下面的方法生成密钥对

我们用生成的密钥对测试一下,可以看到能正常加解密以及通过私钥计算公钥

这里有一点要注意,尽管我们每次都使用同一个公钥进行加密,但是得到的加密字符串是不一样的,这是因为在 rsa 加密中,特别是使用 pkcs#1 v1.5 填充模式(即 rsa/ecb/pkcs1padding),pkcs#1 v1.5 会在加密前对明文进行特定的随机填充,确保每次加密结果不同。

下面是 rsa2 的(注意使用了"rsa/ecb/oaepwithsha-256andmgf1padding"填充,所以需要对接方也需要使用相同的填充方式才可以)

import javax.crypto.cipher;
import java.security.*;
import java.security.spec.pkcs8encodedkeyspec;
import java.security.spec.x509encodedkeyspec;
import java.util.base64;

/**
 * @author sakura
 * @date 2024/12/6 19:10
 */
public class rsa2util {

    // 定义密钥长度
    private static final int key_size = 1024; // 1024 2048 长度越大越安全但是数据长度越长
    private static final string algorithm = "rsa";

    /**
     * 生成rsa密钥对
     *
     * @return keypair 包含公钥和私钥
     * @throws exception 如果生成失败
     */
    public static keypair generatekeypair() throws exception {
        keypairgenerator keypairgenerator = keypairgenerator.getinstance(algorithm);
        keypairgenerator.initialize(key_size);
        return keypairgenerator.generatekeypair();
    }

    /**
     * 使用公钥加密
     *
     * @param data         待加密的数据
     * @param publickeystr base64编码的公钥字符串
     * @return 加密后的数据(base64编码)
     * @throws exception 如果加密失败
     */
    public static string encrypt(string data, string publickeystr) throws exception {
        publickey publickey = getpublickeyfrombase64(publickeystr);
        cipher cipher = cipher.getinstance("rsa/ecb/oaepwithsha-256andmgf1padding");
        cipher.init(cipher.encrypt_mode, publickey);
        byte[] encrypteddata = cipher.dofinal(data.getbytes());
        return base64.getencoder().encodetostring(encrypteddata);
    }

    /**
     * 使用私钥解密
     *
     * @param encrypteddata base64编码的加密数据
     * @param privatekeystr base64编码的私钥字符串
     * @return 解密后的数据
     * @throws exception 如果解密失败
     */
    public static string decrypt(string encrypteddata, string privatekeystr) throws exception {
        privatekey privatekey = getprivatekeyfrombase64(privatekeystr);
        cipher cipher = cipher.getinstance("rsa/ecb/oaepwithsha-256andmgf1padding");
        cipher.init(cipher.decrypt_mode, privatekey);
        byte[] decodeddata = base64.getdecoder().decode(encrypteddata);
        byte[] decrypteddata = cipher.dofinal(decodeddata);
        return new string(decrypteddata);
    }

    /**
     * 使用私钥对数据进行签名(sha256withrsa)
     *
     * @param data         待签名的数据
     * @param privatekeystr base64编码的私钥字符串
     * @return 签名后的数据(base64编码)
     * @throws exception 如果签名失败
     */
    public static string sign(string data, string privatekeystr) throws exception {
        privatekey privatekey = getprivatekeyfrombase64(privatekeystr);
        signature signature = signature.getinstance("sha256withrsa");
        signature.initsign(privatekey);
        signature.update(data.getbytes());
        byte[] signeddata = signature.sign();
        return base64.getencoder().encodetostring(signeddata);
    }

    /**
     * 使用公钥验证签名(sha256withrsa)
     *
     * @param data         原始数据
     * @param signeddata   base64编码的签名数据
     * @param publickeystr base64编码的公钥字符串
     * @return 验签结果,true为签名有效
     * @throws exception 如果验证失败
     */
    public static boolean verify(string data, string signeddata, string publickeystr) throws exception {
        publickey publickey = getpublickeyfrombase64(publickeystr);
        signature signature = signature.getinstance("sha256withrsa");
        signature.initverify(publickey);
        signature.update(data.getbytes());
        byte[] decodedsigneddata = base64.getdecoder().decode(signeddata);
        return signature.verify(decodedsigneddata);
    }

    public static publickey getpublickeyfrombase64(string publickeystr) throws exception {
        byte[] decodedkey = base64.getdecoder().decode(publickeystr);
        x509encodedkeyspec keyspec = new x509encodedkeyspec(decodedkey);
        keyfactory keyfactory = keyfactory.getinstance(algorithm);
        return keyfactory.generatepublic(keyspec);
    }

    public static privatekey getprivatekeyfrombase64(string privatekeystr) throws exception {
        byte[] decodedkey = base64.getdecoder().decode(privatekeystr);
        pkcs8encodedkeyspec keyspec = new pkcs8encodedkeyspec(decodedkey);
        keyfactory keyfactory = keyfactory.getinstance(algorithm);
        return keyfactory.generateprivate(keyspec);
    }

    public static string encodepublickeytobase64(publickey publickey) {
        return base64.getencoder().encodetostring(publickey.getencoded());
    }

    public static string encodeprivatekeytobase64(privatekey privatekey) {
        return base64.getencoder().encodetostring(privatekey.getencoded());
    }

    public static void main(string[] args) throws exception {
        // 生成私钥和公钥
        keypair keypair = generatekeypair();
        string publickeystr = encodepublickeytobase64(keypair.getpublic());
        string privatekeystr = encodeprivatekeytobase64(keypair.getprivate());

        system.out.println("公钥: " + publickeystr);
        system.out.println("私钥: " + privatekeystr);

        // 测试加密解密
        string data = "qaz123456.";
        string encrypteddata = encrypt(data, publickeystr);
        system.out.println("加密后: " + encrypteddata);
        string decrypteddata = decrypt(encrypteddata, privatekeystr);
        system.out.println("解密后: " + decrypteddata);

        // 测试签名和验签
        string signature = sign(data, privatekeystr);
        system.out.println("签名: " + signature);
        boolean isverified = verify(data, signature, publickeystr);
        system.out.println("验签结果: " + isverified);
    }
}

到此这篇关于java rsa加密工具类的设计与实现详解的文章就介绍到这了,更多相关java rsa加密工具类内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com