Расшифруйте плейлист M3U8 с шифрованием AES-128 без IV - PullRequest
0 голосов
/ 31 мая 2018

В настоящее время я создаю приложение для загрузки плейлистов M3U8, но у меня возникла проблема: если плейлист зашифрован с помощью AES-128, например, имеет такую ​​строку:

#EXT-X-KEY:METHOD=AES-128,URI="https://website.com/link.key",IV=0xblablabla

Я должен расшифровать сегменты перед записью их в выходной файл, и, если присутствует IV, приведенный ниже код работает для меня, но если свойство IV не существует, дешифрование дает неправильный результат:

var iv = "parsed iv"; // empty if not present
var key_url = "parsed keyurl";

var AES = new AesManaged()
{
    Mode = CipherMode.CBC,
    Key = await Client.GetByteArrayAsync(key_url)
};

if (!string.IsNullOrEmpty(iv))
    AES.IV = Functions.HexToByte(iv.StartsWith("0x") ? iv.Remove(0, 2) : iv);
else
    AES.IV = new byte[16];

//...

using (FileStream fs = new FileStream("file.ts", FileMode.Create, FileAccess.Write, FileShare.Read))
{
    var data = DownloadSegment(...); // Downloads segment as byte array (encrypted)

    byte[] temp = new byte[data.Length];

    ICryptoTransform transform = AES.CreateDecryptor();
    using (MemoryStream memoryStream = new MemoryStream(data))
    {
        using (CryptoStream cryptoStream = new CryptoStream(memoryStream, transform, CryptoStreamMode.Read))
        {
            cryptoStream.Read(temp, 0, data.Length);
        }
    }

    await fs.WriteAsync(temp, 0, temp.Length);
}

(Это, очевидно, всего лишь фрагмент кода, содержащий часть расшифровки, поскольку все операции синтаксического анализа и загрузки работают нормально).

Кто-нибудь из вас знает, как расшифровать AES?-128 зашифрованный сегмент в файле списка воспроизведения M3U8, если отсутствует IV, например, просто

#EXT-X-KEY:METHOD=AES-128,URI="https://website.com/link.key"?

Любая помощь будет принята с благодарностью.Заранее спасибо!

Ответы [ 3 ]

0 голосов
/ 24 июня 2018

Я реализовал это следующим образом (где seqNum - порядковый номер мультимедиа для этого сегмента):

readonly byte[] blank8Bytes = new byte[8];

// [...]
    AES.IV = blank8Bytes.Concat(IntToBigEndianBytes(seqNum)).ToArray();
// [...]    

// https://stackoverflow.com/a/1318948/9526448
private static byte[] IntToBigEndianBytes(ulong intValue)
{
    byte[] intBytes = BitConverter.GetBytes(intValue);
    if (BitConverter.IsLittleEndian)
        Array.Reverse(intBytes);
    byte[] result = intBytes;
    return result;
}

FYI, так как вы сказали, что также анализируете плейлисты, яНапомню, что я разветвил парсер плейлистов iHeartRadio open-m3u8 и перевел его на C #.Если вам интересно, библиотека C # находится здесь: https://github.com/bzier/open-m3u8

0 голосов
/ 30 апреля 2019

Я знаю, что bzier уже правильно ответил на этот вопрос, но я решил упомянуть об этом для будущих читателей:

С парсингом / дешифрованием файлов m3u8 можно обращаться с помощью ffmpeg автоматически.Взглянув на исходный код , мы можем понять, как устанавливается IV, когда он не предоставляется.

Это также задокументировано в RFC 8216.

Если вы чувствуете необходимость сделать это самостоятельно в C #, вот полностью рабочий пример:

string m3u8_url = "https://example.com/file.m3u8";

WebClient web = new WebClient();
Stream m3u8_data = web.OpenRead(m3u8_url);
web.Dispose();

M3u8Content content = new M3u8Content();
M3uPlaylist playlist = content.GetFromStream(m3u8_data);
int media_sequence = 0;

