def unlock(self, passphrase): # might eventually implement the following as specced and in a separate module: # http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html#aes256-cbc # http://www.w3.org/2008/xmlsec/Drafts/derived-key/derived-keys.xml # https://tools.ietf.org/html/rfc4051 # https://tools.ietf.org/html/rfc6030 # http://www.opensource.apple.com/source/libsecurity_asn1/libsecurity_asn1-29908/asn1/pkcs5.asn1 if self._privateKey: return encryption_elem = self._container.getElementsByTagNameNS(XMLENC_NS_URL, 'EncryptionMethod')[0] # jumping over the structure at the moment, see above derivation_func = PBKDF2 params_elem = encryption_elem.getElementsByTagNameNS(PKCS5_NS_URL, 'Parameters')[0] salt_elem = params_elem.getElementsByTagNameNS(PKCS5_NS_URL, 'Salt')[0] IV = salt = b64decode(salt_elem.firstChild.firstChild.nodeValue) iterations_elem = params_elem.getElementsByTagNameNS(PKCS5_NS_URL, 'IterationCount')[0] iterations = int(iterations_elem.firstChild.nodeValue) key_length_elem = params_elem.getElementsByTagNameNS(PKCS5_NS_URL, 'KeyLength')[0] key_length = int(key_length_elem.firstChild.nodeValue) assert key_length % 8 == 0 prf = lambda p, s: HMAC(p, s, SHA256).digest() key = derivation_func(passphrase, salt, count=iterations, dkLen=(key_length//8), prf=prf) encryption_scheme = AES encryption_mode = AES.MODE_CBC decryptor = encryption_scheme.new(key, mode=encryption_mode, IV=IV) # then the encrypted data key_elem = self._container.getElementsByTagNameNS(XMLENC_NS_URL, 'CipherValue')[0] ciphertext_elem = key_elem.firstChild ciphertext = b64decode(ciphertext_elem.nodeValue) padded_plaintext = decryptor.decrypt(ciphertext) padlen = ord(padded_plaintext[-1]) if padlen not in range(encryption_scheme.block_size) or \ chr(padlen)*padlen != padded_plaintext[-padlen:]: raise KeyLockedError("Key decryption failed") plaintext = padded_plaintext[:-padlen] key_elem = removeIgnorableWhitespace(parseString(plaintext)) keyparams = [RSA.bytes_to_long(b64decode(key_elem.getElementsByTagName(x)[0].firstChild.nodeValue)) for x in ['Modulus', 'Exponent', 'D', 'Q', 'P', 'InverseQ']] self._privateKey = RSA.construct(tuple(keyparams)) self._publicKey = self._privateKey.publickey() self.fingerprint = SHA256.new(self._publicKey.exportKey(format='DER')).hexdigest()