#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#define PRIME_MAX 200 // 生成素數范圍
#define EXPONENT_MAX 200 // 生成指數e范圍
#define Element_Max 127 // 加密單元的最大值,這里為一個char, 即1Byte
char str_read[100]="hello world !"; // 待加密的原文
int str_encrypt[100]; // 加密後的內容
char str_decrypt[100]; // 解密出來的內容
int str_read_len; // str_read 的長度
int prime1, prime2; // 隨機生成的兩個質數
int mod, eular; // 模數和歐拉數
int pubKey, priKey; // 公鑰指數和私鑰指數
// 生成隨機素數,實際應用中,這兩個質數越大,就越難破解。
int randPrime()
{
int prime, prime2, i;
next:
prime = rand() % PRIME_MAX; // 隨機產生數
if (prime <= 1) goto next; // 不是質數,生成下一個隨機數
if (prime == 2 || prime == 3) return prime;
prime2 = prime / 2; // prime>=4, prime2 的平方必定大於 prime , 因此只檢查小於等於prime2的數
for (i = 2; i <= prime2; i++) // 判斷是否為素數
{
if (i * i > prime) return prime;
if (prime % i == 0) goto next; // 不是質數,生成下一個隨機數
}
}
// 歐幾里德演算法,判斷a,b互質
int gcd(int a, int b)
{
int temp;
while (b != 0) {
temp = b;
b = a % b;
a = temp;
}
return a;
}
//生成公鑰指數,條件是 1< e < 歐拉數,且與歐拉數互質。
int randExponent()
{
int e;
while (1)
{
e = rand() % eular; if (e < EXPONENT_MAX) break;
}
while (1)
{
if (gcd(e, eular) == 1) return e; e = (e + 1) % eular; if (e == 0 || e > EXPONENT_MAX) e = 2;
}
}
//生成私鑰指數
int inverse()
{
int d, x;
while (1)
{
d = rand() % eular;
x = pubKey * d % eular;
if (x == 1)
{
return d;
}
}
}
//加密函數
void jiami()
{
str_read_len = strlen(str_read); //從參數表示的地址往後找,找到第一個'\0',即串尾。計算'\0'至首地址的「距離」,即隔了幾個字元,從而得出長度。
printf("密文是:");
for (int i = 0; i < str_read_len; i++)
{
int C = 1; int a = str_read[i], b = a % mod;
for (int j = 0; j < pubKey; j++) //實現加密
{
C = (C*b) % mod;
}
str_encrypt[i] = C;
printf("%d ", str_encrypt[i]);
}
printf("\n");
}
//解密函數
void jiemi()
{
int i=0; for (i = 0; i < str_read_len; i++)
{
int C = 1; int a = str_encrypt[i], b=a%mod;
for (int j = 0; j < priKey; j++)
{
C = (C * b) % mod;
}
str_decrypt[i] = C;
}
str_decrypt[i] = '\0'; printf("解密文是:%s \n", str_decrypt);
}
int main()
{
srand(time(NULL));
while (1)
{
prime1 = randPrime(); prime2 = randPrime(); printf("隨機產生兩個素數:prime1 = %d , prime2 = %d ", prime1, prime2);
mod = prime1 * prime2; printf("模數:mod = prime1 * prime2 = %d \n", mod); if (mod > Element_Max) break; // 模數要大於每個加密單元的值
}
eular = (prime1 - 1) * (prime2 - 1); printf("歐拉數:eular=(prime1-1)*(prime2-1) = %d \n", eular);
pubKey = randExponent(); printf("公鑰指數:pubKey = %d\n", pubKey);
priKey = inverse(); printf("私鑰指數:priKey = %d\n私鑰為 (%d, %d)\n", priKey, priKey, mod);
jiami(); jiemi();
return 0;
}
⑵ java中RSA的方式如何實現非對稱加密的示例
代碼如下,需要依賴一個jar包commons-codec-1.9.jar,用於Base64轉換,請自行下載。
importorg.apache.commons.codec.binary.Base64;
importjavax.crypto.BadPaddingException;
importjavax.crypto.Cipher;
importjavax.crypto.IllegalBlockSizeException;
importjava.io.ByteArrayOutputStream;
importjava.io.UnsupportedEncodingException;
importjava.security.*;
importjava.security.interfaces.RSAPrivateKey;
importjava.security.interfaces.RSAPublicKey;
importjava.security.spec.PKCS8EncodedKeySpec;
importjava.security.spec.X509EncodedKeySpec;
publicclassRSAUtils{
//加密方式
="RSA";
//簽名演算法
_ALGORITHM="SHA1WithRSA";
//創建密鑰對初始長度
privatestaticfinalintKEY_SIZE=512;
//字元編碼格式
="UTF-8";
//RSA最大加密明文大小
privatestaticfinalintMAX_ENCRYPT_BLOCK=117;
//RSA最大解密密文大小
privatestaticfinalintMAX_DECRYPT_BLOCK=128;
privateKeyFactorykeyFactory;
publicRSAUtils(){
keyFactory=KeyFactory.getInstance(ALGORITHM);
}
/**
*私鑰加密
*
*@paramcontent待加密字元串
*@paramprivateKey私鑰
*@return加密後字元串(BASE64編碼)
*/
(Stringcontent,StringprivateKey)throwsException{
Stringresult;
try(ByteArrayOutputStreamout=newByteArrayOutputStream()){
byte[]keyBytes=newBase64().decode(privateKey);
=newPKCS8EncodedKeySpec(keyBytes);
PrivateKeypKey=keyFactory.generatePrivate(pkcs8KeySpec);
Ciphercipher=Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE,pKey);
byte[]data=content.getBytes(CHARSET);
write2Stream(cipher,data,out);
byte[]resultBytes=out.toByteArray();
result=Base64.encodeBase64String(resultBytes);
}catch(Exceptione){
thrownewException(e);
}
returnresult;
}
/**
*公鑰解密
*
*@paramcontent已加密字元串(BASE64加密)
*@parampublicKey公鑰
*@return
*/
(Stringcontent,StringpublicKey)throwsException{
Stringresult="";
try(ByteArrayOutputStreamout=newByteArrayOutputStream()){
byte[]keyBytes=newBase64().decode(publicKey);
X509EncodedKeySpecx509KeySpec=newX509EncodedKeySpec(keyBytes);
PublicKeypKey=keyFactory.generatePublic(x509KeySpec);
Ciphercipher=Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE,pKey);
byte[]data=Base64.decodeBase64(content);
write2Stream(cipher,data,out);
byte[]resultBytes=out.toByteArray();
result=newString(resultBytes);
}catch(Exceptione){
thrownewException(e);
}
returnresult;
}
/**
*公鑰加密
*
*@paramcontent待加密字元串
*@parampublicKey公鑰
*@return加密後字元串(BASE64編碼)
*/
(Stringcontent,StringpublicKey)throwsException{
Stringresult="";
try(ByteArrayOutputStreamout=newByteArrayOutputStream()){
byte[]keyBytes=newBase64().decode(publicKey);
X509EncodedKeySpecx509KeySpec=newX509EncodedKeySpec(keyBytes);
PublicKeypKey=keyFactory.generatePublic(x509KeySpec);
Ciphercipher=Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE,pKey);
byte[]data=content.getBytes(CHARSET);
write2Stream(cipher,
data,out);
byte[]resultBytes=out.toByteArray();
result=Base64.encodeBase64String(resultBytes);
}catch(Exceptione){
thrownewException(e);
}
returnresult;
}
/**
*私鑰解密
*
*@paramcontent已加密字元串
*@paramprivateKey私鑰
*@return解密後字元串
*/
(Stringcontent,StringprivateKey)throwsException{
Stringresult="";
try(ByteArrayOutputStreamout=newByteArrayOutputStream()){
byte[]keyBytes=newBase64().decode(privateKey);
=newPKCS8EncodedKeySpec(keyBytes);
PrivateKeypKey=keyFactory.generatePrivate(pkcs8KeySpec);
Ciphercipher=Cipher.getInstance(ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE,pKey);
byte[]data=Base64.decodeBase64(content);
write2Stream(cipher,data,out);
byte[]resultBytes=out.toByteArray();
result=newString(resultBytes);
}catch(Exceptione){
thrownewException(e);
}
returnresult;
}
privatestaticvoidwrite2Stream(Ciphercipher,byte[]data,ByteArrayOutputStreamout)throws
BadPaddingException,IllegalBlockSizeException{
intdataLen=data.length;
intoffSet=0;
byte[]cache;
inti=0;
//對數據分段解密
while(dataLen-offSet>0){
if(dataLen-offSet>MAX_DECRYPT_BLOCK){
cache=cipher.doFinal(data,offSet,MAX_DECRYPT_BLOCK);
}else{
cache=cipher.doFinal(data,offSet,dataLen-offSet);
}
out.write(cache,0,cache.length);
i++;
offSet=i*MAX_DECRYPT_BLOCK;
}
}
/**
*用私鑰對信息生成數字簽名
*
*@paramdata已加密數據
*@paramprivateKey私鑰(BASE64編碼)
*@returnsign
*/
publicStringsign(Stringdata,StringprivateKey)throwsException{
Stringresult="";
try{
byte[]keyBytes=newBase64().decode(privateKey);
=newPKCS8EncodedKeySpec(keyBytes);
PrivateKeyprivateK=keyFactory.generatePrivate(pkcs8KeySpec);
Signaturesignature=Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(privateK);
signature.update(parse2HexStr(data).getBytes(CHARSET));
result=newBase64().encodeToString(signature.sign());
}catch(Exceptione){
thrownewException(e);
}
returnresult;
}
/**
*校驗數字簽名
*
*@paramdata已加密數據
*@parampublicKey公鑰(BASE64編碼)
*@paramsign數字簽名
*@return
*@throwsException
*/
publicbooleanverify(Stringdata,StringpublicKey,Stringsign)throwsException{
booleanresult;
try{
byte[]keyBytes=newBase64().decode(publicKey);
X509EncodedKeySpeckeySpec=newX509EncodedKeySpec(keyBytes);
PublicKeypublicK=keyFactory.generatePublic(keySpec);
Signaturesignature=Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(publicK);
signature.update(parse2HexStr(data).getBytes(CHARSET));
result=signature.verify(newBase64().decode(sign));
}catch(Exceptione){
thrownewException(e);
}
returnresult;
}
/**
*將二進制轉換成16進制
*
*@paramdata
*@return
*/
(Stringdata)throwsException{
Stringresult="";
try{
byte[]buf=data.getBytes(CHARSET);
StringBuffersb=newStringBuffer();
for(inti=0;i<buf.length;i++){
Stringhex=Integer.toHexString(buf[i]&0xFF);
if(hex.length()==1){
hex='0'+hex;
}
sb.append(hex.toUpperCase());
}
result=sb.toString();
}catch(UnsupportedEncodingExceptione){
thrownewException(e);
}
returnresult;
}
/**
*生成公鑰與私鑰
*/
publicstaticvoidcreateKey()throwsException{
try{
=KeyPairGenerator.getInstance(ALGORITHM);
keyPairGenerator.initialize(KEY_SIZE);
KeyPairkeyPair=keyPairGenerator.generateKeyPair();
RSAPublicKeyrsaPublicKey=(RSAPublicKey)keyPair.getPublic();
RSAPrivateKeyrsaPrivateKey=(RSAPrivateKey)keyPair.getPrivate();
StringpublicKey=Base64.encodeBase64String(rsaPublicKey.getEncoded());
StringprivateKey=Base64.encodeBase64String(rsaPrivateKey.getEncoded());
System.out.println("publicKey="+publicKey+" privateKey="+privateKey);
}catch(NoSuchAlgorithmExceptione){
thrownewException(e);
}
}
publicstaticvoidmain(String[]args)throwsException{
StringPRIVATE_KEY="+m+/fNs1bmgfJhI8lhr/o/Hy8EFB/I/DDyLcCcU4bCLtxpki8edC+KJR2WvyYfnVmWEe//++W5C+lesEOAqdO5nahRZsL8BIDoxTEn2j+DSa///1qX+t8f5wD8i/8GU702PeCwkGI5ymrARq+/+/nkefTq0SNpUDVbGxVpJi9/FOUf";
StringPUBLIC_KEY="+lc///NfOvKvQndzDH60DzLGOMdE0NBrTn/5zEjGwJbVdlvCfOiHwIDAQAB";
RSAUtilsrsaUtil=newRSAUtils();
StringencryptByPublicKey=rsaUtil.encryptByPublicKey("你好!",PUBLIC_KEY);
System.out.println(encryptByPublicKey);
StringdecryptByPrivateKey=rsaUtil.decryptByPrivateKey(encryptByPublicKey,PRIVATE_KEY);
System.out.println(decryptByPrivateKey);
StringencryptByPrivateKey=rsaUtil.encryptByPrivateKey("你好!",PRIVATE_KEY);
System.out.println(encryptByPrivateKey);
StringdecryptByPublicKey=rsaUtil.decryptByPublicKey(encryptByPrivateKey,PUBLIC_KEY);
System.out.println(decryptByPublicKey);
Stringsign=rsaUtil.sign("1234",PRIVATE_KEY);
System.out.println("sign:"+sign);
System.out.println(rsaUtil.verify("1234",PUBLIC_KEY,sign));
}
}
⑶ Java生成的RSA密鑰對,用C#加密解密,怎麼弄
http://davenzeng.blog.51cto.com/3896952/989634看下這個對你有沒有幫助
⑷ c#怎麼調用java生成的RSA 公鑰進行加密
.NET無法調用JAVA產生的RSA公鑰,必須將RSA演算法在.NET裡面重寫才行,在.NET裡面RSA的公鑰長度是128位的,但是你給出的JAVA公鑰卻是159位長度,非常的不標准,公鑰長度不滿足128的肯定無法給.NET使用。
這里最多幫做個對應解析,數據是肯定無法用的:
將java的RSA公鑰最後四個字母AQAB分割開,用.NET的xml格式表示就是
<RSAKeyValue><Molus>
/qp
jLFfDCu3qytxf+/IoCYE
+Hf4hsEDUKV2kkhRJsnwwID</Molus><Exponent>AQAB</Exponent>
</RSAKeyValue>
這里的數據都是用的BASE64編碼,你用BASE64解碼後可以得到byte[],就可以看到密鑰長度了,實際密鑰要轉換為BigInteger後才能參與RSA核心運算
⑸ RSA 加密演算法(原理篇)
前幾天看到一句話,「我們中的很多人把一生中最燦爛的笑容大部分都獻給了手機和電腦屏幕」。心中一驚,這說明了什麼?手機和電腦已經成為了我們生活中的一部分,所以才會有最懂你的不是你,也不是你男朋友,而是大數據。
如此重要的個人數據,怎樣才能保證其在互聯網上的安全傳輸呢?當然要靠各種加密演算法。說起加密演算法,大家都知道有哈希、對稱加密和非對稱加密了。哈希是一個散列函數,具有不可逆操作;對稱加密即加密和解密使用同一個密鑰,而非對稱加密加密和解密自然就是兩個密鑰了。稍微深入一些的,還要說出非對稱加密演算法有DES、3DES、RC4等,非對稱加密演算法自然就是RSA了。那麼當我們聊起RSA時,我們又在聊些什麼呢?今天筆者和大家一起探討一下,有不足的地方,還望各位朋友多多提意見,共同進步。
RSA簡介:1976年由麻省理工學院三位數學家共同提出的,為了紀念這一里程碑式的成就,就用他們三個人的名字首字母作為演算法的命名。即 羅納德·李維斯特 (Ron Rivest)、 阿迪·薩莫爾 (Adi Shamir)和 倫納德·阿德曼 (Leonard Adleman)。
公鑰:用於加密,驗簽。
私鑰:解密,加簽。
通常知道了公鑰和私鑰的用途以後,即可滿足基本的聊天需求了。但是我們今天的主要任務是來探究一下RSA加解密的原理。
說起加密演算法的原理部分,肯定與數學知識脫不了關系。
我們先來回憶幾個數學知識:
φn = φ(A*B)=φ(A)*φ(B)=(A-1)*(B-1)。
這個公式主要是用來計算給定一個任意的正整數n,在小於等於n的正整數中,有多少個與n構成互質的關系。
其中n=A*B,A與B互為質數,但A與B本身並不要求為質數,可以繼續展開,直至都為質數。
在最終分解完成後,即 φ(N) = φ(p1)*φ(p2)*φ(p3)... 之後,p1,p2,p3都是質數。又用到了歐拉函數的另一個特點,即當p是質數的時候,φp = p - 1。所以有了上面給出的歐拉定理公式。
舉例看一下:
計算15的歐拉函數,因為15比較小,我們可以直接看一下,小於15的正整數有 1、2、3、4、5、6、7、8、9、10、11、12、13、14。和15互質的數有1、2、4、7、8、11、13、14一共四個。
對照我們剛才的歐拉定理: 。
其他感興趣的,大家可以自己驗證。
之所以要在這里介紹歐拉函數,我們在計算公鑰和私鑰時候,會用到。
如果兩個正整數m 和 n 互質,那麼m 的 φn 次方減1,可以被n整除。
其中 .
其中當n為質數時,那麼 上面看到的公式就變成了
mod n 1.
這個公式也就是著名的 費馬小定理 了。
如果兩個正整數e和x互為質數,那麼一定存在一個整數d,不止一個,使得 e*d - 1 可以被x整除,即 e * d mode x 1。則稱 d 是 e 相對於 x的模反元素。
了解了上面所講的歐拉函數、歐拉定理和模反元素後,就要來一些化學反應了,請看圖:
上面這幅圖的公式變化有沒有沒看明白的,沒看明白的咱們評論區見哈。
最終我們得到了最重要的第5個公式的變形,即紅色箭頭後面的:
mod n m。
其中有幾個關系,需要搞明白,m 與 n 互為質數,φn = x,d 是e相對於x的模反元素。
有沒有看到一些加解密的雛形。
從 m 到 m。 這中間涵蓋了從加密到解密的整個過程,但是缺少了我們想要的密文整個過程。
OK,下面引入本文的第四個數學公式:
我們來看一下整個交換流程:
1、客戶端有一個數字13,服務端有一個數字15;
2、客戶端通過計算 3的13次方 對 17 取余,得到數字12; 將12發送給服務端;同時服務端通過計算3的15次方,對17取余,得到數字6,將6發送給客戶端。至此,整個交換過程完成。
3、服務端收到數字12以後,繼續計算,12的15次方 對 17取余,得到 數字10。
4、客戶端收到數字 6以後,繼續計算,6的13次方 對 17 取余,得到數字 10。
有沒有發現雙方,最終得到了相同的內容10。但是這個數字10從來沒有在網路過程中出現過。
好,講到這里,可能有些人已經恍然大悟,這就是加密過程了,但是也有人會產生疑問,為什麼要取數字3 和 17 呢,這里還牽涉到另一個數學知識,原根的問題。即3是17的原根。看圖
有沒有發現規律,3的1~16次方,對17取余,得到的整數是從1~16。這時我們稱3為17的原根。也就是說上面的計算過程中有一組原根的關系。這是最早的迪菲赫爾曼秘鑰交換演算法。
解決了為什麼取3和17的問題後,下面繼續來看最終的RSA是如何產生的:
還記得我們上面提到的歐拉定理嗎,其中 m 與 n 互為質數,n為質數,d 是 e 相對於 φn的模反元素。
當迪菲赫爾曼密鑰交換演算法碰上歐拉定理會產生什麼呢?
我們得到下面的推論:
好,到這里我們是不是已經看到了整個的加密和解密過程了。
其中 m 是明文;c 是密文; n 和 e 為公鑰;d 和 n 為私鑰 。
其中幾組數字的關系一定要明確:
1、d是e 相對於 φn 的模反元素,φn = n-1,即 e * d mod n = 1.
2、m 小於 n,上面在講迪菲赫爾曼密鑰交換演算法時,提到原根的問題,在RSA加密演算法中,對m和n並沒有原根條件的約束。只要滿足m與n互為質數,n為質數,且m < n就可以了。
OK,上面就是RSA加密演算法的原理了,經過上面幾個數學公式的狂轟亂炸,是不是有點迷亂了,給大家一些時間理一下,後面會和大家一起來驗證RSA演算法以及RSA為什麼安全。
⑹ 高分求java的RSA 和IDEA 加密解密演算法
RSA演算法非常簡單,概述如下:
找兩素數p和q
取n=p*q
取t=(p-1)*(q-1)
取任何一個數e,要求滿足e<t並且e與t互素(就是最大公因數為1)
取d*e%t==1
這樣最終得到三個數: n d e
設消息為數M (M <n)
設c=(M**d)%n就得到了加密後的消息c
設m=(c**e)%n則 m == M,從而完成對c的解密。
註:**表示次方,上面兩式中的d和e可以互換。
在對稱加密中:
n d兩個數構成公鑰,可以告訴別人;
n e兩個數構成私鑰,e自己保留,不讓任何人知道。
給別人發送的信息使用e加密,只要別人能用d解開就證明信息是由你發送的,構成了簽名機制。
別人給你發送信息時使用d加密,這樣只有擁有e的你能夠對其解密。
rsa的安全性在於對於一個大數n,沒有有效的方法能夠將其分解
從而在已知n d的情況下無法獲得e;同樣在已知n e的情況下無法
求得d。
<二>實踐
接下來我們來一個實踐,看看實際的操作:
找兩個素數:
p=47
q=59
這樣
n=p*q=2773
t=(p-1)*(q-1)=2668
取e=63,滿足e<t並且e和t互素
用perl簡單窮舉可以獲得滿主 e*d%t ==1的數d:
C:\Temp>perl -e "foreach $i (1..9999){ print($i),last if $i*63%2668==1 }"
847
即d=847
最終我們獲得關鍵的
n=2773
d=847
e=63
取消息M=244我們看看
加密:
c=M**d%n = 244**847%2773
用perl的大數計算來算一下:
C:\Temp>perl -Mbigint -e "print 244**847%2773"
465
即用d對M加密後獲得加密信息c=465
解密:
我們可以用e來對加密後的c進行解密,還原M:
m=c**e%n=465**63%2773 :
C:\Temp>perl -Mbigint -e "print 465**63%2773"
244
即用e對c解密後獲得m=244 , 該值和原始信息M相等。
<三>字元串加密
把上面的過程集成一下我們就能實現一個對字元串加密解密的示例了。
每次取字元串中的一個字元的ascii值作為M進行計算,其輸出為加密後16進制
的數的字元串形式,按3位元組表示,如01F
代碼如下:
#!/usr/bin/perl -w
#RSA 計算過程學習程序編寫的測試程序
#watercloud 2003-8-12
#
use strict;
use Math::BigInt;
my %RSA_CORE = (n=>2773,e=>63,d=>847); #p=47,q=59
my $N=new Math::BigInt($RSA_CORE{n});
my $E=new Math::BigInt($RSA_CORE{e});
my $D=new Math::BigInt($RSA_CORE{d});
print "N=$N D=$D E=$E\n";
sub RSA_ENCRYPT
{
my $r_mess = shift @_;
my ($c,$i,$M,$C,$cmess);
for($i=0;$i < length($$r_mess);$i++)
{
$c=ord(substr($$r_mess,$i,1));
$M=Math::BigInt->new($c);
$C=$M->(); $C->bmodpow($D,$N);
$c=sprintf "%03X",$C;
$cmess.=$c;
}
return \$cmess;
}
sub RSA_DECRYPT
{
my $r_mess = shift @_;
my ($c,$i,$M,$C,$dmess);
for($i=0;$i < length($$r_mess);$i+=3)
{
$c=substr($$r_mess,$i,3);
$c=hex($c);
$M=Math::BigInt->new($c);
$C=$M->(); $C->bmodpow($E,$N);
$c=chr($C);
$dmess.=$c;
}
return \$dmess;
}
my $mess="RSA 娃哈哈哈~~~";
$mess=$ARGV[0] if @ARGV >= 1;
print "原始串:",$mess,"\n";
my $r_cmess = RSA_ENCRYPT(\$mess);
print "加密串:",$$r_cmess,"\n";
my $r_dmess = RSA_DECRYPT($r_cmess);
print "解密串:",$$r_dmess,"\n";
#EOF
測試一下:
C:\Temp>perl rsa-test.pl
N=2773 D=847 E=63
原始串:RSA 娃哈哈哈~~~
加密串:
解密串:RSA 娃哈哈哈~~~
C:\Temp>perl rsa-test.pl 安全焦點(xfocus)
N=2773 D=847 E=63
原始串:安全焦點(xfocus)
加密串:
解密串:安全焦點(xfocus)
<四>提高
前面已經提到,rsa的安全來源於n足夠大,我們測試中使用的n是非常小的,根本不能保障安全性,
我們可以通過RSAKit、RSATool之類的工具獲得足夠大的N 及D E。
通過工具,我們獲得1024位的N及D E來測試一下:
n=EC3A85F5005D
4C2013433B383B
A50E114705D7E2
BC511951
d=0x10001
e=DD28C523C2995
47B77324E66AFF2
789BD782A592D2B
1965
設原始信息
M=
完成這么大數字的計算依賴於大數運算庫,用perl來運算非常簡單:
A) 用d對M進行加密如下:
c=M**d%n :
C:\Temp>perl -Mbigint -e " $x=Math::BigInt->bmodpow(0x11111111111122222222222233
333333333, 0x10001,
D55EDBC4F0
6E37108DD6
);print $x->as_hex"
b73d2576bd
47715caa6b
d59ea89b91
f1834580c3f6d90898
即用d對M加密後信息為:
c=b73d2576bd
47715caa6b
d59ea89b91
f1834580c3f6d90898
B) 用e對c進行解密如下:
m=c**e%n :
C:\Temp>perl -Mbigint -e " $x=Math::BigInt->bmodpow(0x17b287be418c69ecd7c39227ab
5aa1d99ef3
0cb4764414
, 0xE760A
3C29954C5D
7324E66AFF
2789BD782A
592D2B1965, CD15F90
4F017F9CCF
DD60438941
);print $x->as_hex"
(我的P4 1.6G的機器上計算了約5秒鍾)
得到用e解密後的m= == M
C) RSA通常的實現
RSA簡潔幽雅,但計算速度比較慢,通常加密中並不是直接使用RSA 來對所有的信息進行加密,
最常見的情況是隨機產生一個對稱加密的密鑰,然後使用對稱加密演算法對信息加密,之後用
RSA對剛才的加密密鑰進行加密。
最後需要說明的是,當前小於1024位的N已經被證明是不安全的
自己使用中不要使用小於1024位的RSA,最好使用2048位的。
----------------------------------------------------------
一個簡單的RSA演算法實現JAVA源代碼:
filename:RSA.java
/*
* Created on Mar 3, 2005
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
import java.math.BigInteger;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.FileWriter;
import java.io.FileReader;
import java.io.BufferedReader;
import java.util.StringTokenizer;
/**
* @author Steve
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class RSA {
/**
* BigInteger.ZERO
*/
private static final BigInteger ZERO = BigInteger.ZERO;
/**
* BigInteger.ONE
*/
private static final BigInteger ONE = BigInteger.ONE;
/**
* Pseudo BigInteger.TWO
*/
private static final BigInteger TWO = new BigInteger("2");
private BigInteger myKey;
private BigInteger myMod;
private int blockSize;
public RSA (BigInteger key, BigInteger n, int b) {
myKey = key;
myMod = n;
blockSize = b;
}
public void encodeFile (String filename) {
byte[] bytes = new byte[blockSize / 8 + 1];
byte[] temp;
int tempLen;
InputStream is = null;
FileWriter writer = null;
try {
is = new FileInputStream(filename);
writer = new FileWriter(filename + ".enc");
}
catch (FileNotFoundException e1){
System.out.println("File not found: " + filename);
}
catch (IOException e1){
System.out.println("File not found: " + filename + ".enc");
}
/**
* Write encoded message to 'filename'.enc
*/
try {
while ((tempLen = is.read(bytes, 1, blockSize / 8)) > 0) {
for (int i = tempLen + 1; i < bytes.length; ++i) {
bytes[i] = 0;
}
writer.write(encodeDecode(new BigInteger(bytes)) + " ");
}
}
catch (IOException e1) {
System.out.println("error writing to file");
}
/**
* Close input stream and file writer
*/
try {
is.close();
writer.close();
}
catch (IOException e1) {
System.out.println("Error closing file.");
}
}
public void decodeFile (String filename) {
FileReader reader = null;
OutputStream os = null;
try {
reader = new FileReader(filename);
os = new FileOutputStream(filename.replaceAll(".enc", ".dec"));
}
catch (FileNotFoundException e1) {
if (reader == null)
System.out.println("File not found: " + filename);
else
System.out.println("File not found: " + filename.replaceAll(".enc", "dec"));
}
BufferedReader br = new BufferedReader(reader);
int offset;
byte[] temp, toFile;
StringTokenizer st = null;
try {
while (br.ready()) {
st = new StringTokenizer(br.readLine());
while (st.hasMoreTokens()){
toFile = encodeDecode(new BigInteger(st.nextToken())).toByteArray();
System.out.println(toFile.length + " x " + (blockSize / 8));
if (toFile[0] == 0 && toFile.length != (blockSize / 8)) {
temp = new byte[blockSize / 8];
offset = temp.length - toFile.length;
for (int i = toFile.length - 1; (i <= 0) && ((i + offset) <= 0); --i) {
temp[i + offset] = toFile[i];
}
toFile = temp;
}
/*if (toFile.length != ((blockSize / 8) + 1)){
temp = new byte[(blockSize / 8) + 1];
System.out.println(toFile.length + " x " + temp.length);
for (int i = 1; i < temp.length; i++) {
temp[i] = toFile[i - 1];
}
toFile = temp;
}
else
System.out.println(toFile.length + " " + ((blockSize / 8) + 1));*/
os.write(toFile);
}
}
}
catch (IOException e1) {
System.out.println("Something went wrong");
}
/**
* close data streams
*/
try {
os.close();
reader.close();
}
catch (IOException e1) {
System.out.println("Error closing file.");
}
}
/**
* Performs <tt>base</tt>^<sup><tt>pow</tt></sup> within the molar
* domain of <tt>mod</tt>.
*
* @param base the base to be raised
* @param pow the power to which the base will be raisded
* @param mod the molar domain over which to perform this operation
* @return <tt>base</tt>^<sup><tt>pow</tt></sup> within the molar
* domain of <tt>mod</tt>.
*/
public BigInteger encodeDecode(BigInteger base) {
BigInteger a = ONE;
BigInteger s = base;
BigInteger n = myKey;
while (!n.equals(ZERO)) {
if(!n.mod(TWO).equals(ZERO))
a = a.multiply(s).mod(myMod);
s = s.pow(2).mod(myMod);
n = n.divide(TWO);
}
return a;
}
}
在這里提供兩個版本的RSA演算法JAVA實現的代碼下載:
1. 來自於 http://www.javafr.com/code.aspx?ID=27020 的RSA演算法實現源代碼包:
http://zeal.newmenbase.net/attachment/JavaFR_RSA_Source.rar
2. 來自於 http://www.ferrara.linux.it/Members/lucabariani/RSA/implementazioneRsa/ 的實現:
http://zeal.newmenbase.net/attachment/sorgentiJava.tar.gz - 源代碼包
http://zeal.newmenbase.net/attachment/algoritmoRSA.jar - 編譯好的jar包
另外關於RSA演算法的php實現請參見文章:
php下的RSA演算法實現
關於使用VB實現RSA演算法的源代碼下載(此程序採用了psc1演算法來實現快速的RSA加密):
http://zeal.newmenbase.net/attachment/vb_PSC1_RSA.rar
RSA加密的JavaScript實現: http://www.ohdave.com/rsa/
⑺ JAVA裡面RSA加密演算法的使用
RSA的Java實現不能一次加密很大的字元,自己處理了一下,見下面的代碼。Base64編碼類用的是一個Public domain Base64 for java http://iharder.sourceforge.net/current/java/base64/其他的保存公鑰到文件等簡單的實現,就不詳細說了,看代碼吧。==============================================import java.security.*;import java.security.spec.PKCS8EncodedKeySpec;import java.security.spec.X509EncodedKeySpec;import java.util.HashMap;import java.util.Map;import javax.crypto.*;import java.io.*;public class Encryptor {private static final String KEY_FILENAME = "c:\\mykey.dat";private static final String OTHERS_KEY_FILENAME = "c:\\Otherskey.dat";// private static final int KEY_SIZE = 1024;// private static final int BLOCK_SIZE = 117;// private static final int OUTPUT_BLOCK_SIZE = 128;private static final int KEY_SIZE = 2048; //RSA key 是多少位的private static final int BLOCK_SIZE = 245; //一次RSA加密操作所允許的最大長度//這個值與 KEY_SIZE 已經padding方法有關。因為 1024的key的輸出是128,2048key輸出是256位元組//可能11個位元組用於保存padding信息了,所以最多可用的就只有245位元組了。private static final int OUTPUT_BLOCK_SIZE = 256;private SecureRandom secrand;private Cipher rsaCipher;private KeyPair keys;private Map<String, Key> allUserKeys;public Encryptor() throws Exception {try {allUserKeys = new HashMap<String, Key>();secrand = new SecureRandom();//SunJCE Provider 中只支持ECB mode,試了一下只有PKCS1PADDING可以直接還原原始數據,//NOPadding導致解壓出來的都是blocksize長度的數據,還要自己處理//參見 http://java.sun.com/javase/6/docs/technotes/guides/security/SunProviders.html#SunJCEProvider////另外根據 Open-JDK-6.b17-src( http://www.docjar.com/html/api/com/sun/crypto/provider/RSACipher.java.html)// 中代碼的注釋,使用RSA來加密大量數據不是一種標準的用法。所以現有實現一次doFinal調用之進行一個RSA操作,//如果用doFinal來加密超過的一個操作所允許的長度數據將拋出異常。//根據keysize的長度,典型的1024個長度的key和PKCS1PADDING一起使用時//一次doFinal調用只能加密117個byte的數據。(NOPadding 和1024 keysize時128個位元組長度)//(2048長度的key和PKCS1PADDING 最多允許245位元組一次)//想用來加密大量數據的只能自己用其他辦法實現了。可能RSA加密速度比較慢吧,要用AES才行rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING");} catch (NoSuchAlgorithmException e) {e.printStackTrace();} catch (NoSuchPaddingException e) {e.printStackTrace();throw e;}ObjectInputStream in;try {in = new ObjectInputStream(new FileInputStream(KEY_FILENAME));} catch (FileNotFoundException e) {if (false == GenerateKeys()){throw e;}LoadKeys();return;}keys = (KeyPair) in.readObject();in.close();LoadKeys();}/** 生成自己的公鑰和私鑰*/private Boolean GenerateKeys() {try {KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA");// secrand = new SecureRandom();// sedSeed之後會造成 生成的密鑰都是一樣的// secrand.setSeed("chatencrptor".getBytes()); // 初始化隨機產生器//key長度至少512長度,不過好像說現在用2048才算比較安全的了keygen.initialize(KEY_SIZE, secrand); // 初始化密鑰生成器keys = keygen.generateKeyPair(); // 生成密鑰組AddKey("me", EncodeKey(keys.getPublic()));} catch (NoSuchAlgorithmException e) {e.printStackTrace();return false;}ObjectOutputStream out;try {out = new ObjectOutputStream(new FileOutputStream(KEY_FILENAME));} catch (IOException e) {e.printStackTrace();return false;}try {out.writeObject(keys);} catch (IOException e) {e.printStackTrace();return false;} finally {try {out.close();} catch (IOException e) {e.printStackTrace();return false;}}return true;}public String EncryptMessage(String toUser, String Message) throws IOException {Key pubkey = allUserKeys.get(toUser);if ( pubkey == null ){throw new IOException("NoKeyForThisUser") ;}try {//PublicKey pubkey = keys.getPublic();rsaCipher.init(Cipher.ENCRYPT_MODE, pubkey, secrand);//System.out.println(rsaCipher.getBlockSize()); 返回0,非block 加密演算法來的?//System.out.println(Message.getBytes("utf-8").length);//byte[] encryptedData = rsaCipher.doFinal(Message.getBytes("utf-8"));byte[] data = Message.getBytes("utf-8");int blocks = data.length / BLOCK_SIZE ;int lastBlockSize = data.length % BLOCK_SIZE ;byte [] encryptedData = new byte[ (lastBlockSize == 0 ? blocks : blocks + 1)* OUTPUT_BLOCK_SIZE];for (int i=0; i < blocks; i++){//int thisBlockSize = ( i + 1 ) * BLOCK_SIZE > data.length ? data.length - i * BLOCK_SIZE : BLOCK_SIZE ;rsaCipher.doFinal(data,i * BLOCK_SIZE, BLOCK_SIZE, encryptedData ,i * OUTPUT_BLOCK_SIZE);}if (lastBlockSize != 0 ){rsaCipher.doFinal(data, blocks * BLOCK_SIZE, lastBlockSize,encryptedData ,blocks * OUTPUT_BLOCK_SIZE);}//System.out.println(encrypted.length); 如果要機密的數據不足128/256位元組,加密後補全成為變為256長度的。//數量比較小時,Base64.GZIP產生的長度更長,沒什麼優勢//System.out.println(Base64.encodeBytes(encrypted,Base64.GZIP).length());//System.out.println(Base64.encodeBytes(encrypted).length());//System.out.println (rsaCipher.getOutputSize(30));//這個getOutputSize 只對 輸入小於最大的block時才能得到正確的結果。其實就是補全 數據為128/256 位元組return Base64.encodeBytes(encryptedData);} catch (InvalidKeyException e) {e.printStackTrace();throw new IOException("InvalidKey") ;}catch (ShortBufferException e) {e.printStackTrace();throw new IOException("ShortBuffer") ;}catch (UnsupportedEncodingException e) {e.printStackTrace();throw new IOException("UnsupportedEncoding") ;} catch (IllegalBlockSizeException e) {e.printStackTrace();throw new IOException("IllegalBlockSize") ;} catch (BadPaddingException e) {e.printStackTrace();throw new IOException("BadPadding") ;}finally {//catch 中 return 或者throw之前都會先調用一下這里}}public String DecryptMessage(String Message) throws IOException {byte[] decoded = Base64.decode(Message);PrivateKey prikey = keys.getPrivate();try {rsaCipher.init(Cipher.DECRYPT_MODE, prikey, secrand);int blocks = decoded.length / OUTPUT_BLOCK_SIZE;ByteArrayOutputStream decodedStream = new ByteArrayOutputStream(decoded.length);for (int i =0 ;i < blocks ; i ++ ){decodedStream.write (rsaCipher.doFinal(decoded,i * OUTPUT_BLOCK_SIZE, OUTPUT_BLOCK_SIZE));}return new String(decodedStream.toByteArray(), "UTF-8");} catch (InvalidKeyException e) {e.printStackTrace();throw new IOException("InvalidKey");} catch (UnsupportedEncodingException e) {e.printStackTrace();throw new IOException("UnsupportedEncoding");} catch (IllegalBlockSizeException e) {e.printStackTrace();throw new IOException("IllegalBlockSize");} catch (BadPaddingException e) {e.printStackTrace();throw new IOException("BadPadding");} finally {// catch 中 return 或者throw之前都會先調用一下這里。}}public boolean AddKey(String user, String key) {PublicKey publickey;try {publickey = DecodePublicKey(key);} catch (Exception e) {return false;}allUserKeys.put(user, publickey);SaveKeys();return true;}private boolean LoadKeys() {BufferedReader input;try {input = new BufferedReader(new InputStreamReader(new FileInputStream(OTHERS_KEY_FILENAME)));} catch (FileNotFoundException e1) {// e1.printStackTrace();return false;}
⑻ 求一個實現RSA加解密的程序源碼 匯編 JAVA C 都可以
首先你要了解rsa演算法和會用c語言
然後到網上搜索大數運算庫
因為rsa得大數運算分解要用到它
首先你要了解rsa演算法和會用c語言
然後到網上搜索大數運算庫
⑼ RSA加解密原理以及三種填充模式
如果需要理解RSA的加密原理,需要理解以下理論:
等同於求一元二次方程 23 * d + 192 * y = 1
可以求得其中一解為(d=167,y=-20)
至此就完成了所有的計算
對於上述例子的到公鑰(221,23)和私鑰(221,167)
在上述的計算過程中一共用到了
上面用到的數中只有公鑰部分是公開的,即(221,23)。那麼我們是否可以通過公鑰來推到出私鑰部分,即已知n和e,推到出d?
(1)ed 1(mod (n)),只有知道 (n)才能解出d
(2) (n)= (p) (q)= (p-1) (q-1),只有知道p和q才能得到 (n)
(3)n=p q,就需要對n進行因式分解
那麼如果可以對n因式分解就可以求出d,也就意味著私匙被破解
那麼RSA加密的可靠性就在於對n因式分解的難度,而現在對一個整數n做因式分解並沒有巧妙的演算法,只有通過暴力破解計算。在實際應用中的n取值通常在1024位以上,而公開已知的可因式分解的最大數為768位。所以現階段來說RSA加密是可靠的。
現在我們就可以進行加密和解密了
我們使用上面生成的公鑰(221,23)來加密。如果我們需要加密的信息是m( m必須為整數並且m要小於n ),m取56,可以用以下公式求出加密串c:
c (mod n)
10 (mod 221)
可以求出加密後的結果c為10
密鑰為(221,167),加密結果c=10,可以使用以下公式求出被加密的信息
m (mod n) 即加密結果的d次方除以n的余數為m
56 (mod 221)
RSA加密屬於塊加密演算法,總是在一個固定長度的塊上進行操作。如果被加密的字元串過長,則需要對字元串進行切割,如果字元串過短則需要進行填充。
以下主介紹一下RSA_PKCS1_PADDING填充模式以及RSA_NO_PADDING模式
此填充模式是最常用的填充模式,在此填充模式下輸入的長度受加密鑰的長度限制,輸入的最大長度為加密鑰的位數k-11。如果公鑰的長度為1024位即128位元組,那麼輸入的長度最多為128-11=117位元組。如果長度小於117就需要填充。如果輸入T的長度為55位元組,填充後的塊為EM,則EM格式如下:
EM= 0x00 || BT || PS || 0x00 || T
在此填充模式下,輸入的長度最多和RSA公鑰長度一樣長,如果小於公鑰長度則會在前面填充0x00。如果公鑰長度是128位元組,輸入T的長度為55位元組,填充後的塊為EM,則EM格式如下:
EM=P || T
參考:
http://www.ruanyifeng.com/blog/2013/06/rsa_algorithm_part_one.html
http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html
https://my.oschina.net/3pgp/blog/749195