def encryptImg(self,img, refkey, mimetype): print(mimetype) if(mimetype == "audio/wav"): derivative = HKDFv3().deriveSecrets(binascii.unhexlify(refkey), "WhatsApp Audio Keys", 112) else: derivative = HKDFv3().deriveSecrets(binascii.unhexlify(refkey), "WhatsApp Image Keys".encode(), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipherKey = parts[1] macKey=derivative[48:80] mac = hmac.new(macKey,digestmod=hashlib.sha256) mac.update(iv) cipher = AES.new(key=cipherKey, mode=AES.MODE_CBC, IV=iv) imgEnc = cipher.encrypt(self.pad(img)) mac.update(imgEnc) hash = mac.digest() hashKey = ByteUtil.trim(mac.digest(), 10) finalEnc = imgEnc + hashKey return finalEnc
def decrypt_file(enc_path, media_key, out_path=""): media_key = binascii.hexlify(media_key) derivative = HKDFv3().deriveSecrets(binascii.unhexlify(media_key), binascii.unhexlify(WHATSAPP_KEY), 112) splits = ByteUtil.split(derivative, 16, 32) iv = splits[0] cipher_key = splits[1] cipher = AES.new(key=cipher_key, mode=AES.MODE_CBC, IV=iv) if (out_path == ""): out_path = os.path.splitext(enc_path)[0] chunk_size = 4096 * 10 with open(enc_path, "rb") as in_file: with open(out_path, "wb") as out_file: while True: chunk = in_file.read(chunk_size) try: piece = cipher.decrypt(chunk) except: # Last chunk most likely to get into here # Because cipher needs a multiple of 16 piece = cipher.decrypt(pad(chunk)) if len(chunk) == 0: break # end of file out_file.write(piece) return out_path
def download_media(self, media_msg, force_download=False): if not force_download: try: if media_msg.content: return BytesIO(b64decode(media_msg.content)) except AttributeError: pass file_data = self.download_file(media_msg.client_url) if not file_data: raise Exception('Impossible to download file') media_key = b64decode(media_msg.media_key) derivative = HKDFv3().deriveSecrets( media_key, binascii.unhexlify(media_msg.crypt_keys[media_msg.type]), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipher_key = parts[1] e_file = file_data[:-10] cr_obj = Cipher(algorithms.AES(cipher_key), modes.CBC(iv), backend=default_backend()) decryptor = cr_obj.decryptor() return BytesIO(decryptor.update(e_file) + decryptor.finalize())
def download_media(self, media_msg, force_download=False): if not force_download: try: if media_msg.content: return BytesIO(b64decode(media_msg.content)) except AttributeError: pass file_data = self.download_file(media_msg.client_url) if not file_data: raise Exception('Impossible to download file') media_key = b64decode(media_msg.media_key) derivative = HKDFv3().deriveSecrets(media_key, binascii.unhexlify(media_msg.crypt_keys[media_msg.type]), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipher_key = parts[1] e_file = file_data[:-10] cr_obj = Cipher(algorithms.AES(cipher_key), modes.CBC(iv), backend=default_backend()) decryptor = cr_obj.decryptor() return BytesIO(decryptor.update(e_file) + decryptor.finalize())
def decrypt_file(enc_path, media_key, wakey, out_path): media_key = binascii.hexlify(media_key) derivative = HKDFv3().deriveSecrets(binascii.unhexlify(media_key), binascii.unhexlify(wakey), 112) splits = ByteUtil.split(derivative, 16, 32) iv = splits[0] cipher_key = splits[1] bs = AES.block_size cipher = AES.new(key=cipher_key, mode=AES.MODE_CBC, IV=iv) chunk_size = 4096 * bs with open(enc_path, "rb") as in_file: with open(out_path, "wb") as out_file: while True: chunk = in_file.read(chunk_size) try: piece = cipher.decrypt(chunk) except: # Last chunk most likely to get into here # Because cipher needs a multiple of 16 chunk = chunk[:-10] # assert len(chunk) % bs == 0 piece = cipher.decrypt(chunk) padding_len = piece[-1] piece = piece[:-padding_len] if len(chunk) == 0: break # end of file out_file.write(piece) return out_path
async def download_media(driver: BaseWhalesongDriver, model: MediaMixin) -> BytesIO: """ Download message's attached media file. It will decrypt media file using key on message object. :param driver: :param model: MediaMixin :return: Media stream. """ file_data = (await driver.download_file(model.client_url)).read() try: media_key = b64decode(model.media_key) except Exception: media_key = b64decode(model.media_key + ('=' * (len(model.media_key) % 3))) try: derivative = HKDFv3().deriveSecrets( media_key, binascii.unhexlify(CRYPT_KEYS[model.type]), 112) except KeyError: raise ValueError('Invalid message type') parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipher_key = parts[1] e_file = file_data[:-10] cr_obj = Cipher(algorithms.AES(cipher_key), modes.CBC(iv), backend=default_backend()) decryptor = cr_obj.decryptor() return BytesIO(decryptor.update(e_file) + decryptor.finalize())
def __init__(self, keyId = None, iteration = None, ciphertext = None, signatureKey = None, serialized = None): assert bool(keyId is not None and iteration is not None and ciphertext is not None and signatureKey is not None)\ ^ bool(serialized),\ "Either pass arguments or serialized data" if serialized: try: messageParts = ByteUtil.split(serialized, 1, len(serialized)- 1 - self.__class__.SIGNATURE_LENGTH, self.__class__.SIGNATURE_LENGTH) version = messageParts[0][0] message = messageParts[1] signature = messageParts[2] if ByteUtil.highBitsToInt(version) < 3: raise LegacyMessageException("Legacy message: %s" % ByteUtil.highBitsToInt(version)) if ByteUtil.highBitsToInt(version) > self.__class__.CURRENT_VERSION: raise InvalidMessageException("Unknown version: %s" % ByteUtil.highBitsToInt(version)) senderKeyMessage = whisperprotos.SenderKeyMessage() senderKeyMessage.ParseFromString(message) if senderKeyMessage.id is None or senderKeyMessage.iteration is None\ or senderKeyMessage.ciphertext is None: raise InvalidMessageException("Incomplete message") self.serialized = serialized self.messageVersion = ByteUtil.highBitsToInt(version) self.keyId = senderKeyMessage.id self.iteration = senderKeyMessage.iteration self.ciphertext = senderKeyMessage.ciphertext except Exception as e: raise InvalidMessageException(e) else: version = [ByteUtil.intsToByteHighAndLow(self.__class__.CURRENT_VERSION, self.__class__.CURRENT_VERSION)] message = whisperprotos.SenderKeyMessage() message.id = keyId message.iteration = iteration message.ciphertext = ciphertext message = message.SerializeToString() signature = self.getSignature(signatureKey, bytes(ByteUtil.combine(version, message))) self.serialized = bytes(ByteUtil.combine(version, message, signature)) self.messageVersion = self.__class__.CURRENT_VERSION self.keyId = keyId self.iteration = iteration self.ciphertext = ciphertext
def decrypt(self, encaud, refkey): derivative = HKDFv3().deriveSecrets(refkey, binascii.unhexlify(self.cryptKeys), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipherKey = parts[1] e_aud = encaud[:-10] AES.key_size = 128 cr_obj = AES.new(key=cipherKey, mode=AES.MODE_CBC, IV=iv) return cr_obj.decrypt(e_aud)
def decrypt(self, encimg, refkey): derivative = HKDFv3().deriveSecrets(refkey, binascii.unhexlify(self.cryptKeys), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipherKey = parts[1] e_img = encimg[:-10] AES.key_size=128 cr_obj = AES.new(key=cipherKey,mode=AES.MODE_CBC,IV=iv) return cr_obj.decrypt(e_img)
def decrypt(self, encimg, refkey): derivative = HKDFv3().deriveSecrets( refkey, binascii.unhexlify("576861747341707020496d616765204b657973"), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipherKey = parts[1] e_img = encimg[:-10] AES.key_size = 128 cr_obj = AES.new(key=cipherKey, mode=AES.MODE_CBC, IV=iv) return cr_obj.decrypt(e_img)
def verifySignature(self, signatureKey): """ :type signatureKey: ECPublicKey """ try: parts = ByteUtil.split(self.serialized, len(self.serialized)- self.__class__.SIGNATURE_LENGTH, self.__class__.SIGNATURE_LENGTH) if not Curve.verifySignature(signatureKey, parts[0], parts[1]): raise InvalidMessageException("Invalid signature!") except InvalidKeyException as e: raise InvalidMessageException(e)
def __init__(self, id = None, iteration = None, chainKey = None, signatureKey = None, serialized = None): """ :type id: int :type iteration: int :type chainKey: bytearray :type signatureKey: ECPublicKey """ assert bool(id is not None and iteration is not None and chainKey is not None and signatureKey is not None)\ ^ bool(serialized),\ "Either pass arguments or serialized data" if serialized: try: messageParts = ByteUtil.split(serialized, 1, len(serialized)- 1) version = messageParts[0][0] message = messageParts[1] if ByteUtil.highBitsToInt(version) < 3: raise LegacyMessageException("Legacy message: %s" % ByteUtil.highBitsToInt(version)) if ByteUtil.highBitsToInt(version) > self.__class__.CURRENT_VERSION: raise InvalidMessageException("Unknown version: %s" % ByteUtil.highBitsToInt(version)) distributionMessage = whisperprotos.SenderKeyDistributionMessage() distributionMessage.ParseFromString(message) if distributionMessage.id is None or distributionMessage.iteration is None\ or distributionMessage.chainKey is None or distributionMessage.signingKey is None: raise InvalidMessageException("Incomplete message") self.serialized = serialized self.id = distributionMessage.id self.iteration = distributionMessage.iteration self.chainKey = distributionMessage.chainKey self.signatureKey = Curve.decodePoint(bytearray(distributionMessage.signingKey), 0) except Exception as e: raise InvalidMessageException(e) else: version = [ByteUtil.intsToByteHighAndLow(self.__class__.CURRENT_VERSION, self.__class__.CURRENT_VERSION)] self.id = id self.iteration = iteration self.chainKey = chainKey self.signatureKey = signatureKey message = whisperprotos.SenderKeyDistributionMessage() message.id = id message.iteration = iteration message.chainKey= bytes(chainKey) message.signingKey = signatureKey.serialize() message = message.SerializeToString() self.serialized = bytes(ByteUtil.combine(version, message))
def decrypt(self, encimg, refkey, tipo="image"): cryptKeys = self.getCryptKeys(tipo) refkey = base64.b64decode(refkey) derivative = HKDFv3().deriveSecrets(refkey, binascii.unhexlify(cryptKeys), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipherKey = parts[1] e_img = encimg[:-10] cr_obj = AES.new(key=cipherKey, mode=AES.MODE_CBC, IV=iv) return cr_obj.decrypt(e_img)
def __init__(self, iteration, seed): """ :type iteration: int :type seed: bytearray """ derivative = HKDFv3().deriveSecrets(seed, "WhisperGroup".encode(), 48) parts = ByteUtil.split(derivative, 16, 32) self.iteration = iteration self.seed = seed self.iv = parts[0] self.cipherKey = parts[1]
def encryptImg(self, img, refkey): derivative = HKDFv3().deriveSecrets(binascii.unhexlify(refkey), binascii.unhexlify(WHATSAPP_KEY), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipherKey = parts[1] macKey = derivative[48:80] mac = hmac.new(macKey, digestmod=hashlib.sha256) mac.update(iv) cipher = AES.new(key=cipherKey, mode=AES.MODE_CBC, IV=iv) imgEnc = cipher.encrypt(self.pad(img)) mac.update(imgEnc) hash = mac.digest() hashKey = ByteUtil.trim(mac.digest(), 10) finalEnc = imgEnc + hashKey return finalEnc
def test_split(self): okm = HexUtil.decodeHex('02a9aa6c7dbd64f9d3aa92f92a277bf54609dadf0b00828acfc61e3c724b84a7bfbe5efb603030526742e3ee89c7024e884e' \ '440f1ff376bb2317b2d64deb7c8322f4c5015d9d895849411ba1d793a827') data = [i for i in range(0, 80)] a_data = [i for i in range(0, 32)] b_data = [i for i in range(32, 64)] c_data = [i for i in range(64, 80)] a,b,c = ByteUtil.split(data, 32, 32, 16) self.assertEqual(a, a_data) self.assertEqual(b, b_data) self.assertEqual(c, c_data)
def encrypt(self, plaintext, ref_key, media_info): derived = HKDFv3().deriveSecrets(ref_key, media_info, 112) parts = ByteUtil.split(derived, 16, 32) iv = parts[0] key = parts[1] mac_key = derived[48:80] cipher_encryptor = Cipher( algorithms.AES(key), modes.CBC(iv), backend=default_backend() ).encryptor() ciphertext = cipher_encryptor.update(plaintext) + cipher_encryptor.finalize() mac = hmac.new(mac_key, digestmod=hashlib.sha256) mac.update(iv) mac.update(ciphertext) return ciphertext + mac.digest()[:10]
async def download_media(driver, model): file_data = (await driver.download_file(model.client_url)).read() media_key = b64decode(model.media_key) try: derivative = HKDFv3().deriveSecrets(media_key, binascii.unhexlify(CRYPT_KEYS[model.type]), 112) except KeyError: raise ValueError('Invalid message type') parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipher_key = parts[1] e_file = file_data[:-10] cr_obj = Cipher(algorithms.AES(cipher_key), modes.CBC(iv), backend=default_backend()) decryptor = cr_obj.decryptor() return BytesIO(decryptor.update(e_file) + decryptor.finalize())
def decrypt(Url,MediaKey,filename,tipo): try: CipherData = urlopen(Url).read() CipherImage = CipherData[:-10] cryptKeys = getCryptKeys(tipo) # SecretsRaw = HKDFv3().deriveSecrets(MediaKey, "WhatsApp Image Keys", 112) SecretsRaw = HKDFv3().deriveSecrets(MediaKey, binascii.unhexlify(cryptKeys), 112) Secrets = ByteUtil.split(SecretsRaw, 16, 32) iv = Secrets[0] CipherKey = Secrets[1] AES.key_size=128 AESInstance = AES.new(key=CipherKey, mode=AES.MODE_CBC, IV=iv) PlainImage = AESInstance.decrypt(CipherImage) with open(filename, 'wb') as f: f.write(PlainImage) f.close() return "success"; except: return;
def decrypt(self, ciphertext, ref_key, media_info): derived = HKDFv3().deriveSecrets(ref_key, media_info, 112) parts = ByteUtil.split(derived, 16, 32) iv = parts[0] key = parts[1] mac_key = derived[48:80] media_ciphertext = ciphertext[:-10] mac_value = ciphertext[-10:] mac = hmac.new(mac_key, digestmod=hashlib.sha256) mac.update(iv) mac.update(media_ciphertext) if mac_value != mac.digest()[:10]: raise ValueError("Invalid MAC") cipher_decryptor = Cipher( algorithms.AES(key), modes.CBC(iv), backend=default_backend() ).decryptor() return cipher_decryptor.update(media_ciphertext) + cipher_decryptor.finalize()
def encrypt(self, plaintext, ref_key, media_info): derived = HKDFv3().deriveSecrets(ref_key, media_info, 112) parts = ByteUtil.split(derived, 16, 32) iv = parts[0] key = parts[1] mac_key = derived[48:80] cipher_encryptor = Cipher( algorithms.AES(key), modes.CBC(iv), backend=default_backend() ).encryptor() if len(plaintext) % 16 != 0: padder = padding.PKCS7(128).padder() padded_plaintext = padder.update(plaintext) + padder.finalize() else: padded_plaintext = plaintext ciphertext = cipher_encryptor.update(padded_plaintext) + cipher_encryptor.finalize() mac = hmac.new(mac_key, digestmod=hashlib.sha256) mac.update(iv) mac.update(ciphertext) return ciphertext + mac.digest()[:10]
def download_media(self, media_msg): try: if media_msg.content: return BytesIO(b64decode(self.content)) except AttributeError: pass file_data = self.download_file(media_msg.client_url) media_key = b64decode(media_msg.media_key) derivative = HKDFv3().deriveSecrets( media_key, binascii.unhexlify(media_msg.crypt_keys[media_msg.type]), 112) parts = ByteUtil.split(derivative, 16, 32) iv = parts[0] cipher_key = parts[1] e_file = file_data[:-10] AES.key_size = 128 cr_obj = AES.new(key=cipher_key, mode=AES.MODE_CBC, IV=iv) return BytesIO(cr_obj.decrypt(e_file))
def decrypt(self, ciphertext, ref_key, media_info): derived = HKDFv3().deriveSecrets(ref_key, media_info, 112) parts = ByteUtil.split(derived, 16, 32) iv = parts[0] key = parts[1] mac_key = derived[48:80] media_ciphertext = ciphertext[:-10] mac_value = ciphertext[-10:] mac = hmac.new(mac_key, digestmod=hashlib.sha256) mac.update(iv) mac.update(media_ciphertext) if mac_value != mac.digest()[:10]: raise ValueError("Invalid MAC") cipher_decryptor = Cipher( algorithms.AES(key), modes.CBC(iv), backend=default_backend() ).decryptor() decrypted = cipher_decryptor.update(media_ciphertext) + cipher_decryptor.finalize() unpadder = padding.PKCS7(128).unpadder() return unpadder.update(decrypted) + unpadder.finalize()
def __init__(self, messageVersion = None, sequence = None, flags=None, baseKey = None, baseKeySignature = None, ratchetKey = None, identityKey = None, serialized = None): """ :type messageVersion: int :type sequence: int :type flags:int :type baseKey: ECPublicKey :type baseKeySignature: bytearray :type ratchetKey: ECPublicKey :type identityKey: IdentityKey :type serialized: bytearray """ if serialized: try: parts = ByteUtil.split(serialized, 1, len(serialized)- 1) self.version = ByteUtil.highBitsToInt(parts[0][0]) self.supportedVersion = ByteUtil.lowBitsToInt(parts[0][0]) if self.version <= CiphertextMessage.UNSUPPORTED_VERSION: raise LegacyMessageException("Unsupportmessageed legacy version: %s" % self.version) if self.version > CiphertextMessage.CURRENT_VERSION: raise InvalidVersionException("Unkown version: %s" % self.version) message = whisperprotos.KeyExchangeMessage() message.ParseFromString(bytes(parts[1])) if not message.HasField("id") or not message.HasField("baseKey")\ or not message.HasField("ratchetKey") or not message.HasField("identityKey")\ or (self.version >= 3 and not message.HasField("baseKeySignature")): raise InvalidMessageException("Some required fields are missing!") self.sequence = message.id >> 5 self.flags = message.id & 0x1f self.serialized = serialized self.baseKey = Curve.decodePoint(bytearray(message.baseKey), 0) self.baseKeySignature = message.baseKeySignature self.ratchetKey = Curve.decodePoint(bytearray(message.ratchetKey), 0) self.identityKey = IdentityKey(message.identityKey, 0) except InvalidKeyException as e: raise InvalidMessageException(e) else: self.supportedVersion = CiphertextMessage.CURRENT_VERSION self.version = messageVersion self.sequence = sequence self.flags = flags self.baseKey = baseKey self.baseKeySignature = baseKeySignature self.ratchetKey = ratchetKey self.identityKey = identityKey version = [ByteUtil.intsToByteHighAndLow(self.version, self.supportedVersion)] keyExchangeMessage = whisperprotos.KeyExchangeMessage() keyExchangeMessage.id = (self.sequence << 5) | self.flags keyExchangeMessage.baseKey = baseKey.serialize() keyExchangeMessage.ratchetKey = ratchetKey.serialize() keyExchangeMessage.identityKey = identityKey.serialize() if messageVersion >= 3: keyExchangeMessage.baseKeySignature = baseKeySignature self.serialized = ByteUtil.combine(version, keyExchangeMessage.SerializeToString())