トップページ > 記事閲覧
DXアーカイブの脆弱性と改善提案
名前:8127 日時: 2018/07/26 12:14

私が作ったゲームはDXアーカイブの暗号化機能を用いています。 噂でtouhouSEというフリーソフトで.dxaが展開できると聞いて、まさかと思って試したのですが展開されてしまいました。 暗号化時に14byte(漢字7文字)を使っているのにもかかわらず数秒で展開されたので、さすがに総当たりでキーを探しているのではないと思いました。 touhouSE(とDxArchive)のソースを読んだのですが、以下のことが分かりました。(アーカイブver6の仕様) ・アーカイブの圧縮時にどんなPWを指定しても、12byteのキーに変換されて圧縮される ・暗号化処理は12byteごとにキーとのxorをかけている ・.dxaの初め48byteは様々な情報を含んだヘッダである ・ヘッダのうち、8byte目から4byteはヘッダのサイズ48 = 0x00000030 が必ず格納されている ・touhouSEは、この仕様を悪用して8byte目から4byteを読み、それと0x00000030のxorをとることでキーの上位4byteを取得している ・同様の方法で全キー12byteを解析される となっているようです。 私の思いつく範囲の対策では以下のようなものがありますがいかがでしょうか? ・48byteのヘッダに対しては、悪用されるのでxor処理をしない ・キーを12byteではなく例えば1024byteにすれば、暗号化前のデータに0x00000000等があったとしてもキーの解析は難しくなるのではないか。 ・ユーザーの入力した短いパスから1024byteのバイナリキーを得る方法として、MD5等の一方向ハッシュ関数を使う ※管理人様は今特にご多忙でいらっしゃると思いますので、すぐに直していただかなくて構いません(11月までにやっていただきたいです・・・) ※私用のため私は今から5日ほど返信できません。
メンテ

Page: 1 | 2 | 3 |

Re: DXアーカイブの脆弱性と改善提案 ( No.24 )
名前:コーラ 日時:2018/08/04 20:35

あと、暗号化の仕組みを変えてしまうと過去のバージョンとの互換がなくなってしまうと思うので DXアーカイブとDXライブラリのバージョン管理が面倒になるのかなと思いました。 なので今回の対応としては以下にとどめておいた方が良いのではないでしょうか? ・DXアーカイブとしては安全性は担保しないという旨の記載を追記 ・利用者側で暗号化をかける場合のサンプルコードなどをミニテクニックに記載
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.25 )
名前:yumetodo 日時:2018/08/04 21:39

>yumetodoさんも #if などで対応されている通りまだ安定していない機能で 安定しています。C++の言語仕様に破壊的変更が入るとも思えません(C++は破壊的変更に極めて慎重なので)。 (constexpr自体はC++20で動的メモリ確保ができそうな勢いではあるけど本件に影響しない) #if使っているのはDxLibがサポートしているコンパイラーのすべてで動くようにし、かつ可能な限りconstexprが有効になるようにしているためです。 > あと、暗号化の仕組みを変えてしまうと過去のバージョンとの互換がなくなってしまうと思うので DXAの仕様を詳しくは知りませんが、後方互換性はあるはずでは
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.26 )
名前:yumetodo 日時:2018/08/04 21:42

>管理人様の負担を減らしつつ、各使用者ごとに好きな暗号化(速度重視とか安全性重視とか)できて良いのではと思いました。 負担激増してかつDxArchiveの存在意義を完全に殺してどうするんですか・・・ >オープンソースに安全性を担保してもらうというのはちょっと間違っているかなと思います。 これまたおかしな話で、じゃあopenssl/libresslはなんなんだと。
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.27 )
名前:8127 日時:2018/08/05 00:22

