For a given file an unique random AES key of 256 bits is generated and encrypted with the encryption key of the datasource the file belongs to. The datasource encryption keys are generated by the admin and are protected using the default keyring of the system Cells is installed in.
SQL
- `SELECT key_data FROM idm_user_keys;
This is my 80 characters base64-encoded of the 60 bytes master key. Right ?
-
SELECT HEX(key_data), block_header_size, block_data_size FROM enc_node_keys NATURAL JOIN data_meta NATURAL JOIN enc_node_blocks WHERE data = '"test4.rtf"';
-
F2A703227282D4F6D54722FC134973652655A191E04F7D8ABDAEAB54B5F2BE90B00401AF4219BAA4AF7BEB1CBE00B3754388C26E0F9245D290972CAE
# This is the 60 bytes file-specific unique key (120 characters HEX-encoded) which, is encrypted (using the data-source key).
26 # block_header_size
-
1751 # block_data_size
These sole values are expected to allow me to decrypt the file, right?
-
openstack object save pydio test4.rtf
to get the encrypted file (here on OVH Swift+S3). 1777 bytes = 1751 + 26
Key decryption
According to SetupEncryptMode definition and call, encryptionKeyPlainBytes
is passed coming from keyProtectionTool.GetDecrypted.
The first 12 bytes being a nonce.
Encrypted file format
The 1777 encrypted bytes are composed of:
- A 26 bytes clear-text header
- The rest of encrypted data
- containing the a 16 bytes AES-GCM tag placed at the end of the data
- From this code I assume that the 12 bytes nonce is actually represented by the 12 first bytes of the header.
Code
Contrary to libressl
, openssl enc
does not support AES-GCM but using Python Cryptodome
should be.
from Cryptodome.Cipher import AES
import binascii, base64, sys
master_key = base64.b64decode(sys.argv[1])
encrypted_file_key = binascii.unhexlify(sys.argv[2])
file_key_nonce, encrypted_file_key = encrypted_file_key[:12], encrypted_file_key[12:]
cipher = AES.new(master_key[0:32], AES.MODE_GCM, nonce = file_key_nonce)
decrypted_file_key = cipher.decrypt(encrypted_file_key) # = 48 bytes
HeaderSize = 26 # hardcoded
with open(sys.argv[3], "rb") as f:
data = f.read()
header = data[:26]
nonce, tag = header[:12], data[-16:]
data = data[26:-16]
cipher = AES.new(decrypted_file_key[:32], AES.MODE_GCM, nonce)
cipher.decrypt_and_verify(data, tag)
Run
$ aes-256-gcm-decrypt "$K" "$FK" test4.rtf
- With “$K” from
SELECT key_data from idm_user_key
- And “$FK” the above file key from
SELECT hex(key_data) FROM enc_node_keys
-
test4.rtf
the encrypted local file
=> ValueError: MAC check failed (Cryptodome/Cipher/_mode_gcm.py :: decrypt_and_verify)
The decryption failed.
Why?
As you can see above I trim both the master key and the decrypted file key to their first 32 bytes but I feel bad about this. Is this the reason for the error? what the adequate use of these keys would be?
Thank you
(@charles?)