前一天有提到共用金鑰密碼系統(Shared-key CryptoSystem),又稱為「對稱密鑰演算法」(Symmetric-key algorithm),稍微複習一下,Shared-key CryptoSystem是公鑰與私鑰為同一把「key」的系統,安全性相較於今天所提到的Public-key Cryptosystem來得低。
公開金鑰密碼系統(Public-key Cryptosystem)又稱為非對稱式密碼學(Asymmetric cryptography)。與前一天提到的共同金鑰密碼系統不同,他擁有兩把「key」,分別用於加密(公鑰,Publickey)與解密(私鑰,Privatekey),安全性比共同金鑰密碼來得高,看看下圖:
從上圖可以看到,公鑰與私鑰非同一把,有心人士拿到了公鑰,也無法解讀訊息,大大加深了安全性。
公鑰(Publickey)與私鑰(Privatekey)為一組,Publickey加密後,必須有對應的Privatekey才能進行解密。
優點:安全性高,僅拿到Publickey是無法解密。
缺點:加密和解密花費時間長、速度慢,只適合對少量資料進行加密。不適用於連續傳輸零碎數據的情況,若要解決連續傳輸零碎數據,解決方法是使用「混成密碼系統」
關於公開金鑰可信度問題的成因是,A無法判斷接收到的公開金鑰製作者是否為為B,需要利用「數位憑證」。關於「數位憑證」,之後會有進一步探討。
公開金鑰密碼系統使用的演算法為「RSA加密」和「橢圓曲線密碼學」(elliptic-curve cryptography),接下來我們來看看使用Python和JavaScript如何實現:
要找出實現公開金鑰密碼系統演算法必要條件:
產生RSA 金鑰:
from Crypto.PublicKey import RSA
# 產生 2048 位元 RSA 金鑰
key = RSA.generate(2048)
# RSA 私鑰
privateKey = key.export_key()
with open("private.pem", "wb") as f:
f.write(privateKey)
# RSA 公鑰
publicKey = key.publickey().export_key()
with open("public.pem", "wb") as f:
f.write(publicKey)
讀取 RSA 金鑰:
from Crypto.PublicKey import RSA
# 讀取
encodedKey = open("private.pem", "rb").read()
# 解密
key = RSA.import_key(encodedKey)
# 輸出 RSA 私鑰
print(key.export_key().decode('utf-8'))
print(key.publickey().export_key().decode('utf-8'))
RSA 金鑰解密資料:
from Crypto.PublicKey import RSA
from Crypto.Cipher import AES, PKCS1_OAEP
# 讀取 RSA 私鑰
privateKey = RSA.import_key(open("private.pem").read())
# 從檔案讀取加密資料
with open("encrypted_data.bin", "rb") as f:
encSessionKey = f.read(privateKey.size_in_bytes())
nonce = f.read(16)
tag = f.read(16)
ciphertext = f.read(-1)
# 以 RSA 金鑰解密 Session 金鑰
cipherRSA = PKCS1_OAEP.new(privateKey)
sessionKey = cipherRSA.decrypt(encSessionKey)
# 以 AES Session 金鑰解密資料
cipherAES = AES.new(sessionKey, AES.MODE_EAX, nonce)
data = cipherAES.decrypt_and_verify(ciphertext, tag)
# 輸出解密後的資料
print(data.decode("utf-8"))
安裝node.js後,在安裝npm,利用npm安裝下列庫:
npm install tweetnacl tweetnacl-util
//import the libraries
const nacl = require('tweetnacl');
nacl.util = require('tweetnacl-util');
//Generate the keys
const david = nacl.box.keyPair();
const viktoria = nacl.box.keyPair();
//encrypting the message
function davidEncrypting(){
const one_time_code = nacl.randomBytes(24);
//Get the message from david
const plain_text = "Hello there Viktoria";
//Get the cipher text
const cipher_text = nacl.box(
nacl.util.decodeUTF8(plain_text),
one_time_code,
viktoria.publicKey,
david.secretKey
);
//message to be sent to Viktoria
const message_in_transit = {cipher_text,one_time_code};
return message_in_transit;
};
//decrypting the message
function viktoriaDecrypting(message){
//Get the decoded message
let decoded_message = nacl.box.open(message.cipher_text, message.one_time_code, david.publicKey, viktoria.secretKey);
//Get the human readable message
let plain_text = nacl.util.encodeUTF8(decoded_message)
//return the plaintext
return plain_text;
};
參考資料:Implementing Public Key Cryptography in JavaScript