JAVA的RSA加密算法工具类
须要用到一个jar
须要注意的问题
JS用同一秘钥生成的密文用java解密出来是逆序的,即js加密123456用java解密出来是654321,原因未知,须要解密js加密的密文请使用后缀为byJs的方法。
HexUtil.java
- > 1];
- // two characters form the hex value.
- for (int i = 0, j = 0; j >> 4];
- out[j++] = toDigits[0x0F & data[i]];
- }
- return out;
- }
- }
- " data-snippet-id="ext.95f10f39d6786f444dfe7f63f74db7ec" data-snippet-saved="false" data-csrftoken="ccbrPHwP-WyjtuyjuHUnUI5J2rTNMwFME_ks" data-codota-status="done">
package cn.edu.zafu.utils;
public class HexUtil {
private static final char[] DIGITS_LOWER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
private static final char[] DIGITS_UPPER = { '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
public static byte[] decodeHex(final char[] data) throws Exception {
final int len = data.length;
if ((len & 0x01) != 0) {
throw new Exception("Odd number of characters.");
}
final byte[] out = new byte[len >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(data[j], j) << 4;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (byte) (f & 0xFF);
}
return out;
}
protected static int toDigit(final char ch, final int index)
throws Exception {
final int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new Exception("Illegal hexadecimal character " + ch
+ " at index " + index);
}
return digit;
}
public static char[] encodeHex(final byte[] data) {
return encodeHex(data, true);
}
public static char[] encodeHex(final byte[] data, final boolean toLowerCase) {
return encodeHex(data, toLowerCase ? DIGITS_LOWER : DIGITS_UPPER);
}
protected static char[] encodeHex(final byte[] data, final char[] toDigits) {
final int l = data.length;
final char[] out = new char[l << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < l; i++) {
out[j++] = toDigits[(0xF0 & data[i]) >>> 4];
out[j++] = toDigits[0x0F & data[i]];
}
return out;
}
}
StringUtil.java
package cn.edu.zafu.utils;
public class StringUtil {
public static boolean isBlank(final CharSequence cs) {
int strLen;
if (cs == null || (strLen = cs.length()) == 0) {
return true;
}
for (int i = 0; i < strLen; i++) {
if (Character.isWhitespace(cs.charAt(i)) == false) {
return false;
}
}
return true;
}
public static String reverse(final String str) {
if (str == null) {
return null;
}
return new StringBuilder(str).reverse().toString();
}
}
FileUtil.java
package cn.edu.zafu.utils;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class FileUtils {
public static FileInputStream openInputStream(File file) throws IOException {
if (file.exists()) {
if (file.isDirectory()) {
throw new IOException("File '" + file
+ "' exists but is a directory");
}
if (file.canRead() == false) {
throw new IOException("File '" + file + "' cannot be read");
}
} else {
throw new FileNotFoundException("File '" + file
+ "' does not exist");
}
return new FileInputStream(file);
}
public static FileOutputStream openOutputStream(File file)
throws IOException {
return openOutputStream(file, false);
}
public static FileOutputStream openOutputStream(File file, boolean append)
throws IOException {
if (file.exists()) {
if (file.isDirectory()) {
throw new IOException("File '" + file
+ "' exists but is a directory");
}
if (file.canWrite() == false) {
throw new IOException("File '" + file
+ "' cannot be written to");
}
} else {
File parent = file.getParentFile();
if (parent != null) {
if (!parent.mkdirs() && !parent.isDirectory()) {
throw new IOException("Directory '" + parent
+ "' could not be created");
}
}
}
return new FileOutputStream(file, append);
}
public static void closeQuietly(InputStream input) {
closeQuietly((Closeable) input);
}
public static void closeQuietly(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (IOException ioe) {
// ignore
}
}
}
RSAUtil.java
package cn.edu.zafu.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyFactory;
import java.security.KeyPairGenerator;
import java.security.Provider;
import java.security.PublicKey;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidParameterException;
import java.security.interfaces.RSAPublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.RSAPublicKeySpec;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
* RSA算法加密/解密工具类。
*
*
*/
public abstract class RSAUtil {
/** 算法名称 */
private static final String ALGORITHOM = "RSA";
/**保存生成的密钥对的文件名。 */
private static final String RSA_PAIR_FILENAME = "/__RSA_PAIR.txt";
/** 密钥大小 */
private static final int KEY_SIZE = 1024;
/** 默认的安全服务提供者 */
private static final Provider DEFAULT_PROVIDER = new BouncyCastleProvider();
private static KeyPairGenerator keyPairGen = null;
private static KeyFactory keyFactory = null;
/** 缓存的密钥对。 */
private static KeyPair oneKeyPair = null;
private static File rsaPairFile = null;
static {
try {
keyPairGen = KeyPairGenerator.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
keyFactory = KeyFactory.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
} catch (NoSuchAlgorithmException ex) {
System.out.println(ex.getMessage());
}
rsaPairFile = new File(getRSAPairFilePath());
}
private RSAUtil() {
}
/**
* 生成并返回RSA密钥对。
*/
private static synchronized KeyPair generateKeyPair() {
try {
keyPairGen.initialize(KEY_SIZE, new SecureRandom(new SimpleDateFormat("yyyyMMdd").format(new Date()).getBytes()));
oneKeyPair = keyPairGen.generateKeyPair();
saveKeyPair(oneKeyPair);
return oneKeyPair;
} catch (InvalidParameterException ex) {
System.out.println("KeyPairGenerator does not support a key length of " + KEY_SIZE + ".");
ex.printStackTrace();
} catch (NullPointerException ex) {
System.out.println("RSAUtils#KEY_PAIR_GEN is null, can not generate KeyPairGenerator instance.");
ex.printStackTrace();
}
return null;
}
/**
* 返回生成/读取的密钥对文件的路径。
*/
private static String getRSAPairFilePath() {
String urlPath = RSAUtil.class.getResource("/").getPath();
return (new File(urlPath).getParent() + RSA_PAIR_FILENAME);
}
/**
* 若须要创建新的密钥对文件,则返回 {@code true}。否则 {@code false}。
*/
private static boolean isCreateKeyPairFile() {
// 是否创建新的密钥对文件
boolean createNewKeyPair = false;
if (!rsaPairFile.exists() || rsaPairFile.isDirectory()) {
createNewKeyPair = true;
}
return createNewKeyPair;
}
/**
* 将指定的RSA密钥对以文件形式保存。
*
* @param keyPair 要保存的密钥对。
*/
private static void saveKeyPair(KeyPair keyPair) {
FileOutputStream fos = null;
ObjectOutputStream oos = null;
try {
fos = FileUtils.openOutputStream(rsaPairFile);
oos = new ObjectOutputStream(fos);
oos.writeObject(keyPair);
} catch (Exception ex) {
ex.printStackTrace();
} finally {
FileUtils.closeQuietly(oos);
FileUtils.closeQuietly(fos);
}
}
/**
* 返回RSA密钥对。
*/
public static KeyPair getKeyPair() {
// 首先推断是否须要又一次生成新的密钥对文件
if (isCreateKeyPairFile()) {
// 直接强制生成密钥对文件,并存入缓存。
return generateKeyPair();
}
if (oneKeyPair != null) {
return oneKeyPair;
}
return readKeyPair();
}
// 同步读出保存的密钥对
private static KeyPair readKeyPair() {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = FileUtils.openInputStream(rsaPairFile);
ois = new ObjectInputStream(fis);
oneKeyPair = (KeyPair) ois.readObject();
return oneKeyPair;
} catch (Exception ex) {
ex.printStackTrace();
} finally {
FileUtils.closeQuietly(ois);
FileUtils.closeQuietly(fis);
}
return null;
}
/**
* 依据给定的系数和专用指数构造一个RSA专用的公钥对象。
*
* @param modulus 系数。
* @param publicExponent 专用指数。
* @return RSA专用公钥对象。
*/
public static RSAPublicKey generateRSAPublicKey(byte[] modulus, byte[] publicExponent) {
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(modulus),
new BigInteger(publicExponent));
try {
return (RSAPublicKey) keyFactory.generatePublic(publicKeySpec);
} catch (InvalidKeySpecException ex) {
System.out.println("RSAPublicKeySpec is unavailable.");
ex.printStackTrace();
} catch (NullPointerException ex) {
System.out.println("RSAUtils#KEY_FACTORY is null, can not generate KeyFactory instance.");
ex.printStackTrace();
}
return null;
}
/**
* 依据给定的系数和专用指数构造一个RSA专用的私钥对象。
*
* @param modulus 系数。
* @param privateExponent 专用指数。
* @return RSA专用私钥对象。
*/
public static RSAPrivateKey generateRSAPrivateKey(byte[] modulus, byte[] privateExponent) {
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(new BigInteger(modulus),
new BigInteger(privateExponent));
try {
return (RSAPrivateKey) keyFactory.generatePrivate(privateKeySpec);
} catch (InvalidKeySpecException ex) {
System.out.println("RSAPrivateKeySpec is unavailable.");
ex.printStackTrace();
} catch (NullPointerException ex) {
System.out.println("RSAUtils#KEY_FACTORY is null, can not generate KeyFactory instance.");
ex.printStackTrace();
}
return null;
}
/**
* 依据给定的16进制系数和专用指数字符串构造一个RSA专用的私钥对象。
*
* @param modulus 系数。
* @param privateExponent 专用指数。
* @return RSA专用私钥对象。
*/
public static RSAPrivateKey getRSAPrivateKey(String hexModulus, String hexPrivateExponent) {
if(StringUtil.isBlank(hexModulus) || StringUtil.isBlank(hexPrivateExponent)) {
System.out.println("hexModulus and hexPrivateExponent cannot be empty. RSAPrivateKey value is null to return.");
return null;
}
byte[] modulus = null;
byte[] privateExponent = null;
try {
modulus = HexUtil.decodeHex(hexModulus.toCharArray());
privateExponent = HexUtil.decodeHex(hexPrivateExponent.toCharArray());
} catch(Exception ex) {
System.out.println("hexModulus or hexPrivateExponent value is invalid. return null(RSAPrivateKey).");
ex.printStackTrace();
}
if(modulus != null && privateExponent != null) {
return generateRSAPrivateKey(modulus, privateExponent);
}
return null;
}
/**
* 依据给定的16进制系数和专用指数字符串构造一个RSA专用的公钥对象。
*
* @param modulus 系数。
* @param publicExponent 专用指数。
* @return RSA专用公钥对象。
*/
public static RSAPublicKey getRSAPublicKey(String hexModulus, String hexPublicExponent) {
if(StringUtil.isBlank(hexModulus) || StringUtil.isBlank(hexPublicExponent)) {
System.out.println("hexModulus and hexPublicExponent cannot be empty. return null(RSAPublicKey).");
return null;
}
byte[] modulus = null;
byte[] publicExponent = null;
try {
modulus = HexUtil.decodeHex(hexModulus.toCharArray());
publicExponent = HexUtil.decodeHex(hexPublicExponent.toCharArray());
} catch(Exception ex) {
System.out.println("hexModulus or hexPublicExponent value is invalid. return null(RSAPublicKey).");
ex.printStackTrace();
}
if(modulus != null && publicExponent != null) {
return generateRSAPublicKey(modulus, publicExponent);
}
return null;
}
/**
* 使用指定的公钥加密数据。
*
* @param publicKey 给定的公钥。
* @param data 要加密的数据。
* @return 加密后的数据。
*/
public static byte[] encrypt(PublicKey publicKey, byte[] data) throws Exception {
Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
ci.init(Cipher.ENCRYPT_MODE, publicKey);
return ci.doFinal(data);
}
/**
* 使用指定的私钥解密数据。
*
* @param privateKey 给定的私钥。
* @param data 要解密的数据。
* @return 原数据。
*/
public static byte[] decrypt(PrivateKey privateKey, byte[] data) throws Exception {
Cipher ci = Cipher.getInstance(ALGORITHOM, DEFAULT_PROVIDER);
ci.init(Cipher.DECRYPT_MODE, privateKey);
return ci.doFinal(data);
}
/**
* 使用给定的公钥加密给定的字符串。
* <p />
* 若 {@code publicKey} 为 {@code null}。或者 {@code plaintext} 为 {@code null} 则返回 {@code
* null}。
*
* @param publicKey 给定的公钥。
* @param plaintext 字符串。
* @return 给定字符串的密文。
*/
public static String encryptString(PublicKey publicKey, String plaintext) {
if (publicKey == null || plaintext == null) {
return null;
}
byte[] data = plaintext.getBytes();
try {
byte[] en_data = encrypt(publicKey, data);
return new String(HexUtil.encodeHex(en_data));
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* 使用默认的公钥加密给定的字符串。
* <p />
* 若{@code plaintext} 为 {@code null} 则返回 {@code null}。
*
* @param plaintext 字符串。
* @return 给定字符串的密文。
*/
public static String encryptString(String plaintext) {
if(plaintext == null) {
return null;
}
byte[] data = plaintext.getBytes();
KeyPair keyPair = getKeyPair();
try {
byte[] en_data = encrypt((RSAPublicKey)keyPair.getPublic(), data);
return new String(HexUtil.encodeHex(en_data));
} catch(NullPointerException ex) {
System.out.println("keyPair cannot be null.");
ex.printStackTrace();
} catch(Exception ex) {
ex.printStackTrace();
}
return null;
}
/**
* 生成由JS的RSA加密的字符串。
* @param publicKey 公钥
* @param plaintext 原文字符串
* @return 加密后的字符串
*/
public static String encryptStringByJs(PublicKey publicKey, String plaintext) {
if(plaintext == null) {
return null;
}
String text = encryptString(publicKey,StringUtil.reverse(plaintext));
return text;
}
/**
* 用默认公钥生成由JS的RSA加密的字符串。
* @param publicKey 公钥
* @param plaintext 原文字符串
* @return 加密后的字符串
*/
public static String encryptStringByJs( String plaintext) {
if(plaintext == null) {
return null;
}
String text = encryptString(StringUtil.reverse(plaintext));
return text;
}
/**
* 使用给定的私钥解密给定的字符串。
* <p />
* 若私钥为 {@code null},或者 {@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
* 私钥不匹配时,返回 {@code null}。
*
* @param privateKey 给定的私钥。
* @param encrypttext 密文。
* @return 原文字符串。
*/
public static String decryptString(PrivateKey privateKey, String encrypttext) {
if (privateKey == null || StringUtil.isBlank(encrypttext)) {
return null;
}
try {
byte[] en_data =HexUtil.decodeHex(encrypttext.toCharArray());
byte[] data = decrypt(privateKey, en_data);
return new String(data);
} catch (Exception ex) {
System.out.println(String.format("\"%s\" Decryption failed. Cause: %s", encrypttext, ex.getCause().getMessage()));
}
return null;
}
/**
* 使用默认的私钥解密给定的字符串。
* <p />
* 若{@code encrypttext} 为 {@code null}或空字符串则返回 {@code null}。
* 私钥不匹配时,返回 {@code null}。
*
* @param encrypttext 密文。
* @return 原文字符串。
*/
public static String decryptString(String encrypttext) {
if(StringUtil.isBlank(encrypttext)) {
return null;
}
KeyPair keyPair = getKeyPair();
try {
byte[] en_data = HexUtil.decodeHex(encrypttext.toCharArray());
byte[] data = decrypt((RSAPrivateKey)keyPair.getPrivate(), en_data);
return new String(data);
} catch(NullPointerException ex) {
System.out.println("keyPair cannot be null.");
ex.printStackTrace();
} catch (Exception ex) {
System.out.println(String.format("\"%s\" Decryption failed. Cause: %s", encrypttext, ex.getMessage()));
ex.printStackTrace();
}
return null;
}
/**
* 使用指定的私钥解密由JS加密的字符串。
* @param privateKey 私钥
* @param encrypttext 密文
* @return {@code encrypttext} 的原文字符串
*/
public static String decryptStringByJs(PrivateKey privateKey,String encrypttext) {
String text = decryptString(privateKey,encrypttext);
if(text == null) {
return null;
}
return StringUtil.reverse(text);
}
/**
* 使用默认的私钥解密由JS加密(使用此类提供的公钥加密)的字符串。
*
* @param encrypttext 密文。
* @return {@code encrypttext} 的原文字符串。
*/
public static String decryptStringByJs(String encrypttext) {
String text = decryptString(encrypttext);
if(text == null) {
return null;
}
return StringUtil.reverse(text);
}
/** 返回已初始化的默认的公钥。
*/
public static RSAPublicKey getDefaultPublicKey() {
KeyPair keyPair = getKeyPair();
if(keyPair != null) {
return (RSAPublicKey)keyPair.getPublic();
}
return null;
}
/** 返回已初始化的默认的私钥。*/
public static RSAPrivateKey getDefaultPrivateKey() {
KeyPair keyPair = getKeyPair();
if(keyPair != null) {
return (RSAPrivateKey)keyPair.getPrivate();
}
return null;
}
}
源代码下载
JAVA的RSA加密算法工具类的更多相关文章
- Rhino+envjs-1.2.js 在java运行网站js 工具类
java爬虫遇到个页面加密的东西,找了些资料学习学习 做了个java运行js的工具类,希望对大家有用,其中用到client(获取js)可以自行换成自己的client.主要是用了 Rhino就是Java ...
- java中常用的工具类(一)
我们java程序员在开发项目的是常常会用到一些工具类.今天我汇总了一下java中常用的工具方法.大家可以在项目中使用.可以收藏!加入IT江湖官方群:383126909 我们一起成长 一.String工 ...
- Java学习-041-颜色工具类(RGB,HEX)
在日常的网页开发中,经常需要进行颜色数值获取.转换,例如获取红色,获取蓝色,获取绿色,RGB转十六进制颜色,十六进制颜色转RGB等,因而在学习过程中,写了一个小工具类,仅供各位小主参考! 多不闲言,直 ...
- JAVA中封装JSONUtils工具类及使用
在JAVA中用json-lib-2.3-jdk15.jar包中提供了JSONObject和JSONArray基类,用于JSON的序列化和反序列化的操作.但是我们更习惯将其进一步封装,达到更好的重用. ...
- JAVA自动生成正则表达式工具类
经过很久的努力,终于完成了JAVA自动生成正则表达式工具类.还记得之前需要正则,老是从网上找吗?找了想修改也不会修改.现在不用再为此烦恼了,使用此生成类轻松搞定所有正则表达式.赶快在同事面前炫一下吧. ...
- java 二进制数字符串转换工具类
java 二进制数字符串转换工具类 将二进制转换成八进制 将二进制转换成十进制 将二进制转换成十六进制 将十进制转换成二进制 package com.iteye.injavawetrust.ad; i ...
- Java学习-049-正则工具类
自去年九月份决定再次入学和职业资格进阶,开始备战二者考试至今,以及当下进行中的职称申请,犹如孤独的狼,不断前行在路上,而今凡凡总总的已历8月... 不感慨了,如下为一园友需要的正则工具类,直接上码: ...
- Java 后台验证的工具类
Java 后台验证的工具类 public class ValidationUtil { //手机号 public static String mobile = "^( ...
- java后端时间处理工具类,返回 "XXX 前" 的字符串
转自:https://www.cnblogs.com/devise/p/9974672.html 我们经常会遇到显示 "某个之间之前" 的需求(比如各种社交软件,在回复消息时,显示 ...
随机推荐
- jQuery回到顶部
jquery回到顶部 <!DOCTYPE html> <html lang="zh-cn"> <head> <meta charset=& ...
- DedeCMS批量替换栏目文件保存目录的方法
学点sql还是很有必要的. 有时候由于栏目太多,但是要修改一下栏目的保存目录.一个一个修改真的有点费事和慢.所以想了一个方法来批量修改栏目的保存目录.就是批量替换: update dede_arc ...
- Nginx环境下常见的开源项目重写汇总
我们做PHP开发的,作者寒冰我觉得大部分时候都在跟开源的系统打交道.比如:Discuz.PHPCMS.ecshop.wordpress等开源系统.一般我们都是在本地搭建测试环境,用的web服务器都是a ...
- TreeView 数据绑定及选中命令处理
昨天接近下班,一个群里面的网友,问treeView绑定后 选中命令怎么来处理,怎么没有效果,而且用MVVM的方式来写:快下班了本来想远程帮他看下,结果就说写个Demo给他看:再加上选中传参: 下面分 ...
- 东软实训1 -jsp内置对象及其常用方法
JSP 的内置对象及方法详细说明 一. request 对象 客户端的请求信息被封装在 request 对象中,通过它才能了解到客户的需 求,然后做出响应.它是 HttpServletRequest ...
- PHP学习系列(1)——字符串处理函数(3)
11.crc32() 函数计算一个字符串的 crc32 多项式.生成 string 参数的 32 位循环冗余校验码多项式.该函数可用于验证数据的完整性. 语法:crc32(string) 注意:由于 ...
- Python自动化运维之2、运算符与数据类型
python对象的相关术语: python程序中保存的所有数据都是围绕对象这个概念展开的: 程序中存储的所有数据都是对象 每个对象都有一个身份.一个类型和一个值 例如,school='MaGe Lin ...
- Objective C内存管理之理解autorelease------面试题
Objective C内存管理之理解autorelease Autorelease实际上只是把对release的调用延迟了,对于每一个Autorelease,系统只是把该Object放入了当前的A ...
- DbUtility-查询DataTable
直接上源码 using System; using System.Data; using System.Threading.Tasks; using DbUtility; namespace Test ...
- 浅析Android中的消息机制
在分析Android消息机制之前,我们先来看一段代码: public class MainActivity extends Activity implements View.OnClickListen ...