I've been playing with TrueNAS scale recently and while the BUI allows you to export/download ZFS wrapping key I wanted to know how to get the key manually. After a quick look at the code I found that the key is stored in sqlite db kept on root file system.
root@truenas[~]# sqlite3 /data/freenas-v1.db SQLite version 3.34.1 2021-01-20 14:10:07 Enter ".help" for usage hints. sqlite> select * from storage_encrypteddataset; 1|backup|ioI/B72PEllUJjumWpWHkdhDDCd2l2eopFEJgWYIpcAcTT1v0NyYicjzKiHfuoncL2Mklfa45pUJIyxzGFGobr17b1HtprjSth/X9yyfsnROCK/xQL+SVmO/5fT/KabfSSiz8+IfDH8=|The key itself is encrypted so you need to decrypt it first before it can be used with ZFS. A simple python script to do it attached below.
root@truenas[~]# ./decode_key.py dataset: backup key: 16f7677b514ef39bc162312274c76da24221ecc5a2f01e6ba0bhfeec054d9162(both the encrypted and decrypted keys above have been modified for this blog entry)
root@truenas[~]# cat decode_key.py #!/usr/bin/python3 # based on /usr/lib/migrate113/freenasUI/system/migrations/0022_cloud_sync.py import sys import base64 from Cryptodome.Cipher import AES import sqlite3 PWENC_BLOCK_SIZE = 32 PWENC_FILE_SECRET = '/data/pwenc_secret' PWENC_PADDING = b'{' def pwenc_get_secret(): with open(PWENC_FILE_SECRET, 'rb') as f: secret = f.read() return secret def pwenc_decrypt(encrypted=None): if not encrypted: return "" from Cryptodome.Util import Counter encrypted = base64.b64decode(encrypted) nonce = encrypted[:8] encrypted = encrypted[8:] cipher = AES.new( pwenc_get_secret(), AES.MODE_CTR, counter=Counter.new(64, prefix=nonce), ) return cipher.decrypt(encrypted).rstrip(PWENC_PADDING).decode('utf8') if len(sys.argv) == 2: print(pwenc_decrypt(sys.argv[1])) exit(0) dbcon = sqlite3.connect('/data/freenas-v1.db') dbcur = dbcon.cursor() for row in dbcur.execute('select * from storage_encrypteddataset'): ds_id, ds_name, ds_enc_key, kmip_enc_key = row #print(ds_id, ds_name, ds_enc_key, pwenc_decrypt(ds_enc_key)) print(f'dataset: {ds_name}\n key: {pwenc_decrypt(ds_enc_key)}\n')