顯示具有 Signature 標籤的文章。 顯示所有文章
顯示具有 Signature 標籤的文章。 顯示所有文章

2014年3月18日 星期二

Python M2Crypto - X.509 Certificate Sign Request 與 Sign Certificate


X.509 憑證基本觀念

X.509 是由 ITU-T 所製定的 PKI 標準,它主要包含以下 4 個規範:
  1. public key certificates
  2. certificate revocation lists
  3. attribute certificates
  4. certification path validation algorithm
X.509 的憑證簽發關係的概念圖如下:


產生 Root CA Certificate

  • 產生一把 RSA key pair (public / private keys) 
  • 準備一個 Root CA 憑證, 以及所需要的資訊,並且設定有效期限(一般來說是10~20年)。
  • 設定此 Root CA 憑證的 X.509 V3 的 Extension 
  • 用此 Root CA 的 RSA private key 來簽署這個憑證( Self-Signed Root CA Certificate)
產生 Self-Signed Root CA Certificate 的基本範例程式:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
import M2Crypto
import time
import os
import struct
from M2Crypto import X509, EVP, ASN1

def generate_rsa_keypair(key_len, exponent):
    def empty_callback():
        pass
    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    return rsa

def create_self_signed_RootCA_certificate(root_ca_info, sign_method="sha256", days=3650):
    # Setp 1: Create RSA-key pair (public/private key)
    rsa = generate_rsa_keypair(2048, 65537)
    private_key = EVP.PKey()
    private_key.assign_rsa(rsa)
    
    # Step 2-1: Prepare X.509 Certificate Signed Request
    req = X509.Request()
    req.set_pubkey(private_key)
    x509_name = req.get_subject()
    x509_name.C = root_ca_info["C"]
    x509_name.CN = root_ca_info["CN"]
    x509_name.ST = root_ca_info["ST"]
    x509_name.L = root_ca_info["L"]
    x509_name.O = root_ca_info["O"]
    x509_name.OU = root_ca_info["OU"]
    req.sign(private_key,sign_method)
    # Step 2-2: Prepare X.509 certificate
    root_ca_cert = X509.X509()
    
    serial = struct.unpack("<Q", os.urandom(8))[0]
    root_ca_cert.set_serial_number(serial)
    root_ca_cert.set_version(3)
    # Setp 2-3: Set required information of RootCA certificate
    root_ca_cert.set_issuer(x509_name)
    root_ca_cert.set_subject(root_ca_cert.get_issuer())
    root_ca_cert.set_pubkey(req.get_pubkey())  # Get the CSR's public key    

    # Step 2-4: Set Valid Date for RootCA certificate
    t = long(time.time())
    now = ASN1.ASN1_UTCTIME()
    now.set_time(t)
    expire = ASN1.ASN1_UTCTIME()
    expire.set_time(t + days * 24 * 60 * 60)
    root_ca_cert.set_not_before(now)
    root_ca_cert.set_not_after(expire)
    # Step 3: Add Extensions for this Root CA certificate
    root_ca_cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE'))
    root_ca_cert.add_ext(X509.new_extension('subjectKeyIdentifier', root_ca_cert.get_fingerprint()))
    
    # Step 4: Use Root CA's RSA private key to sign this certificate
    root_ca_cert.sign(private_key, sign_method)
    return root_ca_cert, private_key

if __name__ == '__main__':
    # Generate a Self-Signed Root CA Certificate
    root_ca_info = {}
    root_ca_info['C'] = "TW"
    root_ca_info['CN'] = "Root CA Certificate"
    root_ca_info['ST'] = "Taiwan"
    root_ca_info['O'] = "ijeCorp Ltd."
    root_ca_info['OU'] = "Security"
    root_ca_info['L'] = "Taipei"
    
    root_ca_cert, private_key = create_self_signed_RootCA_certificate(root_ca_info)
    with open('root_ca_cert.crt', 'w') as f:
        f.write(root_ca_cert.as_pem())
    with open('root_ca_private_key.pem', 'w') as f:
        f.write(private_key.as_pem(cipher=None))
    with open('root_ca_public_key.pem', 'w') as f:
        f.write(root_ca_cert.get_pubkey().as_pem(cipher=None))


產生 Certificate Signed Certificate 

  • 產生一把 RSA key pair (public/private key)
  • 準備一個 X.509 Request 
  • 設定 X.509 Request 的資訊
  • 用 RSA private key 去簽署這個 X.509 Request
產生 Certificate Signed Certificate (CSR) 的基本範例程式:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import M2Crypto
from M2Crypto import X509, EVP

def generate_rsa_keypair(key_len, exponent):
    def empty_callback():
        pass

    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    return rsa

def create_Signed_Certificate_Request(csr_info, key_len=2048, sign_method="sha256"):
    # Step 1: Create a RSA key pair (public/private key)
    rsa_keypair = generate_rsa_keypair(key_len, 65537)
    evp_private_key = EVP.PKey()
    evp_private_key.assign_rsa(rsa_keypair)
    # Step 2: Create a X.509 request 
    csr = X509.Request()
    csr.set_pubkey(evp_private_key)
    # Step 3: Set CSR information
    x509_name = csr.get_subject()
    x509_name.C = csr_info['C']
    x509_name.CN = csr_info['CN']
    x509_name.ST = csr_info['ST']
    x509_name.O = csr_info['O']
    x509_name.OU = csr_info['OU']
    x509_name.L = csr_info['L']

    # Step 4: Use RSA private key to sign it
    csr.sign(evp_private_key, sign_method)
    return csr, evp_private_key

if __name__ == '__main__':
    # Generate CSR for signed Certificate
    csr_info = {}
    csr_info['C'] = "TW"
    csr_info['CN'] = "CA-Certificate"
    csr_info['ST'] = "Taiwan"
    csr_info['O'] = "AbcCorp Ltd."
    csr_info['OU'] = "ABC-CA"
    csr_info['L'] = "Taipei"

    csr, private_key = create_Signed_Certificate_Request(csr_info);

    with open('CSR.pem', 'w') as f:
        f.write(csr.as_pem())
    with open('CSR_private_key.pem', 'w') as f:
        f.write(private_key.as_pem(cipher = None))

Root CA 或是 CA 根據 CSR 簽署一個 Certificate

  • 準備一個 X.509 的憑證
  • 設定 X.509 憑證的有效期限, 有效時間的長短根據需求而有不同
  • 設定 X.509 的 Extension 資訊
  • 根據 CSR 所提供的 subject 以及 public key 來設定 X.509 憑證
  • 使用 Root CA 或是 CA 的 RSA private key 來簽署這個 X.509 憑證
Root CA 根據 CSR 產生 Certificate 的基本範例程式:
此範例程式,只需要研讀 Line 130~133 與 Line 14~47 即可,它是直接以 Root CA 的 private key並且依據 CSR 來簽署憑證


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import M2Crypto
import time
import os
import struct
from M2Crypto import X509, EVP, ASN1

def generate_rsa_keypair(key_len, exponent):
    def empty_callback():
        pass

    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    return rsa

