From Fedora Project Wiki
See Encrypted volume passphrase change or recovery GUI for details.
import nss.nss import os import pycryptsetup import tempfile import volume_key def _cs_log(unused_pri, txt): print 'cryptsetup: %s' % (txt,) def _cs_askyes(unused_pri, txt): print 'cryptsetup %s (y/n)?' % (txt,) raise NotImplementedError def passphrase_slot(device, passphrase): '''Return slot number used for PASSPHRASE in DEVICE.''' c = pycryptsetup.CryptSetup(_cs_askyes, _cs_log) if c.isLuks(device) != 0: raise ValueError, '%s is not a LUKS device' % (device,) dm_name = os.path.basename(tempfile.mktemp(dir='/dev/mapper')) key_file = c.prepare_passphrase_file(passphrase) try: # The C API allows setting dm_name to NULL in order to only check the # result without creating a dm-crypt device. This would make luksClose # unnecessary. slot = c.luksOpen(device, dm_name, key_file) finally: os.remove(key_file) c.luksClose(dm_name) return slot def get_info(packet): '''Parse an escrpw packet, create an object that returns the metadata.''' pass # FIXME # Keep the character set size a power of two to make sure all characters are # equally likely _PASSPHRASE_CHARSET = ("0123456789" "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "./") # 20 chars * 6 bits per char = 120 "bits of security" _PASSPHRASE_LENGTH = 20 def add_backup_passphrase(dest, device, passphrase, cert_file): '''Add PASSPHRASE to DEVICE, store it in an escrow packet DEST.''' nss.nss.nss_init_nodb() with open(cert_file, 'rb') as f: cert_data = f.read() def known_passphrase_cb(unused_prompt, failed_attempts): if failed_attempts == 0: return passphrase return None vol = volume_key.Volume.open(device) ui = volume_key.UI() ui.passphrase_cb = known_passphrase_cb vol.get_secret(volume_key.SECRET_DEFAULT, ui) rnd = nss.nss.generate_random(_PASSPHRASE_LENGTH) cs = _PASSPHRASE_CHARSET new_passphrase = ''.join([cs[ord(c) % len(cs)] for c in rnd]) # Make the result easier to read parts = [] for i in xrange(0, len(new_passphrase), 5): parts.append(new_passphrase[i : i + 5]) new_passphrase = "-".join(parts) vol.add_secret(volume_key.SECRET_PASSPHRASE, new_passphrase) packet = vol.create_packet_assymetric_from_cert_data \ (volume_key.SECRET_PASSPHRASE, cert_data, ui) with open(dest, 'wb') as f: f.write(packet) def store_passphrase(dest, device, passphrase, cert_file): '''Create an escrow packet for DEVICE with PASSPHRASE, write it to DEST. PASSPHRASE must already have been added to DEVICE. ''' nss.nss.nss_init_nodb() with open(cert_file, 'rb') as f: cert_data = f.read() def known_passphrase_cb(unused_prompt, failed_attempts): if failed_attempts == 0: return passphrase return None vol = volume_key.Volume.open(device) ui = volume_key.UI() ui.passphrase_cb = known_passphrase_cb vol.get_secret(volume_key.SECRET_PASSPHRASE, ui) packet = vol.create_packet_assymetric_from_cert_data \ (volume_key.SECRET_PASSPHRASE, cert_data, ui) with open(dest, 'wb') as f: f.write(packet) if __name__ == '__main__': cert_file = 'cert.pem' device = '/dev/loop0' passphrase = '8sme84zu' if False: store_passphrase('packet', device, passphrase, cert_file) if True: add_backup_passphrase('packet', device, passphrase, cert_file) if False: print 'Slot %d' % (passphrase_slot(device, passphrase),)