何か紛糾していますが、 私としては、DXアーカイブの存在意義は以下にあると思っています。 ・生ファイルか.dxaかによらずLoadGraph()等でアクセスできること 自前で暗号化する場合、一度メモリに読み込んで変換する必要がありますが、 一旦復号後のファイルを書き出してLoadGraph()するというダサい方法を取るか、 メモリからハンドルを得るための別の関数を使うかしかありません。 前者は遅いですし、後者は暗号化するせいでユーザーコードを破壊的に変更する必要があります。 ・技術が全くない人でも最低限度の安全性を担保できること 苦労すれば展開できるので暗号化機能自体が要らないという人がいますが、私は必要と考えます。 また、ライセンスを購入して使用する有料ゲーム素材の中には(無断二次利用防止のため) 暗号化必須で使ってくださいというものがあるので、暗号化機能が無くなったりするととても困ります。
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.28 )
名前:コーラ 日時:2018/08/05 00:43

> 一旦復号後のファイルを書き出して DXArchiveSetMemImage()という関数があるのでファイルに書き出す必要はないです。 1) .dxaファイルを自前で暗号化したファイルを作っておく 2) アプリ起動時に暗号化した.dxaを複合しメモリに展開 3) メモリに展開した.dxaをDXArchiveSetMemImage()で設定 > ・技術が全くない人でも最低限度の安全性を担保できること 程度の問題で現状のXORのやり方でも最低限度の安全性は担保していると言えなくはないと思います。
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.29 )
名前:8127 日時:2018/08/05 01:03

>コーラ 様 DXArchiveSetMemImage()ではメモリ効率が悪い場合があります。 data.dxaが小さいファイルをたくさん含み全部で1GBある場合(動画ファイルなどをたくさん含む場合あり得る数値だと思います)、 旧来の方法では小さいファイルにアクセスするごとに小さいファイルのみを復号化することとなりますが、 DXArchiveSetMemImage()では常にメモリを1GB占有することとなります。
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.30 )
名前:コーラ 日時:2018/08/05 01:13

.dxaファイルを分割して用途に応じてDXArchiveSetMemImage()とDXArchiveReleaseMemImage()を使えば良いのではないでしょうか?
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.31 )
名前:管理人 日時:2018/08/05 01:36

> ギウさん > 1)先に自前の暗号化ソフトでファイルを暗号化 > 2)dxaでそのファイルを圧縮 > 3)ゲーム側で、dxaから展開後に任意のコールバックを呼んでもらう こちらの方法ですとファイルを1byteだけ読みたい場合も必ずファイル全体を読み込まなければならないので、 サウンドファイルや動画ファイルのストリーミング再生で問題になりそうです… > コーラさん > オープンソースに安全性を担保してもらうというのはちょっと間違っているかなと思います。 > こういうのは程度の問題で結局いたちごっこになってしまうので > しっかり暗号化をかけたいという人には自前で暗号化をかけてもらって > 安全性の担保は利用者側で行ってもらうという扱いにした方が良いと思いました。 現在でも安全性に拘りのある方は独自ファイルフォーマットで独自暗号化されていますので、 DXアーカイブはそこまでされない方が使用されるにあたって、せめてソフト毎に解析しなければ ならない程度にしたいなと思っています( 現在はソフトを解析するまでも無く dxaファイル単体で解読できてしまうので ) > あと、暗号化の仕組みを変えてしまうと過去のバージョンとの互換がなくなってしまうと思うので > DXアーカイブとDXライブラリのバージョン管理が面倒になるのかなと思いました。 yumetodoさんも仰られていますがDXアーカイブは以前のバージョンのDXアーカイブも読み込める形で 新しい仕様を組み込むので、今回の変更を行った場合も以前のバージョンのDXアーカイブも読み込めるようにします > yumetodoさん > 安定しています。C++の言語仕様に破壊的変更が入るとも思えません(C++は破壊的変更に極めて慎重なので)。 > (constexpr自体はC++20で動的メモリ確保ができそうな勢いではあるけど本件に影響しない) > #if使っているのはDxLibがサポートしているコンパイラーのすべてで動くようにし、かつ可能な限りconstexprが有効になるようにしているためです。 失礼しました、以前はよく先端機能については『Microsoft独自仕様』だったり、『Gnu C は正式な仕様にきちんと対応 しているけど、VisualC++ は中途半端な対応となっているために #if で記述を分岐する必要がある』 ということが多かったので、本件の #if もそれが原因かと勘違いしてしまいました m(_ _;m
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.32 )
名前:ギウ 日時:2018/08/05 10:44

