RSA算法的Java实现
在Java实现该算法前我们先完成Java开发环境的配置,笔者选择的是JDK1.8版本,开发环境用Eclipse
开发环境配置
- JDK安装
- Eclipse安装
JDK安装
(1)JDK下载链接,进入链接后找到以下所示界面:
选择最后一列Windows x64位的下载
x86适用于32位操作系统,x64适用于64位以及32位操作系统
下载完成并放置于C盘中:
(2)配置环境变量
配置JAVA_HOME,Path,CLASSPATH
- JAVA_HOME
右键点击文件夹中“此电脑”选项,选择“属性”,选择其中的“高级系统设置”,
出现如图所示
点击环境变量选择系统变量新建,配置如下:
变量名填:JAVA_HOME
变量值:填JDK的安装目录,及如图所示
PS:点击最上边一栏即可得到JDK安装目录,然后复制该地址到变量值即可 - Path
同配置JAVA_HOME操作一样,不过变量值不一样
Path的值: %JAVA_HOME%\bin
%JAVA_HOME%\bin是Windows操作系统用来寻找可执行文件的路径,当然在我们的JDK目录下的jre中也有bin文件,其中也有部分执行文件,这个配不配置基本不影响的,如果需要,将Path设置为%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin即可
- CLASSPATH
同上述环境变量的配置一样
CLASSPATH的值为: .;%JAVA_HOME%\lib\tools.jar;%JAVA_HOME%\lib\dt.jar
CLASSPATH的路径告诉类装载器到哪里去寻找第三方提供的类和用户定义的类
dt.jar:运行环境类库,主要是Swing包
tools.jar:工具类库
到此为止,JDK的配置即完成。查看是否配置成功:
打开cmd输入java –version以及java ,javac命令无异常即代表成功
Eclipse安装
下载链接
如正常下载软件一样,下载并安装即可使用
RSA的算法原理
我简单介绍一下RSA算法的基本原理
RSA算法基于大整数因子分解困难性问题
- 首先选择两个互异的大素数p和q(保密),计算n=p*q(公开),βn=(p-1)*(q-1)(保密)
- 选择一个随机整数 e (0<e<βn)(公开),满足 gcd(e,βn)=1。计算选择一个随机整数 e (0<e<βn)(公开),满足 gcd(e,βn)=1
- 计算d= e^-1 mod βn(保密)
- 确定: 公钥KU={ e,n},私钥KR={d,p,q},或KR={d,n}
- 加密:已知明文:M 计算密文:C=(M^e)mod n
- 解密:已知密文:C 和私钥 KR={d,n} 计算明文:M=C^d mod n
密钥生成时,如果要求 n 很大,攻击者要将其成功地分解为 p乘以q是困难的,这就是著名的大整数因子分解性问题,这保证了攻击者不能得出 βn=(p-1)*(q-1),因此即使知道公钥{ e,n},也不能通过解密算法将私钥{d,n}推导出来。 --来自《应用密码学》
算法实现:
Main类:
package RSAtest;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.HashMap;
public class Main {
public static void main(String[] args) throws Exception {
HashMap<String, Object> map=RSAUtils.getKeys();
RSAPublicKey publicKey=(RSAPublicKey)map.get("public");
RSAPrivateKey privateKey=(RSAPrivateKey) map.get("private");
//得到公开的N(PS:N=p*q,p和q是保密的
String modulus=publicKey.getModulus().toString();
//得到公开的E(PS:E是公钥中中公开的随机整数
String public_exponent=publicKey.getPublicExponent().toString();
//得到私钥D
String private_exponent=privateKey.getPrivateExponent().toString();
String ming="128";
RSAPublicKey pubKey=RSAUtils.getPublicKey(modulus, public_exponent);
RSAPrivateKey priKey=RSAUtils.getPrivateKey(modulus, private_exponent);
String mi=RSAUtils.encrytByPublicKey(ming, pubKey);
System.out.println(mi);
ming=RSAUtils.decryptByPrivateKey(mi, priKey);
System.err.println(ming);
}
}
RSAUtils类;
package RSAtest;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.HashMap;
import javax.crypto.Cipher;
public class RSAUtils {
public static HashMap<String,Object>getKeys() throws NoSuchAlgorithmException{
HashMap<String,Object>map=new HashMap<String,Object>();
//调用产生RSA算法
KeyPairGenerator KeyPairGen=KeyPairGenerator.getInstance("RSA");
//设置产生RSA算法的密钥长度
KeyPairGen.initialize(Integer.parseInt("1024"));
//生成密钥对
KeyPair keyPair=KeyPairGen.generateKeyPair();
//获取公钥
RSAPublicKey publicKey=(RSAPublicKey) keyPair.getPublic();
//获取私钥
RSAPrivateKey privateKey=(RSAPrivateKey) keyPair.getPrivate();
map.put("public", publicKey);
map.put("private", privateKey);
return map;
}
public static RSAPublicKey getPublicKey(String modulus,String exponent) throws Exception{
BigInteger b1=new BigInteger(modulus);
BigInteger b2=new BigInteger(exponent);
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
RSAPublicKeySpec keySpec=new RSAPublicKeySpec(b1, b2);
return (RSAPublicKey) keyFactory.generatePublic(keySpec);
}
public static RSAPrivateKey getPrivateKey(String modulus,String exponent) throws Exception{
BigInteger b1=new BigInteger(modulus);
BigInteger b2=new BigInteger(exponent);
KeyFactory keyFactory=KeyFactory.getInstance("RSA");
RSAPrivateKeySpec keySpec=new RSAPrivateKeySpec(b1, b2);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
}
public static String encrytByPublicKey(String data,RSAPublicKey publicKey) throws Exception{
Cipher cipher=Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
int key_len=publicKey.getModulus().bitLength();
String []datas =splitString(data,key_len-11);
String mi="";
for(String s:datas) {
mi+=bcd2Str(cipher.doFinal(s.getBytes()));
}
return mi;
}
public static String decryptByPrivateKey(String data,RSAPrivateKey privateKey) throws Exception{
Cipher cipher=Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
int key_len=privateKey.getModulus().bitLength();
byte []bytes=data.getBytes();
byte []bcd=ASCII_TO_BCD(bytes,bytes.length);
System.err.println(bcd.length);
String ming="";
byte[][] arrays =splitArray(bcd,key_len);
for(byte[]arr:arrays) {
ming+=new String(cipher.doFinal(arr));
}
return ming;
}
public static byte[] ASCII_TO_BCD(byte[] ascii,int asc_len) {
byte[] bcd=new byte[asc_len/2];
int j=0;
for(int i=0;i<(asc_len+1)/2;i++) {
bcd[i]=asc_to_bcd(ascii[j++]);
bcd[i]=(byte)(((j>=asc_len)?0x00:asc_to_bcd(ascii[j++]))+(bcd[i]<<4));
}
return bcd;
}
public static byte asc_to_bcd(byte asc) {
byte bcd;
if((asc>='0')&&(asc<='9'))
bcd=(byte)(asc-'0');
else if((asc>='A')&&(asc<='F'))
bcd=(byte)(asc-'A'+10);
else if((asc>='a')&&(asc<='f'))
bcd=(byte)(asc-'a'+10);
else
bcd=(byte)(asc-48);
return bcd;
}
public static String bcd2Str(byte[] bytes) {
char temp[]=new char[bytes.length*2],val;
for(int i=0;i<bytes.length;i++) {
val=(char)(((bytes[i]&0xf0)>>4)&0xf0);
temp[i*2]=(char)(val>9?val+'A'-10:val+'0');
val=(char)(bytes[i]&0x0f);
temp[i*2+1]=(char)(val>9?val+'A'-10:val+'0');
}
return new String(temp);
}
public static String[] splitString(String string,int len) {
int x=string.length()/len;
int y=string.length()%len;
int z=0;
if(y!=0) {
z=1;
}
String[] strings=new String[x+z];
String str="";
for(int i=0;i<x+z;i++) {
if(i==x+z-1&&y!=0) {
str=string.substring(i*len, i*len+y);
}else {
str=string.substring(i*len,i*len+len);
}
strings[i]=str;
}
return strings;
}
public static byte[][] splitArray(byte[] data,int len){
int x=data.length/len;
int y=data.length%len;
int z=0;
if(y!=0) {
z=1;
}
byte[][] arrays=new byte[x+z][];
byte[] arr;
for(int i=0;i<x+z;i++) {
arr=new byte[len];
if(i==x+z-1&&y!=0) {
System.arraycopy(data, i*len, arr, 0, y);
}else {
System.arraycopy(data, i*len, arr, 0, len);
}
arrays[i]=arr;
}
return arrays;
}
}
代码参考来源:https://blog.csdn.net/centralperk/article/details/8558678
运行结果演示:
代码运行的问题在于不管怎么修改明文,解密后的明文输出都是128,这是为什么呢?