def create_certificate_from_CSR(rootCA_cert, rootCA_private_key, csr, days = 365):
    # Step 1: Prepare X.509 Certificate
    cert = X509.X509()
    serial = struct.unpack("<Q", os.urandom(8))[0]
    cert.set_serial_number(serial)
    cert.set_version(3)
    # Step 2: Set Expired Date
    t = long(time.time())
    now = ASN1.ASN1_UTCTIME()
    now.set_time(t)
    expire = ASN1.ASN1_UTCTIME()
    expire.set_time(t + days * 24 * 60 * 60)
    cert.set_not_before(now)
    cert.set_not_after(expire)
    # Step 3: Set X.509 Extensions
    cert.add_ext(X509.new_extension('nsComment', 'SSL sever'))
    cert.add_ext(X509.new_extension('keyUsage', 'Digital Signature')) 
    cert.add_ext(X509.new_extension('keyUsage', 'Key Encipherment', 1)) # 1 means critical
    cert.add_ext(X509.new_extension('keyUsage', 'Data Encipherment',1))
    cert.add_ext(X509.new_extension('keyUsage', 'Key Agreement', 1))
    cert.add_ext(X509.new_extension('extendedKeyUsage', 'clientAuth'))
    cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE'))
    cert.add_ext(X509.new_extension('subjectAltName', 'DNS:www.ijecorp.com'))
    PCI_FULL = "critical, language:Inherit all"
    PCI_LIMITED = "critical, language:1.3.6.1.4.1.3536.1.1.1.9"
    cert.add_ext(X509.new_extension('proxyCertInfo',PCI_FULL, 1))
    # Step 4: Set Subject and Public Key from CSR
    cert.set_issuer(rootCA_cert.get_issuer())
    cert.set_subject(csr.get_subject())
    cert.set_pubkey(csr.get_pubkey())
    # Step 5: Use Private Key of Root CA or CA to sign this X.509 certificate
    cert.sign(rootCA_private_key, 'sha256')

    return cert

def create_Signed_Certificate_Request(csr_info, key_len=2048, sign_method="sha256"):
    # Step 1: Create a RSA key pair (public/private key)
    rsa_keypair = generate_rsa_keypair(key_len, 65537)
    evp_private_key = EVP.PKey()
    evp_private_key.assign_rsa(rsa_keypair)
    # Step 2: Create a X.509 request 
    csr = X509.Request()
    csr.set_pubkey(evp_private_key)
    # Step 3: Set CSR information
    x509_name = csr.get_subject()
    x509_name.C = csr_info['C']
    x509_name.CN = csr_info['CN']
    x509_name.ST = csr_info['ST']
    x509_name.O = csr_info['O']
    x509_name.OU = csr_info['OU']
    # Step 4: Use RSA private key to sign it
    csr.sign(evp_private_key, sign_method)
    return csr, evp_private_key

def create_self_signed_RootCA_certificate(root_ca_info, sign_method="sha256", days=3650):
    # Setp 1: Create RSA-key pair (public/private key)
    rsa = generate_rsa_keypair(2048, 65537)
    private_key = EVP.PKey()
    private_key.assign_rsa(rsa)
    # Step 2-1: Prepare X.509 Certificate Signed Request
    req = X509.Request()
    req.set_pubkey(private_key)
    x509_name = req.get_subject()
    x509_name.C = root_ca_info["C"]
    x509_name.CN = root_ca_info["CN"]
    x509_name.ST = root_ca_info["ST"]
    x509_name.L = root_ca_info["L"]
    x509_name.O = root_ca_info["O"]
    x509_name.OU = root_ca_info["OU"]
    req.sign(private_key,sign_method)
    # Step 2-2: Prepare X.509 certificate
    root_ca_cert = X509.X509()
    serial = struct.unpack("<Q", os.urandom(8))[0]
    root_ca_cert.set_serial_number(serial)
    root_ca_cert.set_version(3)
    # Setp 2-3: Set required information of RootCA certificate
    root_ca_cert.set_issuer(x509_name)
    root_ca_cert.set_subject(root_ca_cert.get_issuer())
    root_ca_cert.set_pubkey(req.get_pubkey())  # Get the CSR's public key    

    # Step 2-4: Set Valid Date for RootCA certificate
    t = long(time.time())
    now = ASN1.ASN1_UTCTIME()
    now.set_time(t)
    expire = ASN1.ASN1_UTCTIME()
    expire.set_time(t + days * 24 * 60 * 60)
    root_ca_cert.set_not_before(now)
    root_ca_cert.set_not_after(expire)
    # Step 3: Add Extensions for this Root CA certificate
    root_ca_cert.add_ext(X509.new_extension('basicConstraints', 'CA:TRUE'))
    root_ca_cert.add_ext(X509.new_extension('subjectKeyIdentifier', root_ca_cert.get_fingerprint()))
    
    # Step 4: Use Root CA's RSA private key to sign this certificate
    root_ca_cert.sign(private_key, sign_method)
    return root_ca_cert, private_key

