Python 如何将有效值传递到cleartext_keyset_json中以创建Tink键

Python 如何将有效值传递到cleartext_keyset_json中以创建Tink键,python,cryptography,tink,Python,Cryptography,Tink,在Tink中,可以将明文键集作为JSON加载和写入。下面是一个非工作示例: { "primaryKeyId": 2800579, "key": [ { "keyData": { "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey", "value":

在Tink中,可以将明文键集作为JSON加载和写入。下面是一个非工作示例:

{
  "primaryKeyId": 2800579,
  "key": [
    {
      "keyData": {
        "typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
        "value": "ODA9eJX9wcAGwZocL0Jym==",
        "keyMaterialType": "SYMMETRIC"
      },
      "status": "ENABLED",
      "keyId": 2800579,
      "outputPrefixType": "TINK"
    }
  ]
}

我的问题是-是否可以将您自己的值插入到各种键/值对中以获得另一个有效键集?我对此进行了试验,但没有取得多大成功-主要是因为“value”键抱怨
无效参数:无法将key\u data.value解析为key type'type.googleapis.com/google.crypto.tink.AesGcmKey'
知道什么是有效的“value”吗?

首先,发布的代码段中值字段的Base64字符串无效,可能是复制/粘贴错误

以下Python代码使用并创建AES-256/GCM的键集,并将其显示为JSON:

导入io
来自tink import aead
从tink导入tink_配置
来自tink import JsonKeysetWriter
从tink导入新的按键集手柄
从tink导入明文\u键集\u句柄
tink_config.register()
密钥模板=aead.aead密钥模板.AES256\U GCM
键集\句柄=新的\键集\句柄(键\模板)
string\u out=io.StringIO()
writer=JsonKeysetWriter(字符串输出)
cleartext\u keyset\u handle.write(writer,keyset\u handle)
序列化的_keyset=string_out.getvalue();
打印(序列化的_键集);
结果与您发布的密钥集类似,例如:

{
“primaryKeyId”:1794775293,
“关键”:[
{
“关键数据”:{
“typeUrl”:“type.googleapis.com/google.crypto.tink.AesGcmKey”,
“值”:“GiD5ojApaIM2MRpPhGf5sVMhxeA6NE5KjdzUxsJ0ChH/JA=”,
“keyMaterialType”:“对称”
},
“状态”:“已启用”,
“keyId”:1794775293,
“outputPrefixType”:“TINK”
}
]
}   
我还没有找到一个文档来描述一般的结构或值字段,但是比较不同算法生成的键集可以得出结论。如果值为十六进制编码,则结果为:

1A20F9A230292968336311A4F8467F9B15321C5E03A344E4A8DDCD4CC2740A11FF24
对于AES-256/GCM,它有34个字节,其中最后32个字节是实际密钥。开头是算法的特征,第二个字节表示密钥的大小,例如,AES-128/GCM为0x1a10,AES-256/GCM为0x1a20,ChaCha20Poly1305为0x1220(但可能更复杂,具体取决于算法)

为AES-256/GCM使用自定义密钥,例如

000102030405060708090A0B0C0D0E0F1011112131415161718191A1B1C1D1E1F
前置0x1a20,Base64编码结果:

GIAAQIDBAUGBWGJCGDQ4PEBESEXQVFHCYGROBHB0EHW==
并应用此值,而不是上述键集中的旧值

修改后的密钥集可以加载并用于加密,如下所示:

来自tink import JsonKeysetReader的

从tink导入明文\u键集\u句柄
序列化的_键集=“”
{
“primaryKeyId”:1794775293,
“关键”:[
{
“关键数据”:{
“typeUrl”:“type.googleapis.com/google.crypto.tink.AesGcmKey”,
“值”:“GIAAQIDBAUGBWGJCGDQ4PEBESEXQVFHCYGROBHB0EHW==”,
“keyMaterialType”:“对称”
},
“状态”:“已启用”,
“keyId”:1794775293,
“outputPrefixType”:“TINK”
}
]
}   
'''
reader=JsonKeysetReader(序列化的_键集)
keyset\u handle=cleartext\u keyset\u handle.read(读卡器)
纯文本=b‘敏捷的棕色狐狸跳过懒惰的狗’
aead_primitive=keyset_handle.primitive(aead.aead)
tink_ciphertext=aead_primitive.encrypt(明文,b'')
密钥集和示例密钥0001…1e1f之间的关系可以通过使用示例密钥(例如使用PyCryptodome)对生成的密文进行解密来验证

Tink密文的格式如中所述。第一个字节指定版本,接下来的4个字节指定密钥ID,后跟实际数据。
对于GCM,实际数据的格式为nonce(12字节)| | |密文| |标记(16字节)。然后可以使用(使用PyCryptodome)进行解密:

从加密密码导入AES
key=bytes.fromhex('000102030405060708090A0B0C0D0E0F1011112131415161718191A1B1C1D1E1F')
前缀=tink_密文[:5]
nonce=tink_密文[5:5+12]
密文=tink_密文[5+12:-16]
tag=tink_密文[-16:]
密码=AES.new(密钥,AES.MODE\u GCM,nonce=nonce)
密码更新(b“”)
decryptedText=密码。解密并验证(密文,标记)
print(decryptedText.decode('utf-8'))#敏捷的棕色狐狸跳过了懒狗

这证明示例键0001…1e1f已正确集成到键集中。

非常出色的侦探工作!所以,如果我为AES-256/GCM获取任何32字节的密钥并在0x1a20前加上前缀,它应该可以工作?@user3776598-是的,没错。键0001…1e1f代表任意键。添加前缀后,结果仍然必须是Base64编码的。它工作得很好。非常感谢你!如果我可以问一下-您如何能够看到前2个字节是固定的,并且是base64编码字符串示例中的字符串长度?@user3776598-正如我在回答中所说的,不幸的是,我没有找到任何规范。我通过比较不同的算法推导出了前缀的含义:对于AES-128/GCM和AES-256/GCM,第一个字节是0x1a,对于ChaCha20Poly1305,它是0x12。对于AES-128/GCM,第二个字节是0x10,对于AES-256/GCM和CHACHA201305,第二个字节是0x20。因此得出结论,第一个字节取决于算法,第二个字节表示密钥大小。但是前缀可能更复杂,具体取决于算法,即所描述的过程对AES/GCM有效,并且必须适用于其他算法。@user3776598-我不知怎么错过了Python标记。所以我用Python代码片段替换了Java代码片段。除此之外,内容没有任何变化。