電卓の16進から10進へ

C#で文字列をバイナリサーチする


前提として、僕のケースでは、『アタッシェケース#3』にて、ファイル先頭から固定値である「_AttacheCaseData」(16バイト)を検索していきます。それにより、自己実行形式ファイルのデータ境界が分かるようになります。

ウェブを検索してみたら、以下のサイトが近い感じがするのですが、

バイナリデータを検索する方法(vb.net)
http://www.my-hobby.jp/index.php/2012/01/vb-net2/

File.ReadAllBytes()で、一気にファイルをバイト単位での読み込みを行っています。僕のアタッシェケース#3では、出力されるファイルが、2GBを余裕で超えてくるファイルも扱う可能性もあるので、それは使えません。

そこで、File.ReadByte()を使います。知ってましたか、ReadByte();

ReadByte()は、ストリームから1バイトずつ読み込んで行きます。ただし、返値がバイトではなく、Int32 にキャストされた符号なしバイト(int)で返ってくるのに要注意。

あらかじめ分かっている定数ならば、僕のようにint配列にしますが、場合によっては、byte値をその度にintにキャストして比較しても良いでしょう。

電卓の16進から10進へ

ちなみにbyte値をintにするには、Windowsの電卓を「プログラマ」にして「16進」→数値入力→「10進」にして、値を出しました。16進を10進に脳内変換で出来ちゃうプログラマーさんはすごいと思う(常識デスカ?)。

「アタッシェケース#3」をリリースしました


「アタッシェケース#3」のβテスト版をリリースしました。ようするにアタッシェケースの「Version.3」へのメジャーバージョンアップです。

アタッシェケース#3アイコンhttps://hibara.org/software/attachecase/   

僕が好んで使っていた統合開発環境「C++Builder」の価格高騰に伴いバージョンアップを諦め、無料で使える、Microsoftの「Microsoft Visual Studio Express 2015 for Windows Desktop」に乗り換えて、開発しました。言語は、C#ですので、ほぼフルスクラッチでの開発でした。

2004/07/25 に『ver.2』がリリースされてから、ここまで少しずつ改良を重ねてきましたが、 それはほとんどが本体側だけで、そこから生成される暗号化データの形式は、互換性を保つため、 ほぼ当時のままの設計で来ていました。

あれから年月が経つにつれて、当時の僕の拙いプログラミングから、パスワードの扱い方にやや弱い部分があることや、 暗号化するバッファの一部がとても小さく、暗号化・復号処理に時間がかかっていたことなどが分かって来ました。

また、データに格納するファイル情報が冗長になり、不要なもの、次第に使われなくなったものが多くなってきました。 そこで今回のメジャーバージョンをキッカケにして、データの仕様も全面的に見直し、再設計を行いました。 その結果、Ver.3 は、Ver.2よりも暗号強度の高いファイルを生成します。

そのため、暗号化ファイルは上位互換です。Ver.3で暗号化したファイルは、ver.2では開くことはできません。ただし、Ver.3では、Ver.2のファイルは開くことができます。

ソースコードは、GPLv3ライセンスとして、GitHubにもアップロードされています。ご興味のある方はぜひご覧いただき、フィードバックや改良案などいただけると嬉しいです(ただし、簡単な質問はググってね♥)。

また今回から、Windows 10にも正式対応しました。一応、タッチパネルを意識した作りをしたつもりですが、細かいところではどうでしょうか。タッチパネルを頻繁に使われる方で、この辺りの挙動でご不便なところがあれば、ご意見いただきたいです。

DotNetZipでEncryptionAlgorithm.WinZipAes256が選択できない


Visual Studio C#で『アタッシェケース』の新版を開発中です。その中で、パスワードZIPファイルを作成するために、DotNetZipというライブラリを使っています。

DotNetZip-Logo

ところが、以下のコードのように設定しても、コンパイルエラーとなります。

Visual Studioのインテリセンスを表示させてみても、
None
PkzipWeak
Unsupported
と、肝心の「AES」が出てきません。おかしいなあ、とDotNetZipのソースを見てみたら、defineで切られているではありませんか。

AESはdefineで切られている

