C++
C++11
DXライブラリ
DxLib
ear
DxLibDay 9

DxLibのDxArchiveの暗号化する機能とExport Administration Regulations 輸出管理規則

DxLib Advent Calendar 2018

この記事はDxLib Advent Calendar 2018 9日目の記事です

<< 8日目|自作のノベルゲームエンジンを作ってみた || 10日目|DXLibで川瀬式MGFを実装 >>

過疎っている。

はじめに

はいはい、タイトル長い長い。もともと2分割しようと思ってた内容を諸事情で一つにくっつけたからこうなる。

DxArchiveとは

正直必要性がわからない機能。

zipファイルと同じアルゴリズムで圧縮が一応かかるとはいえ、ゲームの素材なんてものはもともと圧縮されているものだからむしろ容量が増えるまである。

誰得なんだ・・・?

友人「ゲーム配布するときに素材フォルダをいじられて起動しなくなると困るので固めるために使う」

・・・なるほど、わからん。それDXAファイルを動かされたらあっさり詰むやつでは・・・?

やっぱり不要では?

DxArchiveの暗号化機能

そんな必要性が謎なDxArchiveに更に謎な機能として暗号化機能がある。

・・・何に使うんだ?

8127氏

ライセンスを購入して使用する有料ゲーム素材の中には(無断二次利用防止のため)
暗号化必須で使ってくださいというものがあるので、暗号化機能が無くなったりするととても困ります。

やっぱり謎。そもそも復号化するための鍵がクライアントサイドに最終的に有るのだから、どんなに頑張っても原理的に復号できる。

いや、もちろん復号するコストは上げられる。しかしDRMが滅びつつあるように、コンテンツ保護機能というものは基本的に害悪なのだ。

そして大抵のオチはコンテンツ保護機能がバグってクラッシュするとか、サーバーが閉鎖されて鍵が手に入れられなくなるとかそういうクソみたいな結末だ。

手元にFairUse4WM(有名なDRM解除ソフト)で解除できねーぜって謳って、破れるもんなら破ってみろと配布されていたDRM付きWMVがあるが、サーバーが閉鎖されて正規の再生もできなくなった。

じつにばかばかしい行為なのである。

しかしながら、無知な素材作成者が無意味にも暗号化を要求してくる以上そうせざるをえないのだろう。現実ってそんなもんらしい。

2018/08/12まで存在したDxArchiveの暗号化機能の脆弱性とそれに伴う仕様変更

http://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=4474

にて報告された。

なんと共通鍵を持っていなくても、また共通鍵を求めることなく復号化できるという致命的なバグがあったのだ。

・・・暗号化 #とは

というわけで、議論の末Hash関数にSHA-256を採用しつつ暗号化するように変更がなされました。12byteから一気に増えたね。

Export Administration Regulations 輸出管理規則(ESR)

アメリカには実に滑稽な法律がって、Export Administration Regulationsというやつがそれなのだが、要するに暗号化技術の一部に対して規制がかかりますよ、というものだ。

昔は今以上に規制が厳しくて、たとえばPGPはアメリカ国外へソースコードを含むソフトウェアを輸出できないというお馬鹿な事態が発生していた。

仕方ないからThe PGPi scanning projectっていうのが立ち上がって、紙媒体なら法律で規制外という点を突いてソースコードを印刷して本12冊に分冊して出版、ヨーロッパの有志によってOCRされリリースとかいう茶番が繰り広げられていた。

暗号化ソフトのソースコードを6000ページもの本12冊にして合法的に輸出した壮大なプロジェクト「PGPi scanning project」 - GIGAZINE

で、この規制が若干緩んだものの今もなお存在してる。

ところで執筆現在でもよくわかっていないんだが、このESRってワッセナー・アレンジメントに含まれているんですか?外為法第25条を眺めてもよくわからんかったんですが。

追記:
たまたまTwitterで @arclisp 氏が

輸出令別表第1の9の項(7)(省令第8条第九号)情報セキュリティ(暗号装置)該非用パラメータシート(情報セキュリティ・貨物) 様式9-07
http://www.cistec.or.jp/publication/teisei_data/b-03tuushin/20180130.pdf

というのを見つけました。

DxLibへの影響

で、これがDxLibに影響あるんじゃないかという指摘が10/31になされました。

