在Tink中,可以以jsons的形式加载和编写明文密钥集。下面是一个不工作的例子:
{
"primaryKeyId": 2800579,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
"value": "ODA9eJX9wcAGwZocL0Jym==",
"keyMaterialType": "SYMMETRIC"
},
"status": "ENABLED",
"keyId": 2800579,
"outputPrefixType": "TINK"
}
]
}我的问题是-是否可以将自己的值插入到各种键/值对中以获得另一个有效的密钥集?我尝试过这一点,但没有取得多大的成功-主要是因为“值”键抱怨INVALID_ARGUMENT: Could not parse key_data.value as key type 'type.googleapis.com/google.crypto.tink.AesGcmKey',你知道什么是有效的“值”吗?
发布于 2021-05-01 06:56:08
首先,发布的代码段中值字段的Base64字符串无效,可能是复制/粘贴错误。
下面的Python代码使用Tink版本1.5.0,并以JSON的形式为AES-256/GCM创建并显示密钥集:
import io
from tink import aead
from tink import tink_config
from tink import JsonKeysetWriter
from tink import new_keyset_handle
from tink import cleartext_keyset_handle
tink_config.register()
key_template = aead.aead_key_templates.AES256_GCM
keyset_handle = new_keyset_handle(key_template)
string_out = io.StringIO()
writer = JsonKeysetWriter(string_out)
cleartext_keyset_handle.write(writer, keyset_handle)
serialized_keyset = string_out.getvalue();
print(serialized_keyset);其结果与您发布的KeySet类似,例如:
{
"primaryKeyId": 1794775293,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
"value": "GiD5ojApaIM2MRpPhGf5sVMhxeA6NE5KjdzUxsJ0ChH/JA==",
"keyMaterialType": "SYMMETRIC"
},
"status": "ENABLED",
"keyId": 1794775293,
"outputPrefixType": "TINK"
}
]
} 我还没有找到描述一般结构或值字段的文档,但是比较不同算法生成的KeySets可以得出结论。如果值是十六进制编码的,则结果是:
1a20f9a23029688336311a4f8467f9b15321c5e03a344e4a8ddcd4c6c2740a11ff24对于AES-256/GCM,它有34个字节,其中最后32个字节是实际键。第二个字节表示密钥的大小,例如,AES-128/GCM为0x1a10,AES-256/GCM为0x1a20,ChaCha20Poly1305为0x1220 (但取决于算法)。
为AES-256/GCM使用自定义密钥,例如
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f 在0x1a20之前,Base64对结果进行编码:
GiAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHw==并将此值应用于上述KeySet中的旧值。
修改后的KeySet可以加载并用于加密,如下所示:
from tink import JsonKeysetReader
from tink import cleartext_keyset_handle
serialized_keyset = '''
{
"primaryKeyId": 1794775293,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
"value": "GiAAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHw==",
"keyMaterialType": "SYMMETRIC"
},
"status": "ENABLED",
"keyId": 1794775293,
"outputPrefixType": "TINK"
}
]
}
'''
reader = JsonKeysetReader(serialized_keyset)
keyset_handle = cleartext_keyset_handle.read(reader)
plaintext = b'The quick brown fox jumps over the lazy dog'
aead_primitive = keyset_handle.primitive(aead.Aead)
tink_ciphertext = aead_primitive.encrypt(plaintext, b'')KeySet与示例密钥0001.1e1f之间的关系可以通过使用示例密钥解密生成的密文来验证,例如使用PyCryptodome。
Tink密文的格式用https://github.com/google/tink/blob/v1.5.0/docs/WIRE-FORMAT.md#crypto-formats描述。第一个字节指定版本,接下来的4个字节指定键ID,然后是实际数据。
对于GCM,实际数据的格式为nonce (12字节)、x++、/.=‘bytes 1’>的格式(16字节)。然后(使用PyCryptodome)可以解密:
from Crypto.Cipher import AES
key = bytes.fromhex('000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f')
prefix = tink_ciphertext[:5]
nonce = tink_ciphertext[5:5 + 12]
ciphertext = tink_ciphertext[5 + 12:-16]
tag = tink_ciphertext[-16:]
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
cipher.update(b'')
decryptedText = cipher.decrypt_and_verify(ciphertext, tag)
print(decryptedText.decode('utf-8')) # The quick brown fox jumps over the lazy dog这证明示例键0001.1e1f被正确地集成到KeySet中。
发布于 2021-09-29 23:29:58
虽然另一个答案包含了一些非常酷的工作,但实际的答案略有不同(我们应该将它添加到Wireformat描述中)。此处存储的值是与已注册相应的KeyTypeManager的类型关联的序列化proto。在本例中,它是proto AesGcmKey。AES-GCM除了键大小之外没有任何参数(当给定一个AES-GCM键时,这个参数是隐式定义的),因此proto包含一个单字节数组。(这解释了第一个字节的多余外观,它是版本的proto序列化和一个bytes字段。XChaCha20Poly1305也没有额外的参数,我假设您看到不同前缀的原因是由于等价但不相等的proto序列化,理论上proto的名称不应该影响序列化,两者都使用相同的标记( version为1,原材料为3)和version 0)。
如果您查看更复杂的密钥类型(如ECIES ),则相应的value将更加复杂(并且包含更多的序列化原型)。整个过程都是原型)。
我们计划在不久的将来彻底改进我们的密钥管理层,这将使不使用Tink的密钥格式的密钥的导出/导入变得更容易,而不必依赖proto定义(这些定义应该是内部实现细节)。
https://stackoverflow.com/questions/67320913
复制相似问题