// 16 chars - steal this from the key file.
byte[] key = Encoding.ASCII.GetBytes("0123456701234567");

string path = Path.GetFullPath("output.mp4");
FileStream fs = File.Create(path);

foreach(M3uPlaylistEntry entry in playlist.PlaylistEntries) {

    // establish initialization vector
    // note: iv must be 16 bytes (AES-128)
    byte[] iv = media_sequence.ToBigEndianBytes(); // 8 bytes
    iv = new byte[8].Concat(iv).ToArray(); // add 8 empty bytes to beginning

    // https://tools.ietf.org/html/rfc8216#section-4.3.2.4
    // HLS uses AES-128 w/ CBC & PKCS7
    RijndaelManaged algorithm = new RijndaelManaged() {
        Padding = PaddingMode.PKCS7,
        Mode = CipherMode.CBC,
        KeySize = 128,
        BlockSize = 128
    };

    // key = from uri in m3u8 file
    // iv = derived from sequence number
    algorithm.Key = key;
    algorithm.IV = iv;

    web = new WebClient();
    byte[] data = web.DownloadData(entry.Path);

    // create memorystream to store bytes & cryptostream to decrypt
    MemoryStream ms = new MemoryStream();
    CryptoStream cs = new CryptoStream(ms, algorithm.CreateDecryptor(), CryptoStreamMode.Write);

    // decrypt data to memorystream
    cs.Write(data, 0, data.Length);

    // write decrypted bytes to our mp4 file
    byte[] bytes = ms.ToArray();
    fs.Write(bytes, 0, bytes.Length);

    // close/dispose those streams
    cs.Close();
    ms.Close();
    cs.Dispose();
    ms.Dispose();

    // increment media sequence to update initialization vector
    media_sequence++;

}

// close the file stream & dispose of it
fs.Close();
fs.Dispose();

Вот функция расширения ToBigEndianBytes, которую я позаимствовал из ответа bzier.

public static byte[] ToBigEndianBytes(this int i) {
    byte[] bytes = BitConverter.GetBytes(Convert.ToUInt64(i));
    if (BitConverter.IsLittleEndian)
        Array.Reverse(bytes);
    return bytes;
}

Этот код использует PlaylistsNET для разбора записей плейлиста, и вам придется установить последовательность ключей / начального носителя вручную - но она показывает шифрование и его работу.

Тем не менее, я настоятельно рекомендую использовать ffmpeg.

string cmd = string.Format("ffmpeg -i \"{0}\" -c copy -bsf:a aac_adtstoasc \"{1}\"", m3u8_url, local_mp4_path);
Execute(cmd);

public static void ExecuteCommand(string command) {
    Process process = new Process();
    ProcessStartInfo startInfo = new ProcessStartInfo();
    startInfo.WindowStyle = ProcessWindowStyle.Hidden;
    startInfo.FileName = "cmd.exe";
    startInfo.Arguments = "/C " + command;
    process.StartInfo = startInfo;
    process.Start();
    process.WaitForExit();
}

Это выполнит то же самое с меньшим количеством кода, и вам не нужно будет конвертировать полученный итоговый файл .ts в .mp4, потому что ffmpeg может сделать это за вас..

0 голосов
/ 04 июня 2018

Спецификация HLS гласит [1]:

Метод шифрования AES-128 сообщает, что медиа-сегменты полностью зашифрованы с использованием расширенного стандарта шифрования (AES) [AES_128] с 128-битнымkey, Cipher Block Chaining (CBC) и дополнения к криптографическим стандартам открытого ключа № 7 (PKCS7) [RFC5652].CBC перезапускается на границе каждого сегмента, используя либо значение атрибута Вектор инициализации (IV) , либо порядковый номер носителя в качестве IV;см. раздел 5.2.

Таким образом, вы должны использовать значение тега EXT-X-MEDIA-SEQUENCE в варианте списка воспроизведения.Обязательно экстраполируйте, то есть увеличивайте его для каждого сегмента.

[1] https://tools.ietf.org/html/rfc8216#section-4.3.2.4

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...