>こちらの方法ですとファイルを1byteだけ読みたい場合も必ずファイル全体を読み込まなければならないので、 その場合は位置とサイズをコールバックで渡すとか(使用者はそれを踏まえて暗号化する必要がありますが)。 ただ、「せめてソフト毎に解析しなければならない程度にしたいなと思っています」 という方針とのことで了解です!
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.33 )
名前:yumetodo 日時:2018/08/05 13:58

> 本件の #if もそれが原因かと勘違いしてしまいました m(_ _;m いえいえ、まれによくある行き違いですw 採用されるかどうかは気にしてないですが安定してないと言われるのは違うなというだけのお話でした。 > その場合は位置とサイズをコールバックで渡すとか(使用者はそれを踏まえて暗号化する必要がありますが)。 そこまでしたいならいっそ7zあたりを組み込めばいいんじゃないかと
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.34 )
名前:ギウ 日時:2018/08/05 19:29

>そこまでしたいならいっそ7zあたりを組み込めばいいんじゃないかと 最初に書きましたが私はdxaを使っていません。 勘違いな書き込みをしてしまったようで申し訳ないです。
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.35 )
名前:管理人 日時:2018/08/12 02:13

お待たせしました、DXアーカイブを SHA-256 を使用して暗号化するバージョン( Ver1.07 )ができました ( Ver1.06 など以前のバージョンのDXアーカイブファイルも今まで通り使えます ) 手元で試した限りでは正常に動作しましたので、よろしければお試しください m(_ _;m // 新しい DxaEncode.exe など https://dxlib.xsrv.jp/temp/DXArchive_1_07.zip // ライブラリファイル https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.2 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM.zip // Android版 ARM用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x86.zip // Android版 x86用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい) あと、SHA-256 のハッシュ値を得る関数は以下の通りです // バイナリデータを元に SHA-256 のハッシュ値を計算する( DestBuffer の示すアドレスを先頭に 32byte ハッシュ値が書き込まれます ) void HashSha256( const void *SrcData, size_t SrcDataSize, void *DestBuffer ) ; よろしければお試しください m(_ _)m
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.36 )
名前:8127 日時:2018/08/13 00:53

管理人さま、 ご対応ありがとうございます。 私の方で確認しましたところ、新アーカイブでFileRead_findFirstを呼ぶと不正アクセスで終了してしまいます。 次のプログラムは旧アーカイブでは問題なく動きますが新アーカイブでは動きません。 (data\\a.txtの存在に関係なく落ちる、圧縮PWなし) #include "DxLib.h" namespace { constexpr int windowWidth = 640; constexpr int windowHeight = 480; } bool dxlibInit() { ChangeWindowMode(TRUE); //ウインドウモードにする SetWindowSize(windowWidth, windowHeight); // DXライブラリ初期化処理 if (DxLib_Init() == -1) { return false; } SetDrawScreen(DX_SCREEN_BACK); //描画先を裏画面に設定 return true; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { if (!dxlibInit()) { // エラーが起きたら直ちに終了 return 1; } FILEINFO file; const int handle = FileRead_findFirst("data\\a.txt", &file); if (handle == -1) { printfDx("失敗"); } else { printfDx("サイズ%lld", file.Size); } ScreenFlip(); WaitKey(); DxLib_End(); return 0; }
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.37 )
名前:管理人 日時:2018/08/14 01:50

