Skip to content

Instantly share code, notes, and snippets.

@schorschii
Created August 27, 2025 20:47
Show Gist options
  • Save schorschii/20bd9f3c19349e188483736d57808434 to your computer and use it in GitHub Desktop.
Save schorschii/20bd9f3c19349e188483736d57808434 to your computer and use it in GitHub Desktop.
#!/bin/python3
# This script creates KEYDB.cfg file content (~/.config/aacs/KEYDB.cfg)
# for your personal backup by parsing the cached keys which are
# automatically stored by libaacs in ~/.cache/aacs when a Bluray disc
# could be successfully decrypted with a valid host certificate.
# The decrypted individual disc keys can be used to play the disc at any time later,
# even if your host certificate gets revoked in your drive
# (by inserting a disc with new MKB [MediaKeyBlock] version).
# usage: python3 libaacs-config-creator.py > KEYDB.cfg
import os, sys
import time
import datetime
from pathlib import Path
def main():
key_infos = []
home = str(Path.home())
aacs_cache_dir = home+'/.cache/aacs'
for disc_id in os.listdir(aacs_cache_dir+'/mk'):
mk_path = aacs_cache_dir+'/mk/'+disc_id
vid_path = aacs_cache_dir+'/vid/'+disc_id
vuk_path = aacs_cache_dir+'/vuk/'+disc_id
tit_path = aacs_cache_dir+'/tit/'+disc_id # title name source (not part of libaacs, needs to be created manually)
if(not os.path.exists(vid_path) or not os.path.exists(vuk_path)):
continue
mk_content = open(mk_path, 'r').read().strip()
vid_content = open(vid_path, 'r').read().strip()
vuk_content = open(vuk_path, 'r').read().strip()
if(len(mk_content) != 32 or len(vid_content) != 32 or len(vuk_content) != 32):
eprint(disc_id, 'mk, vid or vuk content is not 32 bytes long!')
continue
tit_content = 'TITLE?'
if(os.path.exists(tit_path)):
tit_content = open(tit_path, 'r').read().strip()
date = datetime.datetime.fromtimestamp(os.path.getmtime(mk_path))
key_infos.append({ 'disc_id':disc_id, 'title':tit_content, 'date':date, 'vuk':vuk_content, 'vid':vid_content, 'mk':mk_content })
key_infos_sorted = sorted(key_infos, key=lambda x:x['date'], reverse=True)
for info in key_infos_sorted:
cfg_line = f'0x{info['disc_id']} = {info['title']} | D | {info['date'].strftime('%Y-%m-%d')} | V | 0x{info['vuk']} | M | 0x{info['mk']} | I | 0x{info['vid']}'
print(cfg_line)
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
if(__name__ == '__main__'):
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment