def pass_decrypt_new(self, encrypted_pwd): """ Decrypts a password from ClawsMail. => new version """ # Everything is explained on the doc / code # https://github.com/eworm-de/claws-mail/blob/master/doc/src/password_encryption.txt # https://github.com/eworm-de/claws-mail/blob/aca15d9a473bdfdeef4a572b112ff3679d745247/src/password.c#L409 m = re.match('{(.*),(.*)}(.*)', encrypted_pwd) if m: # rounds and pbkdf2_rounds should be identical mode, rounds, enc_pwd = m.groups() masterkey = pbkdf2(self.passcrypt_key, self.salt, int(rounds), self.KEYLEN) raw = b64decode(enc_pwd) aes = AESModeOfOperationCBC(masterkey, iv='\0' * 16) cleartxt = b"".join([ aes.decrypt(raw[i:i + self.AES_BLOCK_SIZE]) for i in range(0, len(raw), self.AES_BLOCK_SIZE) ]) plaintext = cleartxt[self.AES_BLOCK_SIZE:] try: return plaintext.decode() except Exception: # Password seems not correct return plaintext
def chrome_decrypt(self, encrypted_value, key, init_vector): encrypted_value = encrypted_value[3:] aes = AESModeOfOperationCBC(key, iv=init_vector) cleartxt = b"".join([ aes.decrypt(encrypted_value[i:i + self.AES_BLOCK_SIZE]) for i in range(0, len(encrypted_value), self.AES_BLOCK_SIZE) ]) return self.remove_padding(cleartxt)
def decrypt_3des(decoded_item, master_password, global_salt): """ User master key is also encrypted (if provided, the master_password could be used to encrypt it) """ # See http://www.drh-consultancy.demon.co.uk/key3.html pbeAlgo = str(decoded_item[0][0][0]) if pbeAlgo == '1.2.840.113549.1.12.5.1.3': # pbeWithSha1AndTripleDES-CBC entry_salt = decoded_item[0][0][1][0].asOctets() cipher_t = decoded_item[0][1].asOctets() # See http://www.drh-consultancy.demon.co.uk/key3.html hp = sha1(global_salt + master_password).digest() pes = entry_salt + convert_to_byte('\x00') * (20 - len(entry_salt)) chp = sha1(hp + entry_salt).digest() k1 = hmac.new(chp, pes + entry_salt, sha1).digest() tk = hmac.new(chp, pes, sha1).digest() k2 = hmac.new(chp, tk + entry_salt, sha1).digest() k = k1 + k2 iv = k[-8:] key = k[:24] return triple_des(key, CBC, iv).decrypt(cipher_t) # New version elif pbeAlgo == '1.2.840.113549.1.5.13': # pkcs5 pbes2 assert str(decoded_item[0][0][1][0][0]) == '1.2.840.113549.1.5.12' assert str( decoded_item[0][0][1][0][1][3][0]) == '1.2.840.113549.2.9' assert str( decoded_item[0][0][1][1][0]) == '2.16.840.1.101.3.4.1.42' # https://tools.ietf.org/html/rfc8018#page-23 entry_salt = decoded_item[0][0][1][0][1][0].asOctets() iteration_count = int(decoded_item[0][0][1][0][1][1]) key_length = int(decoded_item[0][0][1][0][1][2]) assert key_length == 32 k = sha1(global_salt + master_password).digest() key = pbkdf2_hmac('sha256', k, entry_salt, iteration_count, dklen=key_length) # https://hg.mozilla.org/projects/nss/rev/fc636973ad06392d11597620b602779b4af312f6#l6.49 iv = b'\x04\x0e' + decoded_item[0][0][1][1][1].asOctets() # 04 is OCTETSTRING, 0x0e is length == 14 encrypted_value = decoded_item[0][1].asOctets() aes = AESModeOfOperationCBC(key, iv=iv) cleartxt = b"".join([ aes.decrypt(encrypted_value[i:i + AES_BLOCK_SIZE]) for i in range(0, len(encrypted_value), AES_BLOCK_SIZE) ]) return cleartxt