RSA密鑰一般是1024位或2048位,位指的是二進位數
第一步:隨便找兩個質數a b
質數表http://www.baike.com/wiki/质数表
第二步:計算φ(axb)
歐拉函數φ(n)的意思為:小於n並與n互質之數的數量。
Copy 23x29 = 667
φ(667)根據歐拉定理得到為(23-1)*(29-1) = 616
第三步: 隨便找一個數字e,使得1< e < φ(axb)的數字,且e与φ(axb)互質
第四步: 找到一個數字d,使得 ed ≡ 1 (mod φ(n)) 意思為尋找 (19*X) % 616 = 1
Copy //以上面為例子
function te() {
let X = 0
while((19*X) % 616 !== 1) {
X++;
}
return X
}
//回傳227
第五步: 剛才找出n = 667, e = 19 , d = 227
得到公鑰為(667, 19) 私鑰為(667, 227)
如果n可以被輕易被因數分解,d就可以算出,而私鑰將被破解
# 加密
假設字串是ABC,轉為ASCII 為65,66,67
而msg輸入數字過大也會產生解密後和輸入數字不同之情況
建議將密文以單字為單位轉為ascII然後個別存入陣列轉換
所以我們把ABC分為三個65,66,67分別加解密再組合起來
1.先算字母A
這時加密的公鑰匙為(667, 19) 所以加密方式為
這裡因為數字是Big int所以算的時候不可直接用...**...% ...,需要用相關Big INT模組不然會產生計算錯誤
不可用chrome devtool直接計算,結果會不同
建議可以用python的command,因其內建Bigint
Copy 打開command輸入python
然後(65 ** 19 ) % 667
得到數字451
# 解密
私鑰匙是(667, 227)
現在要把剛才的數字 451 解密
這裡牽涉到BIg integer時常會出現infinity
需要使用Big-integer module或是參考費馬小定理>https://zh.wikipedia.org/wiki/费马小定理
最後得到剛才的65即完成
以下為用js的big-integer模組,分別計算字母再連接的Function
Copy var bigInt = require("big-integer");
let msg = "ABC";
let final = [];
msg.split('').forEach(char => { // 每個字母分為Array一個元素
let ascii = char.charCodeAt(0); // 轉為ASCII
let a = bigInt(ascii).pow(19).mod(667); // 用公鑰加密
let b = bigInt(a).pow(227).mod(667); //// 用私鑰解密
final.push(b.toString());
})
let decrypt = final.map(d => {
return String.fromCharCode(parseInt(d)); // 轉為string
})
console.log(decrypt)
Node.js之RSA加解密
OpenSSL之Encrypt與Decrypt
1.產生PEM格式的私鑰
預設產生長度為 512 bit 在最後可加數字1024 、2048或 4096 產生不同長度私鑰
Copy openssl genrsa -out private.pem
2.從剛才的私鑰來產生對應的PEM格式之公鑰
Copy openssl rsa -in private.pem -out public.pem -outform PEM -pubout
3.產生一個稍後用來加密的檔案
Copy echo 'some data' > test.txt
然後檔案內容隨意輸入
4.用公鑰加密test.txt檔案,將會產生encrypt.rsa檔案
Copy openssl rsautl -encrypt -inkey public.pem -pubin -in test.txt -out encrypt.rsa
如檔案大小過大會產生錯誤
5.用私鑰解密檔案
Copy openssl rsautl -decrypt -inkey private.pem -in encrypt.rsa -out decrypt.txt
6.最後查看解密後的檔案內容
即可看到成功還原為原本檔案之檔案內容
OpenSSL之Sign與Verify
1.產生PEM格式的私鑰
預設產生長度為 512 bit 在最後可加數字1024 、2048或 4096 產生不同長度私鑰
Copy openssl genrsa -out private.pem
1.從剛才的私鑰來產生對應的PEM格式之公鑰
Copy openssl rsa -in private.pem -out public.pem -outform PEM -pubout
2.簽名
Copy echo -n "hello" | openssl dgst -RSA-SHA256 -sign private.pem > signed_message
3.驗證
Copy echo -n "hello" | openssl dgst -RSA-SHA256 -verify public.pem -signature signed_message
成功會回傳
使用Node.js驗證
Copy var fs = require ( 'fs' );
var crypto = require ( 'crypto' );
var verify = crypto .createVerify ( 'RSA-SHA256' );
verify .update ( 'hello' );
var res = verify .verify ( fs .readFileSync ( './public.pem' ) ,
fs .readFileSync ( './signed_message' ));
console .log (res);
上面程式為在OpenSSL用私鑰簽名後給Node.js驗證
下面程式為全部使用Node.js簽名與驗證
Copy const crypto = require ( 'crypto' );
const fs = require ( 'fs' );
var private_key = fs .readFileSync ( './private.pem' )
var public_key = fs .readFileSync ( './public.pem' )
private_key = private_key .toString ();
public_key = public_key .toString ();
const sign = crypto .createSign ( 'RSA-SHA256' );
sign .update ( 'test' );
signature = sign .sign (private_key , 'hex' );
const verify = crypto .createVerify ( 'RSA-SHA256' );
verify .update ( 'test' );
output = verify .verify (public_key , signature , 'hex' );
console .log (output)
其他知識
Copy DER (Distinguished Encoding Rules):
二進位內容,屬於 ASN.1 制定的編碼之一
PEM (Privacy-enhanced Electronic Mail):
為 DER 格式經過 BASE64 編碼後,通常會有 ----- BEGIN XXX ----- / ----- END XXX ----- 之類的東西包夾起來。由於 PEM 格式採用了 BASE64 編碼,文字都被編成常用的英文數字符號,方便於網路上傳送及複製 (如即時通訊、電子郵件等)。OpenSSL 預設產生的檔案都是 PEM 格式