http://dxlib.o.oo7.jp/cgi/patiobbs/patio.cgi?mode=view&no=4534&p=1

さて、ESRですが、Exportというぐらいだから、アメリカからの輸出に対しての規制です。

これだとピンときてないかもしれないのでもうちょっと踏み込むと、AndroidのGoogle PlayとかApple StoreとかGithub ReleaseとかNugetとかはアメリカ国内に拠点を持つ企業のサービスであり、アメリカからの輸出に該当します。

DxLibには以前は12byte=96bitの鍵、上述の通りSHA-256すなわち256bitへの変更があり、いずれにせよ共通鍵方式で56bitを超える鍵が利用されてきました。

というわけでこの辺をみつつ、影響を解釈していきましょう。

DxLib自体

これはDxLibの再頒布も含みます

結論から言うと届け出(許可例外TSU)が必要です。

何故かと言うとDxLibはNuGetでも配布されており、共通鍵方式で56bitを超える鍵が使われているからです。

というわけでDxLib自体は届け出(メールを投げつける)をやったそうです。

ところが、DxLibは結構あちこちで再頒布されているらしく、ここで問題が生じます。

つまりアメリカからの輸出という形態に該当する形で再頒布するたびに再頒布を行う主体の人が届け出(許可例外TSU)をしなければならないということです。

業を煮やしたDxLib作者は鍵を56bitに弱体化すると表明しました。まじかよ・・・。

結局CRC32を2回適用して56bit分取り出し、LZ圧縮とハフマン圧縮で固定ヘッダー攻撃防止を行ったようです。

DxLibのDXA暗号化機能を利用していないアプリケーション

届け出不要です。

DxLibのDXA暗号化機能を「知的所有権・著作権保護」のために利用するアプリケーション

届け出不要です。

DxLibのDXA暗号化機能をその他の目的で利用する場合

一体どんなことをすればこれに該当するのかわかりませんが、例えば通信の暗号化にDXAの暗号化を使ったとかそんなんですかね・・・?

この場合はECCN番号分類に従って手続きが必要になります。

結論

自由ソフトウェアの発展を阻害するExport Administration Regulationsは死すべし、慈悲はない。

余談: DxArchiveの暗号化機能を利用するときにパスワードをどのようにプログラム内で指定するべきか

まあ何やっても完全に秘匿することはできないわけですが、そのまま文字列リテラルとして書いてしまうとバイナリエディタで実行ファイルを覗くだけでパスワードがわかってしまいます。

せっかく暗号化機能を使うなら流石にもうひと工夫くらいしたほうがいいでしょう。

https://gist.github.com/yumetodo/238c52d4382db93e1978743cf299ba4d

#include "inferior_encrypted_string.hpp"
#include <iostream>
#if defined(DXLIB_CUSTOM_NO_CXX11_CONSTEXPR) && defined(DXLIB_CUSTOM_NO_CXX14_CONSTEXPR)
const inferior_encrypted_string::inferior_encrypted_string<char, sizeof("arikitari")> s1 = inferior_encrypted_string::make_inferior_encrypted_string("arikitari");
const inferior_encrypted_string::inferior_encrypted_string<char, sizeof("ありきたりな世界")> s2 = inferior_encrypted_string::make_inferior_encrypted_string("ありきたりな世界");
#else
constexpr auto s1 = inferior_encrypted_string::make_inferior_encrypted_string("arikitari");
constexpr auto s2 = inferior_encrypted_string::make_inferior_encrypted_string("ありきたりな世界");
#endif
int main()
{
    std::cout
        << s1.str << std::endl
        << s1.decrypt() << std::endl
        << std::endl
        << s2.str << std::endl
        << s2.decrypt() << std::endl;
}

https://wandbox.org/permlink/SOsUuAvhLRbFeWUS

のようにすることでDxLibが対応するコンパイラすべてでコンパイルは通りつつ、C++11のconstexprが利用できればバイナリエディタからは覗けなくなります(C++11consteexprが利用できない環境では無意味です)。

中身的には各byteに31を減算する作業をコンパイル時に行って、実行時に31を加算して戻しているだけのものです。

なお

add BYTE PTR [ecx],0x1f

のようなかなり特徴的なコードが吐かれるようなので依然として破るのは簡単だったりします。