Day22:安全性和演算法-公开金钥密码系统(Public-key Cryptosystem)

前言

前一天有提到共用金钥密码系统(Shared-key CryptoSystem),又称为「对称密钥演算法」(Symmetric-key algorithm),稍微复习一下,Shared-key CryptoSystem是公钥与私钥为同一把「key」的系统,安全性相较於今天所提到的Public-key Cryptosystem来得低。


公开金钥密码系统(Public-key Cryptosystem)

公开金钥密码系统(Public-key Cryptosystem)又称为非对称式密码学(Asymmetric cryptography)。与前一天提到的共同金钥密码系统不同,他拥有两把「key」,分别用於加密(公钥,Publickey)与解密(私钥,Privatekey),安全性比共同金钥密码来得高,看看下图:

参考资料:基础密码学(对称式与非对称式加密技术

从上图可以看到,公钥与私钥非同一把,有心人士拿到了公钥,也无法解读讯息,大大加深了安全性。

公钥(Publickey)与私钥(Privatekey)为一组,Publickey加密後,必须有对应的Privatekey才能进行解密。

优点:安全性高,仅拿到Publickey是无法解密。
缺点:加密和解密花费时间长、速度慢,只适合对少量资料进行加密。不适用於连续传输零碎数据的情况,若要解决连续传输零碎数据,解决方法是使用「混成密码系统」

可信度-数位凭证

关於公开金钥可信度问题的成因是,A无法判断接收到的公开金钥制作者是否为为B,需要利用「数位凭证」。关於「数位凭证」,之後会有进一步探讨。


公开金钥密码系统使用的演算法为「RSA加密」和「椭圆曲线密码学」(elliptic-curve cryptography),接下来我们来看看使用Python和JavaScript如何实现:

Python在Public-key Cryptosystem的实现

要找出实现公开金钥密码系统演算法必要条件:

  1. 能用某个数加密(计算)数据
  2. 能用其他的数来计算还原原始数据
  3. 能防止从一个金钥推算出另一个金钥的运算

产生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"))

JavaScript在Public-key Cryptosystem的实现

安装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


<<:  [Day7]Where子句

>>:  [CodeIgniter 3] 记忆体的隐形杀手:Log all queries

Day-16 回呼函式、高阶函式与IIFE

回呼函式 所谓回呼函式(callback function)与一般函式基本相同,差别在於它须「具一定...

[Lesson14] Retrofit

在 gradle (Module) 层级的 dependencies 中内加入: implement...

Day 6:AWS是什麽?30天从动漫/影视作品看AWS服务应用 -伊藤计划《和谐》

(不写code,有点不懂但看起来超酷的呈现方式) 先小小悼念一下作者伊藤计划,天才英年早逝,如果仍...

Day 14 - Asynchronous 非同步核心

前言 非同步一直是困扰着 Javascript 新手的小魔王,以前常常会有「为什麽这行先跑到没有先执...

[Day8]Rare Easy Problem

上一篇介绍了2 the 9s,是一题会需要重复执行的题目,使用回圈跟副程序会比较容易执行,整体上不会...