JavaRSA加密工具类的设计与实现详解,
JavaRSA加密工具类的设计与实现详解,
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加密工具类内容请搜索3672js教程以前的文章或继续浏览下面的相关文章希望大家以后多多支持3672js教程!
您可能感兴趣的文章:- 前端RSA加密java后端解密示例代码
- 详解RSA加密算法的原理与Java实现
- 教你用Java实现RSA非对称加密算法
- Java实现RSA加密工具类
- java 非对称加密算法RSA实现详解
- Java实现的RSA加密解密算法示例
用户点评