def get_basekeys(filePass, salt): ''' Generate user and file keys from the respective passwords and a hopefully random salt. user password if not provided, fallsback to a default. If provided, it should be readable only by the user and not by group or all. ''' # process file password kdf = pbkdf2.PBKDF2HMAC( algorithm=SHA256(), length=32, salt=salt, iterations=186926, # Gandhi+ backend=default_backend()) fileKey = base64.urlsafe_b64encode(kdf.derive(bytes(filePass, "utf-8"))) # get and process user password try: f = open("~/.config/spreadsheetkvc/userpass") l = f.readline() userPass = l.strip() f.close() except: userPass = "******" kdf = pbkdf2.PBKDF2HMAC( algorithm=SHA256(), length=32, salt=salt, iterations=186922, # Gandhi+ backend=default_backend()) userKey = base64.urlsafe_b64encode(kdf.derive(bytes(userPass, "utf-8"))) return userKey, fileKey
def wcdb_decrypt_first_page(raw, page_size, device_salt, password): salt_mask = 0x3a salt_size = 16 cipher_key_size = 32 cipher_key_iter = 4000 cipher_iv_size = algorithms.AES.block_size // 8 hmac_key_size = cipher_key_size hmac_key_iter = 2 hmac_sig_size = hashes.SHA1.digest_size reserved_size = (cipher_iv_size + hmac_sig_size + algorithms.AES.block_size // 8 - 1) // (algorithms.AES.block_size // 8) * (algorithms.AES.block_size // 8) page = raw[0:page_size] page_salt = page[:salt_size] page_content_enc = page[salt_size:-reserved_size] page_reserved = page[-reserved_size:] cipher_iv = page_reserved[0:cipher_iv_size] hmac_sig = page_reserved[cipher_iv_size:cipher_iv_size + hmac_sig_size] cipher_key = pbkdf2.PBKDF2HMAC(hashes.SHA1(), cipher_key_size, device_salt, 1, default_backend()).derive( pbkdf2.PBKDF2HMAC( hashes.SHA1(), cipher_key_size, page_salt, cipher_key_iter, default_backend()).derive(password)) hmac_key = pbkdf2.PBKDF2HMAC( hashes.SHA1(), hmac_key_size, device_salt, 1, default_backend()).derive( pbkdf2.PBKDF2HMAC(hashes.SHA1(), hmac_key_size, bytes([x ^ salt_mask for x in page_salt]), hmac_key_iter, default_backend()).derive(cipher_key)) h = hmac.HMAC(hmac_key, hashes.SHA1(), default_backend()) h.update(page_content_enc) h.update(cipher_iv) h.update(int(1).to_bytes(4, 'little')) h.verify(hmac_sig) decryptor = Cipher(algorithms.AES(cipher_key), modes.CBC(cipher_iv), default_backend()).decryptor() page_content_dec = decryptor.update( page_content_enc) + decryptor.finalize() assert (page_content_dec[21 - 16] == 64) assert (page_content_dec[22 - 16] == 32) assert (page_content_dec[23 - 16] == 32) assert (all(v == 0 for v in page_content_dec[72 - 16:72 - 16 + 20])) return b'SQLite format 3\x00' + page_content_dec
def wcdb_decrypt_left_pages(raw, page_size, device_salt, password): salt_mask = 0x3a salt_size = 16 cipher_key_size = 32 cipher_key_iter = 4000 cipher_iv_size = algorithms.AES.block_size // 8 hmac_key_size = cipher_key_size hmac_key_iter = 2 hmac_sig_size = hashes.SHA1.digest_size reserved_size = (cipher_iv_size + hmac_sig_size + algorithms.AES.block_size // 8 - 1) // (algorithms.AES.block_size // 8) * (algorithms.AES.block_size // 8) salt = raw[0:salt_size] cipher_key = pbkdf2.PBKDF2HMAC(hashes.SHA1(), cipher_key_size, device_salt, 1, default_backend()).derive( pbkdf2.PBKDF2HMAC( hashes.SHA1(), cipher_key_size, salt, cipher_key_iter, default_backend()).derive(password)) hmac_key = pbkdf2.PBKDF2HMAC(hashes.SHA1(), hmac_key_size, device_salt, 1, default_backend()).derive( pbkdf2.PBKDF2HMAC( hashes.SHA1(), hmac_key_size, bytes([x ^ salt_mask for x in salt]), hmac_key_iter, default_backend()).derive(cipher_key)) raw_dec = bytearray() for i in range(1, len(raw) // page_size): page = raw[i * page_size:i * page_size + page_size] page_content_enc = page[:-reserved_size] page_reserved = page[-reserved_size:] cipher_iv = page_reserved[0:cipher_iv_size] hmac_sig = page_reserved[cipher_iv_size:cipher_iv_size + hmac_sig_size] h = hmac.HMAC(hmac_key, hashes.SHA1(), default_backend()) h.update(page_content_enc) h.update(cipher_iv) h.update((i + 1).to_bytes(4, 'little')) h.verify(hmac_sig) decryptor = Cipher(algorithms.AES(cipher_key), modes.CBC(cipher_iv), default_backend()).decryptor() raw_dec.extend( decryptor.update(page_content_enc) + decryptor.finalize()) return bytes(raw_dec)
def _CalculateHash(self, password, salt, iteration_count): kdf = pbkdf2.PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=salt, iterations=iteration_count, backend=openssl.backend) return kdf.derive(password)
def __init__(self, enckey): params = fetch( enckey, "./xenc11:DerivedKey/xenc11:KeyDerivationMethod/pkcs5:PBKDF2-params" ) if params is None: raise ValueError("XML file is missing PBKDF2 parameters!") salt = fetch(params, "./Salt/Specified/text()", base64.b64decode) itrs = fetch(params, "./IterationCount/text()", int) klen = fetch(params, "./KeyLength/text()", int) hmod = fetch(params, "./PRF/@Algorithm", convertHMACType, hashes.SHA1) if salt is None: raise ValueError("XML file is missing PBKDF2 salt!") if itrs is None: raise ValueError("XML file is missing PBKDF2 iteration count!") if klen is None: raise ValueError("XML file is missing PBKDF2 key length!") self.kdf = pbkdf2.PBKDF2HMAC(algorithm=hmod(), length=klen, salt=salt, iterations=itrs, backend=default_backend())
def _derive_key(password: bytes) -> bytes: kdf = pbkdf2.PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=b'', iterations=pow(10, 7), backend=backends.default_backend()) return base64.urlsafe_b64encode(kdf.derive(password))
def encrypt(key, iv, salt, plaintext, iterations=1000): """ Returns: (bytes) ciphertext """ if len(salt) != 16: raise Exception("Expected 128 bits of salt - got %i bits" % len( (salt) * 8)) if len(iv) != 16: raise Exception("Expected 128 bits of IV - got %i bits" % (len(iv) * 8)) sha = hashes.SHA512() kdf = pbkdf2.PBKDF2HMAC(sha, 64, salt, iterations, backend) k = kdf.derive(key) aes_key = k[0:32] sha_key = k[32:] packed_file = ( b"\x01" # version + salt + iv + struct.pack(">L", iterations) + encrypt_ctr(aes_key, iv, plaintext)) packed_file += hmac_sha256(sha_key, packed_file) return (b"-----BEGIN MEGOLM SESSION DATA-----\n" + base64.encodestring(packed_file) + b"-----END MEGOLM SESSION DATA-----")
def DecryptString(self, ciphertext: str) -> str: ciphertext_bytes = base64.b64decode(ciphertext) salt, header, body = ciphertext_bytes[:48], ciphertext_bytes[ 48:48 + 16], ciphertext_bytes[48 + 16:] if len(salt) == 48 and len(header) == 16: xts_key = pbkdf2.PBKDF2HMAC(hashes.SHA1(), 128 // 8 * 2, salt[0:40], 1000, default_backend()).derive( self._password) else: raise ValueError('Broken ciphertext: length is too short.') xts_cipher = Cipher( algorithms.AES(xts_key), modes.XTS( b'\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00' ), default_backend()) xts_decryptor = xts_cipher.decryptor() header = xts_decryptor.update(header) + xts_decryptor.finalize() header_tag, header_textlength, header_blocksize = \ header[0:4], int.from_bytes(header[4:12], 'little'), int.from_bytes(header[12:16], 'little') padded_textlength = header_textlength if header_textlength % 16 == 0 else header_textlength + 16 - header_textlength % 16 if not (header_tag == b'XTS1'): raise ValueError('Broken ciphertext: header_tag is corrupted.') if not (padded_textlength == len(body)): raise ValueError( 'Broken ciphertext: header_textlength is corrupted.') if not (0 < header_blocksize <= 0x100000 and header_blocksize % 16 == 0): raise ValueError( 'Broken ciphertext: header_blocksize is corrupted.') plaintext_bytes = bytearray() for i in itertools.count(): offset_begin = i * header_blocksize offset_end = offset_begin + header_blocksize if offset_begin < len(body): xts_cipher = Cipher(algorithms.AES(xts_key), modes.XTS(i.to_bytes(16, 'little')), default_backend()) xts_decryptor = xts_cipher.decryptor() block = xts_decryptor.update( body[offset_begin:offset_end]) + xts_decryptor.finalize() if len( block ) < header_blocksize and header_textlength != padded_textlength: block = block[0:header_textlength - padded_textlength] plaintext_bytes.extend(block) else: break return plaintext_bytes.decode('utf-8')
def configure(self): backend = self.configured_data['BACKEND'] digest = self.configured_data['DIGEST'] salt = self.configured_data['SALT'] # Key Derivation Function kdf = pbkdf2.PBKDF2HMAC( algorithm=digest, length=digest.digest_size, salt=salt, iterations=30000, backend=backend, ) self.configured_data['KEY'] = kdf.derive( force_bytes(self.configured_data['KEY'] or settings.SECRET_KEY)) return self.configured_data
def EncryptString(self, plaintext: str) -> str: plaintext_bytes = plaintext.encode('utf-8') salt = os.urandom(48) header_tag = b'XTS1' header_textlength = len(plaintext_bytes) header_blocksize = 0x10000 xts_key = pbkdf2.PBKDF2HMAC(hashes.SHA1(), 128 // 8 * 2, salt[0:40], 1000, default_backend()).derive(self._password) body = bytearray() for i in itertools.count(): offset_begin = i * header_blocksize offset_end = offset_begin + header_blocksize if offset_begin < len(plaintext_bytes): xts_cipher = Cipher(algorithms.AES(xts_key), modes.XTS(i.to_bytes(16, 'little')), default_backend()) xts_encryptor = xts_cipher.encryptor() block = plaintext_bytes[offset_begin:offset_end] if len(block) % 16 != 0: block += b'\x00' * (16 - len(block) % 16) body.extend( xts_encryptor.update(block) + xts_encryptor.finalize()) else: break xts_cipher = Cipher( algorithms.AES(xts_key), modes.XTS( b'\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00' ), default_backend()) xts_encryptor = xts_cipher.encryptor() header = xts_encryptor.update( header_tag + header_textlength.to_bytes(8, 'little') + header_blocksize.to_bytes(4, 'little')) + xts_encryptor.finalize() ciphertext_bytes = salt + header + body return base64.b64encode(ciphertext_bytes).decode('utf-8')
def _create_encryption_key( password: Union[bytes, str], hash_salt: bytes, hash_iterations: int ) -> bytes: password = password.encode() if isinstance(password, str) else password kdf = pbkdf2.PBKDF2HMAC(hashes.SHA256(), 32, hash_salt, hash_iterations) return base64.urlsafe_b64encode(kdf.derive(password))
def pbkdf2_sha256(password, salt, iters): """PBKDF2 with HMAC-SHA256""" ctx = pbkdf2.PBKDF2HMAC(hashes.SHA256(), 32, salt, iters, default_backend()) return ctx.derive(password)
def wcdb_generate_device_salt(serialno: bytes, cpu_serial: bytes): serial = serialno + cpu_serial return pbkdf2.PBKDF2HMAC(hashes.SHA1(), 16, serial, 1, default_backend()).derive(serial)
def _transform_password(password: str, hash_salt: bytes, hash_iterates: int) -> bytes: kdf = pbkdf2.PBKDF2HMAC(hashes.SHA256(), 32, hash_salt, hash_iterates) return b64.urlsafe_b64encode(kdf.derive(password.encode()))