if __name__ == '__main__':
    # Generate a Self-Signed Root CA Certificate
    root_ca_info = {}
    root_ca_info['C'] = "TW"
    root_ca_info['CN'] = "Root CA Certificate"
    root_ca_info['ST'] = "Taiwan"
    root_ca_info['O'] = "ijeCorp Ltd."
    root_ca_info['OU'] = "Security"
    root_ca_info['L'] = "Taipei"
    root_ca_cert, root_ca_private_key = create_self_signed_RootCA_certificate(root_ca_info)

    # Generate CSR for signed Certificate
    csr_info = {}
    csr_info['C'] = "TW"
    csr_info['CN'] = "MyCompany-Certificate"
    csr_info['ST'] = "."
    csr_info['O'] = "ijeCorp Ltd."
    csr_info['OU'] = "Security"
    csr, ca_private_key = create_Signed_Certificate_Request(csr_info);

    # Use Root CA's private key to sign a certificate from CSR
    cert = create_certificate_from_CSR(root_ca_cert, root_ca_private_key, csr)
    with open('my_cert.crt', 'w') as f:
        f.write(cert.as_pem()) 
以上的範例程式都是採用 SHA-256 是基於安全性的考量,請參考[2]

Reference:
[1] http://svn.osafoundation.org/m2crypto/trunk/contrib/SimpleX509create.py
[2] http://www.tbs-certificates.co.uk/FAQ/en/475.html


2013年8月18日 星期日

Python M2Crypto - RSA 的 Encrypt, Decrypt, Sign and Verify

        這裡要介紹一些RSA基本知識,以及如何產生一把 RSA 的非對稱式(asymmetric) 公開金鑰 (public key)和 私有金鑰(private key)。並且用一個簡單的範例程式來解釋如何用RSA來進行加密解密和簽章驗證的應用。

RSA的基本知識和重要名詞

        RSA是一種asymmetric演算法,它是透過一組public key和private key來進行Encrypt/Decrypt或是Sign/Verify。它的優點是:資料交換過程當中,雙方只需要拿到對方的public key即可加密資料,然後將加密後的密文(cipher)傳送給對方。只有正確的接收者才會有private key能夠解出密文(cipher)。缺點是,加密或是解密的效能較差不適合用於大量的資料加密。RSA的private key的建議長度最少是1024 bits以上,才具有基本的安全性, private key長度越長所需要的加解密運算成本越高,相對也會更加安全。

Key Length

        RSA 的Key Length 決定了RSA被破解的強度,長度越長基本上越難以被破解。但是,不是永遠不能破解,只是目前還沒有提出有效的破解方法。

Public Exponent

        公開指數是為了滿足RSA演算法所需要的一個整數,而且必須是質數Exponent ,然而很多密碼學的函式庫所內建的RSA Public Exponent都是65537的質數。有個討論在探討RSA Public Exponent 選擇 3 是否不夠安全的問題,有興趣的可以參考這網頁。無論如何,基本上選擇 65537的質數應該是一個較為安全且建議的作法。雖然選擇過大的質數會影響解密和驗證的效率,但是除非是要應用在運算能力非常弱的環境上,否則選擇小的質數當作Public Exponent應該不建議的,特別是Padding Mode很差的情形。但是,若選用合適的Padding Mode時,即使選擇3當作 RSA Public Exponent對於安全性並沒有太大的不同。

