学校里的实验正好在学习网络安全方面的密码学基础,就正好想着写一个RSA加密的算法,之前也看到了不少RSA加密的代码,不过大部分都是使用库来实现的,由于想更好的理解就不调用security库来实现一次,当然如果日后使用到RSA的话,肯定还是用库的好,毕竟自己写的基本功能满足了但是肯定还有很多不足,不多BB 了,上代码:
RSA算法1.随机地选择两个大素数p和q,而且保密;
2.计算n=pq,将n公开;
3.计算φ(n)=(p-1)(q-1),对φ(n)保密;
4.随机地选取一个正整数e,1
5.根据ed=1(mod φ(n)),求出d,并对d保密;
6.加密运算:C=Me(mod n);
7.解密运算:M=Cd(mod n)。
注意:在加密运算和解密运算中,M和C的值都必须小于n,也就是说,如果明文(或密文)太大,必须进行分组加密(或解密)。(这个是重点,也是本次实验我没完成的一步,人比较废物。。。。。。)
模幂算法
public static BigInteger modExp(BigInteger b, BigInteger n, BigInteger m) {
BigInteger result = new BigInteger("1");
b = b.remainder(m);
do {
if ((n.remainder(new BigInteger("2"))).compareTo(BigInteger.ONE)==0){
result=(result.multiply(b)).remainder(m);
}
b = (b.multiply(b)).remainder(m);
n = n.shiftRight(1);
} while (n != BigInteger.ZERO);
return result;
}
因为RSA是大素数为基础的算法,所以使用了BigInteger类,因为long只能满足到64位,实际情况可能一句话都加密不了。
当然Biginteger类中自带了modpow函数可以进行模的幂运算,包括后面的求逆元同样可以使用其进行计算,这里我没有使用他,而是只是自己写出来以便更好的理解
模逆(求逆元)
public static BigInteger modInv1(BigInteger b, BigInteger m) {
if (b.compareTo(m)==1||b.compareTo(m)==0)
b = b.remainder(m);
return Gcd(b, m)[1].compareTo(BigInteger.ZERO)==-1 ? Gcd(b, m)[1].add(m) : Gcd(b, m)[1];
}
public static BigInteger[] Gcd(BigInteger a, BigInteger b) {
if (a.compareTo(b)==-1) {
BigInteger temp = a;
a = b;
b = temp;
}
BigInteger[] result = new BigInteger[3];
if (b.compareTo(BigInteger.ZERO)==0) {
result[0] = new BigInteger("1");
result[1] = new BigInteger("0");
result[2] = a;
return result;
}
BigInteger[] temp = Gcd(b, a.remainder(b));
result[0] = temp[1];
result[1] = temp[0].subtract((a.divide(b)).multiply(temp[1]));
result[2] = temp[2];
return result;
}
RSA加解密
public static BigInteger encyrpt(byte[] textByte,BigInteger e,BigInteger n) throws UnsupportedEncodingException {
BigInteger t = new BigInteger(1,textByte);
BigInteger C = modExp(t,e,n);//可以直接使用modpow函数进行模幂算法,这里采取了手动实现以更便于理解底层
// System.out.println(C);
return C;
}
public static BigInteger dncyrpt(BigInteger C,BigInteger d,BigInteger n) throws UnsupportedEncodingException {
BigInteger cm = modExp(C,d,n);
return cm;
}
因为算法都是数学问题,是以数字的形式体现,那当我们想运用于实际中加密一串字符串或是一段语言时该怎么办呢?
System.out.println("输入明文:");
Scanner input = new Scanner(System.in);
String M = input.next();
System.out.println("需要加密的明文:"+M);
byte[] textByte = M.getBytes("UTF-8");
BigInteger C = encyrpt(textByte,e,n);
byte[] cmessage = C.toByteArray();
String a = base64.encodeToString(cmessage);
System.out.println("加密得到的密文:"+a);
BigInteger cm = dncyrpt(C,d,n);
byte[] recmessage = cm.toByteArray();
String encodedText2 = base64.encodeToString(recmessage);
System.out.println("解密后得到的信息明文:"+new String(base64.decode(encodedText2), "UTF-8"));
熟练的在自己设置的函数体调用时对其进行类型的装换
基本为byte[] string BigInteger 三类
package secourity;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.util.Random;
import java.util.Scanner;
import org.apache.commons.codec.binary.base64;
public class RSA {
public static void main(String[] args) throws Exception {
//需要加密的明文
System.out.println("输入明文:");
Scanner input = new Scanner(System.in);
String M = input.next();
System.out.println("需要加密的明文:"+M);
byte[] textByte = M.getBytes("UTF-8");
System.out.println("bytelength:"+textByte.length);
//生成大素数p,q
int bitlength = (textByte.length)*8;//byte=8bite,使用这个步骤,让p,q算出的n的长度一定是大于输入明文的
base64 base64 = new base64();
BigInteger p = BigInteger.probablePrime(bitlength, new Random());
BigInteger q = BigInteger.probablePrime(bitlength, new Random());
//n=p*q生成加解密运算的mod数
BigInteger n = p.multiply(q);
int num = n.bitLength();
System.out.println("bit长度为:"+num);
//生成欧几里得算法输出的R
BigInteger r = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
//生成公钥e
BigInteger e;
do {
// e = new BigInteger(new Random().nextInt(r.bitLength() - 1) + 1, new Random());
e = new BigInteger(900, new Random());
} while (e.compareTo(r) != -1 || e.gcd(r).intValue() != 1);
//生成私钥
BigInteger d = modInv1(e,r);
//公钥和私钥做base64编码操作
byte[] publickey = e.toByteArray();
String encodedText = base64.encodeToString(publickey);
// System.out.println(e);
byte[] pravitekey = d.toByteArray();
String encodedText1 = base64.encodeToString(pravitekey);
System.out.println("公钥为:"+encodedText);
System.out.println("私钥为:"+encodedText1);
BigInteger C = encyrpt(textByte,e,n);
byte[] cmessage = C.toByteArray();
String a = base64.encodeToString(cmessage);
System.out.println("加密得到的密文:"+a);
BigInteger cm = dncyrpt(C,d,n);
byte[] recmessage = cm.toByteArray();
String encodedText2 = base64.encodeToString(recmessage);
System.out.println("解密后得到的信息明文:"+new String(base64.decode(encodedText2), "UTF-8"));
}
public static BigInteger encyrpt(byte[] textByte,BigInteger e,BigInteger n) throws UnsupportedEncodingException {
BigInteger t = new BigInteger(1,textByte);
BigInteger C = modExp(t,e,n);//可以直接使用modpow函数进行模幂算法,这里采取了手动实现以更便于理解底层
// System.out.println(C);
return C;
}
public static BigInteger dncyrpt(BigInteger C,BigInteger d,BigInteger n) throws UnsupportedEncodingException {
BigInteger cm = modExp(C,d,n);
return cm;
}
public static BigInteger modExp(BigInteger b, BigInteger n, BigInteger m) {
BigInteger result = new BigInteger("1");
b = b.remainder(m);
do {
if ((n.remainder(new BigInteger("2"))).compareTo(BigInteger.ONE)==0){
result=(result.multiply(b)).remainder(m);
}
b = (b.multiply(b)).remainder(m);
n = n.shiftRight(1);
} while (n != BigInteger.ZERO);
return result;
}
public static BigInteger modInv1(BigInteger b, BigInteger m) {
if (b.compareTo(m)==1||b.compareTo(m)==0)
b = b.remainder(m);
return Gcd(b, m)[1].compareTo(BigInteger.ZERO)==-1 ? Gcd(b, m)[1].add(m) : Gcd(b, m)[1];
}
public static BigInteger[] Gcd(BigInteger a, BigInteger b) {
if (a.compareTo(b)==-1) {
BigInteger temp = a;
a = b;
b = temp;
}
BigInteger[] result = new BigInteger[3];
if (b.compareTo(BigInteger.ZERO)==0) {
result[0] = new BigInteger("1");
result[1] = new BigInteger("0");
result[2] = a;
return result;
}
BigInteger[] temp = Gcd(b, a.remainder(b));
result[0] = temp[1];
result[1] = temp[0].subtract((a.divide(b)).multiply(temp[1]));
result[2] = temp[2];
return result;
}
}
因为自己代码的习惯和熟练度都还不是很好,所以这段代码的main部分还是封装的不大好,不过逻辑还算相对比较清楚,如果能起到一定的学习作用那是最好,当然真实情况下的RSA还要考虑更多的问题,实际应用中还是调用库比较好。



