diff --git a/yt_dlp/aes.py b/yt_dlp/aes.py index 8503e3dfd..b37f0dd39 100644 --- a/yt_dlp/aes.py +++ b/yt_dlp/aes.py @@ -2,8 +2,15 @@ from __future__ import unicode_literals from math import ceil -from .compat import compat_b64decode, compat_pycrypto_AES -from .utils import bytes_to_intlist, intlist_to_bytes +from .compat import ( + compat_b64decode, + compat_ord, + compat_pycrypto_AES, +) +from .utils import ( + bytes_to_intlist, + intlist_to_bytes, +) if compat_pycrypto_AES: @@ -25,6 +32,10 @@ else: return intlist_to_bytes(aes_gcm_decrypt_and_verify(*map(bytes_to_intlist, (data, key, tag, nonce)))) +def unpad_pkcs7(data): + return data[:-compat_ord(data[-1])] + + BLOCK_SIZE_BYTES = 16 @@ -506,5 +517,6 @@ __all__ = [ 'aes_encrypt', 'aes_gcm_decrypt_and_verify', 'aes_gcm_decrypt_and_verify_bytes', - 'key_expansion' + 'key_expansion', + 'unpad_pkcs7', ] diff --git a/yt_dlp/cookies.py b/yt_dlp/cookies.py index 700415b35..fc033a8ae 100644 --- a/yt_dlp/cookies.py +++ b/yt_dlp/cookies.py @@ -11,7 +11,11 @@ from datetime import datetime, timedelta, timezone from enum import Enum, auto from hashlib import pbkdf2_hmac -from .aes import aes_cbc_decrypt_bytes, aes_gcm_decrypt_and_verify_bytes +from .aes import ( + aes_cbc_decrypt_bytes, + aes_gcm_decrypt_and_verify_bytes, + unpad_pkcs7, +) from .compat import ( compat_b64decode, compat_cookiejar_Cookie, @@ -846,10 +850,9 @@ def pbkdf2_sha1(password, salt, iterations, key_length): def _decrypt_aes_cbc(ciphertext, key, logger, initialization_vector=b' ' * 16): - plaintext = aes_cbc_decrypt_bytes(ciphertext, key, initialization_vector) - padding_length = plaintext[-1] + plaintext = unpad_pkcs7(aes_cbc_decrypt_bytes(ciphertext, key, initialization_vector)) try: - return plaintext[:-padding_length].decode('utf-8') + return plaintext.decode('utf-8') except UnicodeDecodeError: logger.warning('failed to decrypt cookie (AES-CBC) because UTF-8 decoding failed. Possibly the key is wrong?', only_once=True) return None diff --git a/yt_dlp/downloader/fragment.py b/yt_dlp/downloader/fragment.py index d4f112b0f..19c0990d3 100644 --- a/yt_dlp/downloader/fragment.py +++ b/yt_dlp/downloader/fragment.py @@ -14,7 +14,7 @@ except ImportError: from .common import FileDownloader from .http import HttpFD -from ..aes import aes_cbc_decrypt_bytes +from ..aes import aes_cbc_decrypt_bytes, unpad_pkcs7 from ..compat import ( compat_os_name, compat_urllib_error, @@ -366,8 +366,7 @@ class FragmentFD(FileDownloader): # not what it decrypts to. if self.params.get('test', False): return frag_content - decrypted_data = aes_cbc_decrypt_bytes(frag_content, decrypt_info['KEY'], iv) - return decrypted_data[:-decrypted_data[-1]] + return unpad_pkcs7(aes_cbc_decrypt_bytes(frag_content, decrypt_info['KEY'], iv)) return decrypt_fragment diff --git a/yt_dlp/extractor/adn.py b/yt_dlp/extractor/adn.py index 5a1283baa..0863e0d85 100644 --- a/yt_dlp/extractor/adn.py +++ b/yt_dlp/extractor/adn.py @@ -8,11 +8,10 @@ import os import random from .common import InfoExtractor -from ..aes import aes_cbc_decrypt +from ..aes import aes_cbc_decrypt_bytes, unpad_pkcs7 from ..compat import ( compat_HTTPError, compat_b64decode, - compat_ord, ) from ..utils import ( ass_subtitles_timecode, @@ -84,14 +83,11 @@ class ADNIE(InfoExtractor): return None # http://animedigitalnetwork.fr/components/com_vodvideo/videojs/adn-vjs.min.js - dec_subtitles = intlist_to_bytes(aes_cbc_decrypt( - bytes_to_intlist(compat_b64decode(enc_subtitles[24:])), - bytes_to_intlist(binascii.unhexlify(self._K + 'ab9f52f5baae7c72')), - bytes_to_intlist(compat_b64decode(enc_subtitles[:24])) - )) - subtitles_json = self._parse_json( - dec_subtitles[:-compat_ord(dec_subtitles[-1])].decode(), - None, fatal=False) + dec_subtitles = unpad_pkcs7(aes_cbc_decrypt_bytes( + compat_b64decode(enc_subtitles[24:]), + binascii.unhexlify(self._K + 'ab9f52f5baae7c72'), + compat_b64decode(enc_subtitles[:24]))) + subtitles_json = self._parse_json(dec_subtitles.decode(), None, fatal=False) if not subtitles_json: return None diff --git a/yt_dlp/extractor/drtv.py b/yt_dlp/extractor/drtv.py index 70134204c..37e4d5b26 100644 --- a/yt_dlp/extractor/drtv.py +++ b/yt_dlp/extractor/drtv.py @@ -7,13 +7,11 @@ import re from .common import InfoExtractor -from ..aes import aes_cbc_decrypt +from ..aes import aes_cbc_decrypt_bytes, unpad_pkcs7 from ..compat import compat_urllib_parse_unquote from ..utils import ( - bytes_to_intlist, ExtractorError, int_or_none, - intlist_to_bytes, float_or_none, mimetype2ext, str_or_none, @@ -191,13 +189,11 @@ class DRTVIE(InfoExtractor): def decrypt_uri(e): n = int(e[2:10], 16) a = e[10 + n:] - data = bytes_to_intlist(hex_to_bytes(e[10:10 + n])) - key = bytes_to_intlist(hashlib.sha256( - ('%s:sRBzYNXBzkKgnjj8pGtkACch' % a).encode('utf-8')).digest()) - iv = bytes_to_intlist(hex_to_bytes(a)) - decrypted = aes_cbc_decrypt(data, key, iv) - return intlist_to_bytes( - decrypted[:-decrypted[-1]]).decode('utf-8').split('?')[0] + data = hex_to_bytes(e[10:10 + n]) + key = hashlib.sha256(('%s:sRBzYNXBzkKgnjj8pGtkACch' % a).encode('utf-8')).digest() + iv = hex_to_bytes(a) + decrypted = unpad_pkcs7(aes_cbc_decrypt_bytes(data, key, iv)) + return decrypted.decode('utf-8').split('?')[0] for asset in assets: kind = asset.get('Kind') diff --git a/yt_dlp/extractor/newstube.py b/yt_dlp/extractor/newstube.py index dab4aec44..479141ae0 100644 --- a/yt_dlp/extractor/newstube.py +++ b/yt_dlp/extractor/newstube.py @@ -5,11 +5,9 @@ import base64 import hashlib from .common import InfoExtractor -from ..aes import aes_cbc_decrypt +from ..aes import aes_cbc_decrypt_bytes, unpad_pkcs7 from ..utils import ( - bytes_to_intlist, int_or_none, - intlist_to_bytes, parse_codecs, parse_duration, ) @@ -47,10 +45,8 @@ class NewstubeIE(InfoExtractor): })) key = hashlib.pbkdf2_hmac( 'sha1', video_guid.replace('-', '').encode(), enc_data[:16], 1)[:16] - dec_data = aes_cbc_decrypt( - bytes_to_intlist(enc_data[32:]), bytes_to_intlist(key), - bytes_to_intlist(enc_data[16:32])) - sources = self._parse_json(intlist_to_bytes(dec_data[:-dec_data[-1]]), video_guid) + dec_data = unpad_pkcs7(aes_cbc_decrypt_bytes(enc_data[32:], key, enc_data[16:32])) + sources = self._parse_json(dec_data, video_guid) formats = [] for source in sources: diff --git a/yt_dlp/extractor/rtl2.py b/yt_dlp/extractor/rtl2.py index 4e3aa0398..e29171474 100644 --- a/yt_dlp/extractor/rtl2.py +++ b/yt_dlp/extractor/rtl2.py @@ -4,16 +4,13 @@ from __future__ import unicode_literals import re from .common import InfoExtractor -from ..aes import aes_cbc_decrypt +from ..aes import aes_cbc_decrypt_bytes, unpad_pkcs7 from ..compat import ( compat_b64decode, - compat_ord, compat_str, ) from ..utils import ( - bytes_to_intlist, ExtractorError, - intlist_to_bytes, int_or_none, strip_or_none, ) @@ -142,17 +139,12 @@ class RTL2YouIE(RTL2YouBaseIE): self._BACKWERK_BASE_URL + 'stream/video/' + video_id, video_id) data, iv = compat_b64decode(stream_data['streamUrl']).decode().split(':') - stream_url = intlist_to_bytes(aes_cbc_decrypt( - bytes_to_intlist(compat_b64decode(data)), - bytes_to_intlist(self._AES_KEY), - bytes_to_intlist(compat_b64decode(iv)) - )) + stream_url = unpad_pkcs7(aes_cbc_decrypt_bytes( + compat_b64decode(data), self._AES_KEY, compat_b64decode(iv))) if b'rtl2_you_video_not_found' in stream_url: raise ExtractorError('video not found', expected=True) - formats = self._extract_m3u8_formats( - stream_url[:-compat_ord(stream_url[-1])].decode(), - video_id, 'mp4', 'm3u8_native') + formats = self._extract_m3u8_formats(stream_url.decode(), video_id, 'mp4', 'm3u8_native') self._sort_formats(formats) video_data = self._download_json( diff --git a/yt_dlp/extractor/shemaroome.py b/yt_dlp/extractor/shemaroome.py index 00a5b00cd..45c12915a 100644 --- a/yt_dlp/extractor/shemaroome.py +++ b/yt_dlp/extractor/shemaroome.py @@ -2,10 +2,9 @@ from __future__ import unicode_literals from .common import InfoExtractor -from ..aes import aes_cbc_decrypt +from ..aes import aes_cbc_decrypt, unpad_pkcs7 from ..compat import ( compat_b64decode, - compat_ord, ) from ..utils import ( bytes_to_intlist, @@ -76,8 +75,7 @@ class ShemarooMeIE(InfoExtractor): url_data = bytes_to_intlist(compat_b64decode(data_json['new_play_url'])) key = bytes_to_intlist(compat_b64decode(data_json['key'])) iv = [0] * 16 - m3u8_url = intlist_to_bytes(aes_cbc_decrypt(url_data, key, iv)) - m3u8_url = m3u8_url[:-compat_ord((m3u8_url[-1]))].decode('ascii') + m3u8_url = unpad_pkcs7(intlist_to_bytes(aes_cbc_decrypt(url_data, key, iv))).decode('ascii') formats, m3u8_subs = self._extract_m3u8_formats_and_subtitles(m3u8_url, video_id, fatal=False, headers={'stream_key': data_json['stream_key']}) self._sort_formats(formats)