Padding Mode

        RSA基本上必須透過隨機的Padding方式,以確保即使每次都加密相同明文(Plan-Text)時候,不會產生完全相同的密文(Cipher-Text)。而OpenSSL支援 4 種 Padding Modes,以下截取自OpenSSL官方文件。而M2Crypto目前只支援 RSA_PKCS1_PADDING 和 RSA_PKCS1_OAEP_PADDING,根據官方文件上的建議就是使用 RSA_PKCS1_OAEP_PADDING。
RSA_PKCS1_PADDING
RSA_PKCS1_OAEP_PADDING
RSA_SSLV23_PADDING
RSA_NO_PADDING

RSA Encrypt / Decrypt 的基本範例程式解說

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import M2Crypto
import M2Crypto.BN as BN

def generate_keypair_as_pem(key_len, exponent):
    def empty_callback():
        pass

    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    # Get RSA Public Key in PEM format
    buf = M2Crypto.BIO.MemoryBuffer('')
    rsa.save_pub_key_bio(buf)
    public_key = buf.getvalue()

    # Get Private Key in PEM format
    buf = M2Crypto.BIO.MemoryBuffer('')
    rsa.save_key_bio(buf, None)
    private_key = buf.getvalue() # RSA Private Key
    
    return (public_key, private_key)

if __name__ == '__main__':
    keylen = 1024         # 1024 bits
    exponent = 65537  
    padding = M2Crypto.RSA.pkcs1_oeap_padding
    
    # Generate RSA key-pair in PEM files for public key and private key 
    public_key, private_key = generate_keypair_as_pem(keylen, exponent)
    message = 'This is a plain text data'
        
    # Use public key to encrypt 'message'
    buf = M2Crypto.BIO.MemoryBuffer('')
    buf.write(public_key)
    rsa1 = M2Crypto.RSA.load_pub_key_bio(buf)
    cipher_message = rsa1.public_encrypt(message, padding)

    # Use private key to decrypt 'cipher_message'
    rsa2 = M2Crypto.RSA.load_key_string(private_key)
    plaintext_message = rsa2.private_decrypt(cipher_message, padding)

  1. 使用RSA演算法之前,必須產生 RSA 金鑰(Public Key and Private Key Pair)
  2. 第 22 和 23 行指定 key長度為 1024 bits,選用的public exponent 為 65537 
  3. 產生 RSA Key-Pair 在第 8 行,透過 M2Crypto.RSA.gen_key 函數並指定 key 長度和 public exponent。第 3 個參數基本上只要給 empty_callback 即可,若是沒有給時,你呼叫這個函數會在 standard output 中出現類似....++的符號。它只是用來表示初始化  RSA key-pair 的進度狀態。此時我們可以取得 RSA 的 instance,存在 rsa 變數中。
  4. 分別取得 RSA public key 和 private key。M2Crypto 提供的方法,會將 Public key 和Private key 轉成 PEM 格式
  5. 第 10 ~12 行是取得 RSA public key 的方式,第 15 ~17 行是取得RSA private key的方式。差別在於 rsa.save_key_bio(buf, None) 的第 2 個參數設定為 None的原因,是希望直接取得真正的 RSA private key 而不要再經由 aes_128_cbc的方式來保護。否則執行到這段程式碼時,系統會在 console 要求使用者輸入 passphrase 。細節請參M2Crypto官方文件。 但是,一般來說如果是要存在系統中某個地方時候,是會透過另一種加密演算法來保護這把 RSA private key。
  6. 第 31 ~33 行是載入 RSA public key 取得 RSA的 instance 存在變數 rsa1 中,第 34 行呼叫  rsa1.public_encrypt(message, padding)來加密明文(Plain Text),其中指定 padding mode 為 OEAP Padding 。
  7. 第 37 ~38 透過 RSA private key 解開密文(Cipher Text),也必須指定相同的 padding mode 。


RSA Sign and Verify Signature 的基本範例程式解說

