Androidマンになりたいおじさん

自分の備忘録的なのです。Androidを普及できたらいいなと思ったりしながら書きます

暗号化配信について(ExoPlayer + HLS + AES-128)

はじめに

こんにちは!!!!!!最近、暗号周りの勉強をして面白かったので、見返せるように書いてみました!

ここで主に紹介するのはAndroid + HLS + AES-128になりますmm

暗号化配信

最近、当たり前となってきてるストリーミング配信ですが、インターネットを通じて配信されてるので様々な不正利用が考えられます。コンテンツを保護するためにしっかりとコンテンツを暗号化してから、配信しましょう。

暗号化配信の他にも DRM配信がありますが、詳しくは別記事に書いてますmm gumiossan.hatenablog.com

まずは暗号化によく出てきそうなワードを紹介していきます。 暗号化配信では、共通鍵暗号が主に使われるみたいです。

共通鍵暗号

暗号化と復号化の際に使用する鍵が一緒のことを指します。 鍵が漏れたら、誰でも復号されてしまうから、鍵を如何に安全に配布することが重要になってくる。 処理速度が特徴となってるので、大きなサイズの暗号化に向いてます。

共通鍵暗号には大きく以下のような手法があります。

  • ブロック暗号
  • ストリーム暗号

ブロック暗号

平文を一定の大きさ(ブロック)にいくつかまとめて暗号化するやり方。暗号文は平文のサイズと同じになる。

ブロックサイズよりも大きな平文を暗号化するには暗号化モードというのを利用します。

いくつかに区切って処理しているので、処理負荷が小さい。

AES(64, 128, 256)などが代表的なものです。

ストリーム暗号

平文を小さな単位(1bit, 1byte..etc.)で順次処理で暗号化するやり方。

平文と鍵のXOR(排他的論理和)をとって、暗号・復号するのが特徴。

細かい単位で処理しているので、処理速度は速いが効率は悪い。

リアルタイム性が求められる、無線LANの暗号化などにも使われてるみたいです。

安全性はブロック暗号の方が優れているとか...。

IV

IV(initializationn vector) = 初期化ベクトル -> データを解読しにくくするためのランダムなbit列のこと。

例えば、同じコンテンツを同じkeyで何度も暗号化してたら、そのうち暗号文から推測などがされたり、バレる危険性があります。

それを防ぐために同じコンテンツを同じkeyで暗号化はするのですが、IVを合間に挟むことで結果的に出力される暗号文を変える役割を担っています。

ブロック暗号, ストリーム暗号両方で使われていて、両者でIVの実装は異なる。

ブロック暗号IV

後述するCBCモードでIVが主に使われる。

平文と直前の暗号化したブロックを参照し、XORをしたものが次のブロックの暗号文となる。

初めて暗号化する時だけ、直前のブロックはないのでIVが使われる。

ストリーム暗号IV

こっちは単純で疑似乱数生成器で暗号文を作成するのですが、毎回同じseedを使っていると出力される乱数がパターン化される。 なので、(IV + seed)をすることで疑似乱数生成器に偏りをなくすのに使われる。

暗号化モード

ブロック暗号でブロックサイズよりも大きいサイズの平文を暗号化するときに利用するもの。

  • CBC
  • CTR
  • ECB
  • CFB..etc.

色々モードはありますが、配信ではCBC, CTRが主に使われるみたいです。DRMでもこの2つが使われています。

CBCモード

CBC(Cipher Block Chaining) = 暗号ブロック連鎖

先程のブロック暗号IVで紹介したまんまのモードです。

直前の暗号ブロックと平文ブロックにXORをとり、それが次の暗号文となるのを最後まで繰り返します。

一番最初はIVでXORをとります。

つまり、暗号化のときは直前情報がいるから並列処理ができない....(復号化のときはできる)

平文コンテンツがブロックに分けた時にサイズが綺麗に割り切れるとは言い切れません。

なので、最後の方でスカスカになってブロックサイズを埋め合わせたいという時に使われるのがパディングというデータで埋めます。

CTRモード

CTR(CounTeR) = カウンタモード

ブロック暗号なんですが、モードを切り替えることでストリーム暗号として扱えるみたいです。

1ずつインクリメントしていくカウンタを用意し、それを暗号化し、出力される暗号文と平文ブロックでXORをとる。

ストリーム暗号なので、CBCと違いパディングなどの調整は必要ないということですね! こっちでは暗号化も復号化も並列処理ができる...!!!

カウンタは0, 1, 2, 3...nとなっていきますが、それだと結果が固定化しちゃいますよね。 なので、ノンスと言われる使い捨て乱数とカウンタを組み合わせるみたいです! -> IVみたいなもんですね。

HLS + AES-128

HLSの暗号化仕様はAES-128で、CBCやCTRモードのブロック暗号みたいです。

使い方

MediaPlaylistに#EXT-X-KEYを宣言してあげましょう。

サンプル

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:5
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="https://sample.jp/hls/video/key/hoge.key",IV=0123456789ABCDEF0123456789ABCDEF
#EXTINF:5.0000,
otamesi01.ts
#EXTINF:5.0000,
otamesi02.ts
  • METHOD -> AES-128を使うよ!
  • URI -> keyの場所を指してるよ!
  • IV -> 上記で説明していた、IVで、CTRモードなのでノンスとして扱われる(?)

Android

特にクライアントは意識することはないんですが、知っとくだけでも面白いかもしれないですね!

ExoPlayerでは、MediaPlaylistを取得し、そこに記されたsegment file(.ts)を取得してくるのですが、ここの段階でAes128DataSourceを合間に挟んで、内部でURIのkeyとIVを使い、復号化しています。

お気づきかもしれませんが、めちゃくちゃ強度しては弱いです...。キャプチャできる人なら、やりたい放題ということですね...。なので、より強固なDRMを使おうというわけですね!!!

以下は暗号化されたコンテンツをlocalで試したくなったときにどうしたらいいんだろう?ってなったので、その時のメモです!

任意のts fileを用意して、ffmpegとかで暗号化しちゃって、その時使ったkeyをlocal pathとして配置して、MediaPlaylistを作成し、上記のSampleみたいに適切なURIとIVさえ宣言できれば大丈夫そうです!

作成したMediaPlaylistと再生したいts fileをassetsフォルダーを作成し、配置してあげます。

ExoPlayerのDefaultDataSourceFactoryがあり、これはassets配下のhlsをいい感じに読み込んでくれます。 ただのlocalオンリーなら、これでいいのですがURI先が通信発生するのであれば、HttpDataSourceFactoryDefaultDataSourceFactoryの引数に指定してあげます。

あとは再生urlにurl = "asset:///hogehoge.m3u8"という風に指定してあげれば、再生できますb

まとめ

暗号って難しい分野だと個人的には思ってるのですが、これがないとインターネットの秩序は最悪ですね。。。先人に感謝しましょう!

余裕がある人はDRMを使って、動画を守っていきましょう!!

それでは皆さん、よいExo lifeを!!!!!!