おそらくパスワード付きZIPのAESは、アーカイバによって解凍できなかったりするので、こういう扱いなのでしょうか。実際、DotNetZipヘルプの「EncryptionAlgorithm 列挙体」には、こう書かれていました。

Values of WinZipAes128 and WinZipAes256 are not part of the Zip specification, but rather imply the use of a vendor-specific extension from WinZip. If you want to produce interoperable Zip archives, do not use these values. For example, if you produce a zip archive using WinZipAes256, you will be able to open it in Windows Explorer on Windows XP and Vista, but you will not be able to extract entries; trying this will lead to an “unspecified error”. For this reason, some people have said that a zip archive that uses WinZip’s AES encryption is not actually a zip archive at all. A zip archive produced this way will be readable with the WinZip tool (Version 11 and beyond).

WinZipAes128 値と WinZipAes256 値は zip 仕様に含まれていませんが、WinZip のベンダー固有の拡張を使用することを意味しています。相互運用可能な Zip アーカイブを生成するには、これらの値を使用しないでください。たとえば、WinZipAes256 を使用して zip アーカイブを生成する場合、Windows XP および Vista で Windows Explorer で開くことができますが、エントリーを解凍することはできません。解凍しようとすると、「未定義のエラー」となります。このため、WinZip の AES 暗号化を使用した zip アーカイブは、実際にはまったく zip アーカイブでないと言う人もいます。この方法で生成された zip アーカイブは、WinZip ツール (バージョン 11 以降) で読み込むことができます。

ですので、AESをどうしても使いたい場合は、Visual Studioの「条件付きコンパイルシンボル」に「AESCRYPTO」を追加します。

プロジェクトのプロパティを開く

プロジェクトのプロパティを開いて、

条件付きコンパイルシンボル

追加すると、コンパイルも通り、インテリセンスにも「WinZipAes128」「WinZipAes256」の値が表示されるようになります。

JavaScriptでiOSアプリ、Androidアプリを作る環境は今はだいぶ整っている


しばらくJavaScriptでの仕事が続いていたので、じゃあ鉄は熱いうちに打つかと、作りたかったスマホゲームアプリをプライベートで、しかもJavaScript開発で一気呵成に作ってしまおうと思い立ちました。

そのゲームは以下に。もしお気に召していただけたのなら、お布施代わりに課金していただけるとうれしいです(フルバージョンになるだけの一回課金です)。

tamasabo

過去にも何度かJavaScriptでアプリ開発をやろうとして失敗したんですよね。

JavaScript開発でネイティブアプリにするフレームワークは、PhoneGapを初めとして、当時いくつか選択肢はありましたが、そのときは、どれもイマイチでした(できることが少なく、難度が高いという意味で)。

しかし、今回もCordva(PhoneGap)を使いましたが、当時とは状況がガラリと大きく変わっていたようです。

JavaScriptだけですべてを表現できるわけではない

「JavaScriptさえ書ければ、何でも表現できる!」と鼻息荒く始めるのですが、実際ハードウェアや、ネイティブ部分の壁にぶち当たると、もはやほとんど無力です。

今回でいえば、

  • アプリ内課金
  • アプリ内広告
  • ソーシャルシェア

です。中でもアプリ内課金では、iOS内のStoreKit(ネイティブ)を操作してiTunesサーバまで問い合わせるなんて、想像しただけでも、JavaScriptだけでは100%不可能。

「ああ、、、やっぱりムリだよなあ」と思って調べてたら、現在ではCordovaのプラグインが山ほどあって、アプリ内課金だけでも二つ三つ見つかる状況です。以下、今回のゲームアプリで使ったプラグインです。

アプリ課金
https://github.com/AlexDisler/cordova-plugin-inapppurchase

アプリ内広告
https://apps.admob.com
プラグイン
https://github.com/appfeel/admob-google-cordova

ソーシャルシェア
https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin

いずれもMITライセンスという素晴らしさ(たしかにGPLだとApple審査で弾かれますもんね。当たり前と言えば当たり前なのですが)。

PhpStormの万能感

phpstorm

まさか、JavaScriptによるスマホアプリ開発で、PhpStormが使えるとは思ってもみませんでした。