以下這個範例,是 sender 以安全的方式傳送一個 message 給 receiver 的 RSA 常見的應用。為了方便解釋,以下我們稱 A 為 sender, B為 receiver 。它大致上有 7 個步驟如下:

  1. A與B各自產生一個 RSA的 key-pair (private and public key)
  2. A與B交換自己的 public key。
  3. A使用B的 public key來加密訊息產生 Cipher message。
  4. A再使用自己的 private key 來為 Cipher message 產生 Signature。
  5. 然後 A 把 Signature 和 Cipher message 傳送給 B。
  6. B 必須用 A的 public key 來驗證所收到的 Signature 是否正確。
  7. B 再用自己的 private key 來解開 Cipher Message,即可得到A傳送的訊息內容。 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import M2Crypto
import M2Crypto.BN as BN

def generate_keypair_as_pem(key_len, exponent):
    def empty_callback():
        pass

    rsa = M2Crypto.RSA.gen_key(key_len, exponent, empty_callback)
    # Get RSA Public Key in PEM format
    buf = M2Crypto.BIO.MemoryBuffer('')
    rsa.save_pub_key_bio(buf)
    public_key = buf.getvalue()

    # Get Private Key in PEM format
    buf = M2Crypto.BIO.MemoryBuffer('')
    rsa.save_key_bio(buf, None)
    private_key = buf.getvalue() # RSA Private Key
    
    return (public_key, private_key)

def get_data_digest(data):
    msg_digest = M2Crypto.EVP.MessageDigest('sha256')
    msg_digest.update (data)
    digest =  msg_digest.digest()
    return digest

def generate_secure_msg(A_private_key, B_public_key, message):
    padding = M2Crypto.RSA.pkcs1_oaep_padding
    buf = M2Crypto.BIO.MemoryBuffer('')
    buf.write(B_public_key)
    rsa1 = M2Crypto.RSA.load_pub_key_bio(buf)
    cipher_message = rsa1.public_encrypt(message, padding)
    # Use A's private key to sign the 'cipher_message'
    digest1 = get_data_digest(cipher_message)
    rsa2 = M2Crypto.RSA.load_key_string(A_private_key)
    signature = rsa2.sign(digest1, 'sha256')
    return cipher_message, signature

def read_secure_msg(A_public_key, B_private_key, cipher_message, signature):
    try:
        # Use A's public key to verify 'signature'
        buf = M2Crypto.BIO.MemoryBuffer('')
        buf.write(A_public_key)
        rsa3 = M2Crypto.RSA.load_pub_key_bio(buf)                
        # Verify
        digest2 = get_data_digest(cipher_message)
        rsa3.verify(digest2, signature, 'sha256')
        # Use B's private key to decrypt 'cipher_message'
        rsa4 = M2Crypto.RSA.load_key_string(B_private_key)        
        padding = M2Crypto.RSA.pkcs1_oaep_padding
        plaintext_message = rsa4.private_decrypt(cipher_message, padding)
        return plaintext_message
    except Exception as err:        
        print 'Verify Fail:%r'% err
        raise 

if __name__ == '__main__':
    keylen = 1024         # 1024 bits
    exponent = 65537
    padding = M2Crypto.RSA.pkcs1_oaep_padding
    
    # Generate RSA key-pair in PEM files for public key and private key 
    A_pub_key, A_priv_key = generate_keypair_as_pem(keylen, exponent)
    
    # Generate RSA key-pair in PEM files for public key and private key 
    B_pub_key, B_priv_key = generate_keypair_as_pem(keylen, exponent)

    # A is sender, B is receiver
    msg = 'A want to send this message to B'

    # Sender's behavior
    cipher_msg, signature = generate_secure_msg(A_priv_key, B_pub_key, msg)

    # Receiver's behavior
    plain_text = read_secure_msg(A_pub_key, B_priv_key, cipher_msg, signature)

附註:
        實務上 RSA 通常都會搭配 AES 做 secure key 的保護,純粹是根據你所要保護的資料大小以及應用所著重的特點而有不同,此外 RSA 並不適合用來加密大量資料。

Reference: