信封加密简要

信封加密(Envelope Encryption)是一种应对海量数据的高性能加解密方案,国内的各种公有云都有密钥管理系统,简称 KMS(Key Management Service),该系统中就包含信封加密方案。

一图胜万言(图来自腾讯云文档):

enveope encrypt decrypt

名词解释:

  • DEK = data encryption keys
  • KMS = Key Management Service
  • AES = Advanced Encryption Standard

加密核心流程:

    1. 用户向 KMS 请求的时候,系统会给你返回一对密钥(明文 key+密文 key), 二者作用不同,明文 key 用来给本地文件加密,密文 key 用来从 KMS 系统获取明文 key。至于 KMS 系统如何维护二者的对应关系的,这个读者大可不必担心。反正 2 个 key 关系非同一般,各司其职,要是真不能理解,可以想想婚姻登记所,传统婚姻一个主内做家务,一个主外搞钱。
    1. 用明文 key 加密数据,比如你要加密一个 test.txt 文件什么的。心急的可能要问,有了明文 key,到底怎么加密呢?不要慌,我给你看简单 Python 示例:
    1from Crypto.Cipher import AES
    2key = b'Sixteen byte key'         # 这里就是明文key(here is the plainkey)
    3cipher = AES.new(key, AES.MODE_EAX)
    4nonce = cipher.nonce
    5ciphertext, tag = cipher.encrypt_and_digest(data) # 加密 data,返回 ciphertext(先忽略nonce和tag等)
    
    1. 假设上面的 text.txt 加密后命名为 secret.bin,本地加密完成后总要放到一个地方存起来,大陆新闻里面的贪官,钱财存墙体、保险柜、小区空房什么的,如今数字时代,文件一般存到云存储中,存起来的时候你不光要存加密文件本身,你还得存密文 key,不然没法解密,那玩笑就开大了,白忙活。一般加密后明文 key 就删除了,不留痕迹。加密后的文件和密文 key 一起存起来,好比用信封给包起来?(所以叫信封加密?这是我猜的...)

解密核心流程:

    1. 若干年后,你要用数据了。先把信封从存储系统中拿出来,信里面有加密数据 + 密文 key,你用密文 key 向 KMS 系统请求获得明文 key,然后你想起上面雪封很久的加密程序,心理想太好了。当初是我亲手加密的,现在亲手解密,一切就像回到从前,存封许久的密密文件由你来解码,感觉自己像军统特务,神秘且居功至伟,这是熟悉的感觉!
    1. 回到现实,用 KMS 返回的明文 key 解密数据,也搞个简单示例:
    1  from Crypto.Cipher import AES
    2  key = b'Sixteen byte key'          # 还是那个熟悉的明文key(the same plainkey)
    3  cipher = AES.new(key, AES.MODE_EAX, nonce=nonce)
    4  plaintext = cipher.decrypt(ciphertext)   # 解密得到plantext
    5  try:
    6      cipher.verify(tag)
    7      print("The message is authentic:", plaintext)
    8  except ValueError:
    9      print("Key incorrect or message corrupted")
    
    1. 拿到数据明文后,阅后即焚毁,白天兴奋不安、夜晚难以入眠,几十年来,这个星球上只有你一个人知道这个机密,太不可思议了 😅。

好了,虚拟故事讲完了,现实中,你不是戴笠,也没有委员长给你撑腰。

苦哈哈写代码才是日常.....

所谓帮人帮到底,下面我给一个比较完整的伪代码示例:

 1
 2import requests
 3import base64
 4from Crypto.Cipher import AES    #pip install pycryptodome
 5
 6
 7url = "your_kms_url"
 8
 9
10def gen_signature(method, params, secret_key):
11
12    '''
13    signature
14    '''
15    pass
16
17
18def generate_data_key():
19    '''
20    get planinkey and cipherkey
21    '''
22    params = {
23        'xxx1': 'yyy1',
24        'xxx2': 'yyy2',
25    }
26    params['signature'] = gen_signature()
27    r = requests.get(url, params=params)
28    rdata = r.json()["data"]
29    plainkey, cipherkey = rdata["plaintext"], rdata["ciphertext"]
30    return plainkey,cipherkey
31
32
33def get_plainkey(cipherkey):
34    '''
35    use cipherkey get plainkey"
36    '''
37    params = {
38        'zzz1': 'mmm1'
39        'foo': 'bar'
40    }
41    params["ciphertext"] = cipherkey
42    params['signature'] = gen_signature()
43
44    r = requests.get(url, params=params)
45    rdata = r.json()["data"]
46    plainkey = rdata["plaintext"]
47    return plainkeypt
48
49
50def envelope_encrypt(plainkey):
51    '''encrypt'''
52    key = base64.b64decode(plainkey)
53    with open(to_be_encrypt_file, "rb") as f:
54        data = f.read()
55    cipher = AES.new(key, AES.MODE_SIV)  # chose your aes mode
56    ciphertext, tag = cipher.encrypt_and_digest(data)
57
58    with open(encrypted_file,"wb") as file_out:
59        [ file_out.write(x) for x in (tag, ciphertext) ]
60
61def envelope_decrypt():
62    '''decrypt'''
63    with open(cipherkey_file,'r') as f:
64        cipherkey = f.read()
65    key = getDatakeyPlaintext(cipherkey)
66    key = base64.b64decode(key)
67    if key:
68        with open(encrypted_file,"rb") as file_in:
69            tag, ciphertext = [ file_in.read(x) for x in (16, -1) ]
70        cipher = AES.new(key, AES.MODE_SIV)
71        data = cipher.decrypt_and_verify(ciphertext,tag)
72        with open(decrypt_file,"wb") as file_origin:
73            file_origin.write(data)
74
75def upload_to_cloud(upload_file):
76    '''
77    upload cipherkey and secret file to cloud like aws s3
78    '''
79    pass
80
81
82if __name__ == "__main__":
83
84    to_be_encrypt_file = 'text.txt'          # 待加密文件
85    encrypted_file = "secret.bin"            # 加密后的文件
86    decrypt_file = "origin"                  # 解密后的文件
87    cipherkey_file = "cipherkey"
88
89    plainkey, cipherkey = generate_data_key()
90
91    # encryt
92    envelope_encrypt(plainkey)
93
94    #upload
95    upload_to_cloud(upload_file)
96
97    # decrpyt at someday
98    #envelope_decrypt()

上面的伪代码只是反应了核心流程,还需要读者根据自己的业务状况修改。

最后修改于: Friday, December 22, 2023
欢迎关注微信公众号,留言交流。

相关文章:

翻译: