基本介紹
RSA
加密算法是一種非對稱加密算法。這就意味着通過這個算法,你即將獲得一對密鑰,分別是公鑰和私鑰。你可以將公鑰公佈出去,別人利用你的公鑰加密後的內容,只能使用你的私鑰來解開,即可保證你和別人通信的安全性,這就是這個加密算法的意義所在。
算法步驟
參考來自:25行代碼實現完整的RSA算法
算法難點
- 如何儲存大數,動態語言一般不存在這個問題。不過在Java中就需要藉助
BigInteger
,其他靜態語言可能需要藉助第三方庫才能存儲。 - 如何計算一個超大整數的超大整數次冪,然後取超大整數模,這個文字有點繞,大概就是這個樣子:,這個問題呢就需要使用到蒙哥馬利方法了。
- 如何產生兩個隨機1024位大質數?這個問題在
Java
直接利用如下方法即可:
public static BigInteger[] getRandomPQ() {
BigInteger p = BigInteger.probablePrime(numLength, new Random());
while (!p.isProbablePrime(accuracy)) {
p = BigInteger.probablePrime(numLength, new Random());
}
BigInteger q = BigInteger.probablePrime(numLength, new Random());
while (!q.isProbablePrime(accuracy)) {
q = BigInteger.probablePrime(numLength, new Random());
}
return new BigInteger[]{p, q};
}
不僅可以產生指定長度的大數,還可以控制其爲素數的準確率,即:,accuracy
越大爲素數的準確率就越高。
Java代碼實現
import java.math.BigInteger;
import java.util.Random;
public class RSA {
private final static int numLength = 1024;//素數長度
private final static int accuracy = 100;//素數的準確率爲1-(2^(-accuracy))
//獲取最大公約數
private BigInteger getGCD(BigInteger a, BigInteger b) {
if (b.byteValue() == 0) return a;
return getGCD(b, a.mod(b));
}
//擴展歐幾里得方法,計算 ax + by = 1中的x與y的整數解(a與b互質)
private static BigInteger[] extGCD(BigInteger a, BigInteger b) {
if (b.signum() == 0) {
return new BigInteger[]{a, new BigInteger("1"), new BigInteger("0")};
} else {
BigInteger[] bigIntegers = extGCD(b, a.mod(b));
BigInteger y = bigIntegers[1].subtract(a.divide(b).multiply(bigIntegers[2]));
return new BigInteger[]{bigIntegers[0], bigIntegers[2], y};
}
}
//超大整數超大次冪然後對超大的整數取模,利用蒙哥馬利乘模算法,
//(base ^ exp) mod n
//依據(a * b) mod n=(a % n)*(b % n) mod n
private static BigInteger expMode(BigInteger base, BigInteger exp, BigInteger mod) {
BigInteger res = BigInteger.ONE;
//拷貝一份防止修改原引用
BigInteger tempBase = new BigInteger(base.toString());
//從左到右實現簡答
/*
D=1
WHILE E>=0
IF E%2=0
C=C*C % N
E=E/2
ELSE
D=D*C % N
E=E-1
RETURN D
*/
for (int i = 0; i < exp.bitLength(); i++) {
if (exp.testBit(i)) {//判斷對應二進制位是否爲1
res = (res.multiply(tempBase)).mod(mod);
}
tempBase = tempBase.multiply(tempBase).mod(mod);
}
return res;
}
//產生公鑰與私鑰
public static SecretKey generateKey(BigInteger p, BigInteger q) {
//令n = p * q。取 φ(n) = (p-1) * (q-1)。
BigInteger n = p.multiply(q);
//計算與n互質的整數個數 歐拉函數
BigInteger fy = p.subtract(BigInteger.ONE).multiply(q.subtract(BigInteger.ONE));
//取 e ∈ [1 < e < φ(n) ] ,( n , e )作爲公鑰對,這裏取65537
BigInteger e = new BigInteger("65537");
//計算ed與fy的模反元素d。令 ed mod φ(n) = 1,計算d,然後將( n , d ) 作爲私鑰對
BigInteger[] bigIntegers = extGCD(e, fy);
//計算出的x不能是負數,如果是負數,則進行x=x+fy。使x爲正數,但是x<fy。
BigInteger x = bigIntegers[1];
if (x.signum() == -1) {
x = x.add(fy);
}
//返回計算出的密鑰
return new SecretKey(n, e, x);
}
public static SecretKey generateKey() {
BigInteger[] pq = getRandomPQ();
return generateKey(pq[0], pq[1]);
}
//加密
public static BigInteger encrypt(BigInteger text, SecretKey.PublicKey publicKey) {
return expMode(text, publicKey.e, publicKey.n);
}
//解密
public static BigInteger decrypt(BigInteger cipher, SecretKey.PrivateKey privateKey) {
return expMode(cipher, privateKey.d, privateKey.n);
}
//加密
public static String encrypt(String text, SecretKey.PublicKey publicKey) {
return encrypt(new BigInteger(text.getBytes()), publicKey).toString();
}
//解密
public static String decrypt(String chipper, SecretKey.PrivateKey privateKey) {
BigInteger bigInteger = expMode(new BigInteger(chipper), privateKey.d, privateKey.n);
byte[] bytes = new byte[bigInteger.bitLength() / 8 + 1];
for (int i = 0; i < bytes.length; i++) {
for (int j = 0; j < 8; j++) {
if (bigInteger.testBit(j + i * 8)) {
bytes[bytes.length - 1 - i] |= 1 << j;
}
}
}
return new String(bytes);
}
//產生兩個隨機1024位大質數
public static BigInteger[] getRandomPQ() {
BigInteger p = BigInteger.probablePrime(numLength, new Random());
while (!p.isProbablePrime(accuracy)) {
p = BigInteger.probablePrime(numLength, new Random());
}
BigInteger q = BigInteger.probablePrime(numLength, new Random());
while (!q.isProbablePrime(accuracy)) {
q = BigInteger.probablePrime(numLength, new Random());
}
return new BigInteger[]{p, q};
}
//密匙對
static class SecretKey {
BigInteger n, e, d;
public SecretKey(BigInteger n, BigInteger e, BigInteger d) {
this.n = n;
this.e = e;
this.d = d;
}
public PublicKey getPublicKey() {
return new PublicKey(n, e);
}
public PrivateKey getPrivateKey() {
return new PrivateKey(n, d);
}
//密鑰
static class PrivateKey {
public BigInteger n, d;
public PrivateKey(BigInteger n, BigInteger d) {
this.n = n;
this.d = d;
}
}
//公鑰
static class PublicKey {
public BigInteger n, e;
public PublicKey(BigInteger n, BigInteger e) {
this.n = n;
this.e = e;
}
}
}
public static void main(String[] args) {
SecretKey secretKey = RSA.generateKey();
//明文內容不要超過1024位,超過後需要分段加密
String text = "Hello world";
String chipper = RSA.encrypt(text, secretKey.getPublicKey());
System.out.println("加密後:\n" +
//密文長度可能會隨着隨機密鑰的改變而改變,最長不超過2048位
"密文二進制長度:" + new BigInteger(chipper).bitLength()
+ "\n"
+ chipper);
String origin = RSA.decrypt(chipper, secretKey.getPrivateKey());
System.out.println("解密後:\n" + origin);
}
}