「PHPですよね?・・・」と知人から指摘を受けたとき、
「な、何を言ってるのか、わからねーと思うが・・・」

と、脳内ポルナレフ状態でした。たしかにPHP含めたサーバサイド開発環境じゃないのかよ、と思われますが、JavaScriptも扱うので、つまりは、iOS, Androidの統合開発環境としても使えます。

設定はとっても簡単。Cordovaのプロジェクトを作ったら、上部メニューにある「Select Run/Debug Configuration」を開きます。

select-run-and-debug

あとは、左ペインにある「PhoneGap/Cordova」を選択するだけです。

select-cordova

iOSの場合

ios-emulate

PhpStorm上で「実行」をすると、iOSの場合は、エミュレータが起動します。

別のプラグインを使えば、実機転送まで行けるそうですが、これだけでも充分すぎるくらいのデバッグ環境です。

Androidの場合

android-run

Androidの場合は、adbサーバが起動した状態で、Android端末がUSB接続されていれば、自動的に表示され、選択状態となります。

これでPhpStorm上の「実行」で、アプリはAndroid端末に転送され、デバッグできる状態になります。

一人でやっている人はすごい

以前はチームとして開発していたことがあるのですが、こうしてすべての工程を一人でこなすことになるとは思いも寄りませんでした。

今回は音関係以外、グラフィックやプログラミングは一人でやりましたが、なんと言っても大変だったのは、課金部分のデバッグでしょうか。一回だけでも課金が成功してしまえば、そのAppleアカウントはもうテストで使えなくなるからです。果たしていくつのAppleIDを作ったのやら・・・

あとは、それだけじゃないんですね。

リリースまで行くには、いろいろやるべきことがある。

プライバシーポリシーの作成(英語版も出す場合は、英語版も!)と、それを外部に置くための場所、ランディングページ(https://tamasabo.jp/)の作成をしなくてはならない。

App Storeに置くスクリーンショット画像の作成。解像度がiPhone、iPad含めて大量にあるので、地味に用意するのがたいへんだったり。

Appleの審査でのやり取りは依然として英語ですし、時差の関係か夜中の1時頃に、質問が飛んできたりします。

たいしたアプリではないので、さほど多くもないでしょうが、今後は開発者アカウントが存続するかぎり、サポートも続けていかないと、いけないのだろうなあ、と思っているところです。

JavaScriptでCryptoJSを使って、AESの暗号化と復号を行う


ウェブサイトを見回してみても、正しく実装されていなかったり、良いサンプルが無かったので、記事にしてみました。

→ DEMO&ソースコード:https://jsfiddle.net/hibara/qzono8jb/

CryptJSについては、以下にあります。
https://code.google.com/archive/p/crypto-js/

暗号化するにあたって

CryptJSの本題に入る前に、少し暗号化についてのお作法を知っておく必要があります。詳細は僕が書いた、別記事の「Visual Studio C#でファイルを暗号化してみる」を参照していただきたいですが、一応ざっとおさらい。

暗号化モードではCBCモードを使うのがベター

ブロック暗号方式と呼ばれるものは、その名のとおり、何バイトかずつブロック単位で暗号化していきますが、ここでやりがちなのがECBモードでしょうか。

ECBモード

これの何が問題かといえば、毎回同じデータ、同じパスワードだと、毎回同じ内容の暗号化データがでてきしまうという点です。

あるいは、各ブロックが小さくなるので、暗号化データへの総当たり攻撃(ブルート・フォースアタック)がしやすくなります。

基本的には、CBCモードを使いましょう。

CBCモード/暗号化

冒頭に、乱数による初期化ベクトル(Initialization Vector)を与えて、各暗号化ブロックに捻り合わせて行くイメージでしょうか。

CBCモード/復号する

ちなみに、暗号の大家であるブルース・シュナイアー氏がその著書『暗号技術大全』(日本語訳版は絶版・・・)の中でも、

ファイルを暗号化するのであれば、CBCモードがベストだろう。このモードを使えば、セキュリティは大きく向上するし、保存したデータに多少エラーが発生しても、同期エラーが発生することはまずない。アプリケーションが(ハードウェアではなく)ソフトウェアベースであれば、CBCがほぼ確実にいちばんいい。

と書いています。

パディングモード

ブロック暗号方式では、何バイトかのブロック単位で暗号化することにより、場合によっては、「端数」が出てしまいます。

これは暗号化されると、どこまでが暗号化データだったのか、復号時に正しく判別ができなくなくなるということです。

パディングモードでよく使われるのは、PKCS7のパディングモードでしょうか。

たとえば、以下の例ですと、データ長が8バイトで、実際のデータ列が9バイトあれば、残りの7バイトは、以下のように埋められます。

PKCS7パディングモード

つまり「余り」に埋められた合計サイズが、数値として埋められるというわけです。
これにより、復号時に、データ境界線をプログラムで判別できるようになります。

CryptoJSにはすべて揃っている

ところが、いざ、CBCモードで、PKCS7のパディングモードで暗号化したいと、該当のソースファイルを当たったら、どこにも見当たらない。「おかしい」と思って、本家のページを当たってみたところ、いずれも「Default」であるということが判明。

ユーザーが万一、なにも設定せずに使ってしまっても、黙ってCBCモードでPKCS7パディングモードで暗号化されるという親切設計でした(笑)。

CryptoJS supports the following modes:

CBC (the default)
CFB
CTR
OFB
ECB
And CryptoJS supports the following padding schemes:

Pkcs7 (the default)
Iso97971
AnsiX923
Iso10126
ZeroPadding
NoPadding

暗号化キーは鍵空間を広く使う

これは暗号化ユーティリティを使うすべてのユーザーにも言えることですが、パスワードはなるべく長い文字列で使ってほしいところです。当然、総当たり攻撃がしやすいという問題があるからです。

とはいえ、ユーザビリティを強制するのも、ツールの自由度を下げます。ただ、開発者側もそういった問題に少なからずフォローすることはできます。

たとえば、一文字のみパスワードを入れられても、鍵空間を目一杯使って、毎回異なるパスワードキーを生成してあげれば、多少この問題を和らげることができます(ただし、ブルートフォースアタックのような攻撃には何の訳にも立ちません)。

鍵空間

本題の「CryptoJS」

さて、本題の「CryptoJS」ですが、Google Code Archiveに上がっている、ライブラリです。そのサイトには、こう書かれています。

CryptoJS is a growing collection of standard and secure cryptographic algorithms implemented in JavaScript using best practices and patterns. They are fast, and they have a consistent and simple interface.

CryptoJSは、ベストプラクティス、ベストな形で、JavaScriptにおいての安全な暗号アルゴリズム標準となるべく開発しているものの一つです。これらは高速であり、一貫性とシンプルなインターフェイスを提供しています。

実際、オープンソースで、CDNやGitHubにも上がっています。

使い方は、たしかに簡単で、実際に使いたいjsファイルをhtmlヘッダ内で定義するだけです。

CryptoJSのAESを使ってみる

通常なら、「aes.js」だけで行けますが、今回は鍵空間を広げるためのライブラリを使うので、「pbkdf2.js」を含めました。

CryptoJS を使う上での注意点は、やはり「バイナリ」の扱いでしょうか。

おそらくウェブ上(サーバ間)でのデータのやりとりも考慮されているのか、データをバイナリデータ(Hex = 16進文字列)や、Base64エンコーディングして渡す場面が何度かあります。

ただ、CryptoJS では、それらを適宜、必要なデータへコンバートするためのメソッドも用意されています。

CryptoJS.enc.Hex.parse()
CryptoJS.enc.Base64.parse()
CryptoJS.enc.Utf8.parse()

などを駆使して暗号化します。

まずは、暗号化から。この程度のソースコードにjQueryを使っているのはご容赦ください。

暗号化の際の注意点としては、暗号に必要なsaltやIVなどを、暗号化データに含めないといけない点です。

ここでは単に、カンマ区切りとしていますが、他に方法があるのなら、どのような手段でも良いでしょう。

そして、復号はこちら。

以上です。

実際のデモは、先にも書きましたが、
https://jsfiddle.net/hibara/qzono8jb/

で、見られます。

s