すみません、テスト不足でした、x86ビルドでは正常に動作しないバグがありました orz ( x64環境でしかテストしていなかった ) 修正版をアップしましたので、お手数で申し訳ありませんが、よろしければ再度ダウンロードしてください m(_ _;m https://dxlib.xsrv.jp/temp/DxLibVCTest.zip // Windows版 VisualC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCCTest.zip // Windows版 BorlandC++ 用 https://dxlib.xsrv.jp/temp/DxLibBCC2Test.zip // Windows版 C++ Builder 10.2 用 https://dxlib.xsrv.jp/temp/DxLibGCC_MinGWTest.zip // Windows版 MinGW 用 https://dxlib.xsrv.jp/temp/DxLibDotNet.zip // Windows版 .NET用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_ARM.zip // Android版 ARM用 https://dxlib.xsrv.jp/temp/DxLibAndroidTest_x86.zip // Android版 x86用 https://dxlib.xsrv.jp/temp/DxLibMakeTest.zip // ソース (中身を既存のライブラリのファイルに上書きして、BCCをお使いの 場合は『再構築』を、VCをお使いの場合は『リビルド』を、 Dev-C++をお使いの方は「Rebuild All(Ctrl+F11)」をして下さい)
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.38 )
名前:8127(解決) 日時:2018/08/14 12:37

管理人さま、 こちらの環境でも正常動作することを確認しました。 この度は長々と対応してくださってありがとうございました。 仕様を議論してくださったみなさまにもお礼申し上げます。 (私の暗号理論への理解の浅さが露呈したのでもっと勉強します)
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.39 )
名前:yumetodo 日時:2018/08/20 22:07

ミニテクの方は説明が追加されたようですが、SetDXArchiveKeyStringの方にも説明が必要じゃないかと思われます。
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.40 )
名前:8127 日時:2018/08/20 22:18

私からも一つ、(No18の投稿でも言いましたが)この文章もミニテクに追加していただけますか。 「以前のアーカイブからはパスワードが逆算される可能性が高いので、新しいアーカイブを使う場合は、以前と暗号化パスワードを変えてください。」
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.41 )
名前:管理人 日時:2018/08/21 00:42

ご指摘ありがとうございます SetDXArchiveKeyString の解説とミニテクコーナーに以前のバージョンでの パスワード逆算についての記述を追加しました m(_ _)m <アーカイブ機能を使ってファイルを一つに纏める> https://dxlib.xsrv.jp/dxtec.html#T11 <SetDXArchiveKeyString> https://dxlib.xsrv.jp/function/dxfunc_other.html#R15N32 あと、以前のバージョンでのパスワードが逆算されることについて『脆弱性』と表現していましたが、 『脆弱性』は多くの場合セキュリティホールによってPCがハッキングされたりする危険性があることについて 使われる表現なので、『解析によってパスワードが分かってしまう問題』といった表現に変更しました
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.42 )
名前:8127(解決) 日時:2018/08/22 15:41

管理人さま、ありがとうございます。 >あと、以前のバージョンでのパスワードが逆算されることについて『脆弱性』と表現していましたが、 >『脆弱性』は多くの場合セキュリティホールによってPCがハッキングされたりする危険性があることについて >使われる表現なので、『解析によってパスワードが分かってしまう問題』といった表現に変更しました その通りです。いいと思います。
メンテ
Re: DXアーカイブの脆弱性と改善提案 ( No.43 )
名前:yumetodo 日時:2018/12/09 01:58

DxLib Advent Calendar 2018 9日目の記事としてまとめさせていただいたので報告までに。 DxLibのDxArchiveの暗号化する機能とExport Administration Regulations 輸出管理規則 ttps://qiita.com/yumetodo/items/89af53d3cf8bc236de2f
メンテ

Page: 1 | 2 | 3 |

題名
名前
コメント
パスワード (記事メンテ時に使用)

   クッキー保存