In Tink, it is possible to load and write cleartext keysets as jsons. An non-working example is seen below:
{
"primaryKeyId": 2800579,
"key": [
{
"keyData": {
"typeUrl": "type.googleapis.com/google.crypto.tink.AesGcmKey",
"value": "ODA9eJX9wcAGwZocL0Jym==",
"keyMaterialType": "SYMMETRIC"
},
"status": "ENABLED",
"keyId": 2800579,
"outputPrefixType": "TINK"
}
]
}
My question is- is it possible to insert your own values into the various key/value pairs to get another valid keyset? I have experimented with this and haven't had much success- mainly because of the "value" key which complains INVALID_ARGUMENT: Could not parse key_data.value as key type 'type.googleapis.com/google.crypto.tink.AesGcmKey' Any idea of what a valid "value" would be?
First of all, the Base64 string of the value field in the posted code snippet is invalid, possibly a copy/paste error.
The following Python code uses Tink version 1.5.0 and creates and displays a keyset for AES-256/GCM as JSON:
The result is similar to the KeySet you posted and is e.g.:
I haven't found a documentation that describes the structure in general or for the value field, but comparing the generated KeySets for different algorithms allows conclusions. If value is hex encoded, the result is:
For AES-256/GCM it has 34 bytes, where the last 32 bytes are the actual key. The beginning is characteristic for the algorithm, the second byte indicates the size of the key, e.g. 0x1a10 for AES-128/GCM, 0x1a20 for AES-256/GCM or 0x1220 for ChaCha20Poly1305 (but can be more complex depending on the algorithm).
To use a self-defined key for AES-256/GCM, e.g.
prepend 0x1a20, Base64 encode the result:
and apply this value instead of the old value in the above KeySet.
The modified KeySet can be loaded and used for encryption as follows:
The relationship between KeySet and the example key 0001...1e1f can be verified by decrypting the generated ciphertext using the example key without Tink, e.g. with PyCryptodome.
The format of the Tink ciphertext is described in Tink Wire Format, Crypto Formats. The first byte specifies the version, the next 4 bytes the key ID, followed by the actual data.
For GCM the actual data has the format nonce (12 bytes) || ciphertext || tag (16 bytes). Decryption is then possible with (using PyCryptodome):
which proves that the example key 0001...1e1f was correctly integrated into the KeySet.