FC2ブログ


VS2017-はじめの1/10歩(18):暗号化処理を取り込む

   プログラミング [2019/09/16]
「くりぷと」って聞いて・・・「元素にそんな名前のがあったよーな」と思ってしまうさるです。

Windows10タブレット向けのアプリを作ろうとしています。
VS2017を使うんだけど慣れてないからVS6でまずは作ってました。言わばWin32アプリです。
両方の環境(クロス環境)でコンパイルできるソースとして書いてます。
これまでの書き込みも含めると、

→ナレーション再生と音声認識を使う
  →そのため音声データの作り方(多言語対応)
  →ナレーション(.WAV)再生のサンプルコード
  →音声認識のサンプルコード
→VS6で作ったC/C++コードをVS2017に持って行って.cppレベルで共通にする方法
→ダイアログベースのプログラム
  →背景に画像(.BMP)を使う
  →ラベルを透かす
  →ボタンの色を変える
  →Windowsタブレット上でピンチイン/アウト:拡大縮小
  →タブレット画面の回転への対応
  →カスタムなチェックボックス作成
  →ボタンに画像を貼付ける
  →スクロールとスワイプ
→HTTPでファイルを送受信する
  →手法1:ブラウザ使って
  →手法2:Wininetを使う
暗号化処理を取り込む←今回

となってます。

世の中、データの暗号化は当たり前に使われる時代なんですよね。
ほぼ、そんなこと気にせず通信環境で動くアプリやサービスを使ってるけど。

例えば、LAN環境で使用するローカルなDBサーバシステムがあったとします。
そのサーバシステムに対して、LAN環境外でデータの更新がしたくなったとします。

つまり、持ち歩きのPCで加工したい部分を予め取り出して、どっか別の場所で加工して、戻す仕掛け。
そうすれば、DBとのデータの出し入れだけLAN環境のエリアで行えば、そのデータの加工はどこでへ行ってもできる。

「そんなの公衆回線を使ってDBアクセス環境を作っちゃえばいいじゃん。」と思われるでしょう。
今はほとんど通信料は定額だし、WiFi環境もそこいらに・・・・
ないんです。
さるの棲む田舎では、WiFiスポットを探すどころか、電波が届かないところも未だにざらにあるのですよ。

ちなみに、さるの実家でのポケットWiFiの可否としては
・Do*omo △ :スンゲー遅い。3G<->4G行ったり来たり。
・A*     × :通じません
・Softb* 不明:カバー域マップで見るとつながることになってる。

そんなところで外回りされる方のためには、データの部分的持ち歩きはあってもいい機能ではないかと。
定額と謂えども、その分の通信コストも削減できるはず。

ただし、ローカルなデータを持ち出すのだから、端末を落としたら大変です。
しかも今のところ持ち歩きデバイスはWindowsタブレットだし。
なのでファイル自体は「暗号化しておこう」と思ったのが、事の始まりです。

いつもながら、前置き長くてすいません。

そんなこんなで、「暗号化」についてちょっとだけ勉強することになった。

暗号化方式も色々あるらしが、「AES」というのがよさげらしい。

調べているうちに、「ローカル環境内の通信で、タブレットからDBアクセス時にハッキングされたら?」と思ってしまった。
(ローカルな環境でしかやれないことだし、そんなに心配するほどでもないのだけど。)

-ユーザ認証は必要でしょう。
-ってことは、ID/パスワードをサーバ側スクリプトに送り込むよな。
-裸で?
-せめてパスワードは分からないようにしようよ。
-どんなのがある?
-「PBKDF2」※という単語が出てきた。
-じゃそれ使って見よう。
-当然、データもダウンロード段階で暗号化。
-保存もそのままで、参照・編集時に復号ね。

と思ったのがウンのツキ。
この時点で「暗号化」についての知識はゼロです。
使われている言葉すら分かりません。

調べ始めたんだけど、色んな説明してくれてるサイトはあるんだけど、
Windows、VCで絞ると、割と無かった印象。
なので、結構時間が掛かりました。

それで・・・・


◆PBKDF2
まずは、「サーバアプリに使用許可を求めるときに送信する(アカウント&)パスワードを分からないようにするのに使うのかな~」くらいの認識で使ってみることに。

Windowsでサポートされているかどうか調べたら、
「Cryptographic Provider Development Kit」というのが引っかかった。
中身は、BCryptXxxxx等のAPI。
BCryptDeriveKeyPBKDF2という関数もある。
割とすんなに行けそうか?
とおもって、ちゃちゃと数十行のコードを書いてVS6上でコンパイルしてみた。

PlatForm SDKは、Windows7用までは、インストールしてあったが、そのヘッダ内でエラー。
BCryptXxxxxの説明を見ると、Windows7以降でサポートと書いてある。
ってことは、たぶんVS6だとダメってことなんじゃないかしら。
『まあ、今後使うものとして、VS6環境はもう「なし」でいいんじゃないの?』とも思いましたが。
ここまで「VS6&VS2017で共通のソースコード」でやってきたので途中であきらめるのはちょっとくやしい。

モトイでもう一回調べ直して「DPAPI」「Cryptography Functions」というキーワード。
CryptXxxxxみたいなAPIがある。
「B」が付いてないから、以前のライブラリなのかと思う。
WindowsXP以降使えるような書き方。
「なら、PBKDF2は?」・・・
ない。「これを呼べばできますI/F」がない!
さんざん探しまくりましたが、ビット列をPBKDF2でハッシュ化するための数件のサンプルコードに行き当たった。

その内の以下
http://www.idrix.fr/Root/Samples/pbkdf2.cpp

上記サイトの会社のHP上から、利用規約というか権利主張的な記述がないか見たが、どうも「ご自由に」「保証はしませんよ」な位置付けらしい。
ありがたく参考に・・・使わせてもらうことに。

量は多くないし、先のDPAPIを前提にしている。
だけど、・・・さるには難しいコードだった。
検討段階で、「PBKDF2」※という言葉を最初に見つけた「説明してくれてるサイト」で、サンプルとして使っていたのは、どうもこのコードっぽい。
むちゃくちゃ、遠回りした。

早速、.cppをベンチマークテストコードを除いて、テストプログラムにリンクして入れて見た。
動いたみたいな感じだった。
コードの処理の意味は分かりません。
とはいうものの、暗号化APIのリファレンスからのコメントは備忘のために入れた。

これは、ハッシュ化するだけなので、一方通行の変換なんですね。
作り終わってから、「戻すのはどうすんの?」とか思ってしまったけど、
そもそもハッシュ化は、元のデータを分からない形に変換することをいうらしいのね。(^^;)

※ここで、心配が。
サーバアプリ側が受け取ったIDとパス(ハッシュ化されたデータ)で利用者リスト中にそんな人がいるかを判定すると仮定します。
ってことは、サーバアプリ(CGI)側では別の言語(PerlとかPHPとか)で使えるハッシュ化関数でPBKDF2して突合せを行うんだよな。
・・・答えが一致するといいんだけど。・・・サーバ自体をハッキングされて利用者リストを覗かれたら?・・・でもそれだったらDBを直接まさぐるよな。・・・危険度は一緒だよな。


◆Base64
例えば、サーバアプリに秘匿したいデータをハッシュ化して動作パラメタとして送る場合、ハッシュ化後のデータはバイナリなので、POST/GETする場合にはBase64変換するのが当たり前・・・なんですかね。
なのでBase64も必要です。
Cの標準関数的に普通に存在するのかと思いきや、ないのね。

サンプルを探しました。[2019/2現在]
http://yano.hatenadiary.jp/entry/20100908/1283945820
https://qiita.com/leak4mk0/items/6c7f708dd59d52e0bc5c
変換自体を自作してます。

https://blog.janjan.net/2018/10/25/vc-wincrypt-convert-base64/
http://www.lab.its55.com/?p=34
Base64もDPAPIでできるみたい。

上記サイトに掲載されていたコードを参考にさる風のコーディングに修正して見た。
参考サイトと同じようにBase64Enc/Dec 2つの関数を準備した。

動作確認用に、
送られてきたパス(PBKDF2ハッシュ値&Base64化)をPHPでBase64エンコードして、期待してたパスのPBKDF2ハッシュ値と一緒かどうか判定するコードサンプルは以下の感じでOKでした。
//-----------------------------------------
$my_pass = 'watashi';
$salt = 'shioshio';
$rotate = 220;

//****入力ハッシュ値をバイナリ化
$inhash = base64_decode($hash_word);
//****期待パス($my_pass)とハッシュ値が同一かを比較
$myhash = hash_pbkdf2 ("sha256", $my_pass, $salt, $rotate, 32, TRUE);
if ($myhash != $inhash) {
   //不一致
  }
//-----------------------------------------

※SALTとRotateの値は、予めクライアント側と合わせておく必要があります。
PHPだと至って短い。



◆AES
次に、AESです。
通信中はもちろん、ファイルとしてデータを端末に保存しているときは、暗号化された状態じゃないとねー。
(そんな大層な守秘義務のあるデータを持ち歩くことって・・・もしそうなら、正直言って持って歩かない方がいいと思う。)

「AES」の方は、2019/2時点で以下で解説してくれてました。
https://www.hiramine.com/programming/windows/encryptdecryptstring_aes128ecb.html

上記のサイトのコードを参考に、さる風のコーディングに修正して、コメントを付け足して。
固定の暗号化方式(AES-256-ECB PKCS5)を使った暗復号ルーチンを作ってみた。


◆さる的トリビア
本当はトラブルの話で、サーバアプリ側作成時に嵌ったはなし。

サーバ側でエンコード結果をクライアント側でデコード、または、その逆を実施して相互にデータを交換できるかどうかを試すためにPHPでサーバスクリプトを作った。

URL先の.phpにPOSTでアカウントとパスワード(PBKDF2ハッシュ)と機能番号を指定すると、決まったファイルをダウンロードかアップロードできるという仕掛け。
クライアント側は、上記したようなデータ変換を実施して、HTTP通信をする様なプログラムです。

やってみたら、
〇心配していたPBKDF2(hash_pbkdf2())は、あっさりクライアント側と同じ変換結果が出た。\(^o^)/
〇Base64は、まあね。大丈夫ですよ。
×AES・・・上手く復号できません。

openssl_encrypt/_decriptのパラメタが、きっとクライアント側の変換時と一致してないんでしょう。
※PHP版の上記APIのパラメタ指定の話しです。

最初、パラメタは、(変換元データ、変換方式(AES-XXXXとか)、変換キー)の3つだけ。
APIのスペック的には、+「オプション」、「iv」、「iv長」とあと3つ指定できる。

先に「iv」って何よ→initialization vectorの略で初期化ベクトル→だから初期化ベクトルって何!
たぶん、追加の暗号鍵みたいなもんですね。
ランダムな値を取るだとか書いてたので、相手にデータ渡したときの復号は?とかさらに心配になります。
→ivも一緒に渡すんですね、結局。

ivという言葉自体、クライアント側のCアプリを作ってる最中に出てこなかったので、多分指定は絶対してないはず。

残りは、「オプション」となってるフラグです。
指定できるのは、0か、OPENSSL_RAW_DATA と OPENSSL_ZERO_PADDINGの組合せ。
それぞれの単独のオプション機能の有り無しなのかと思いきや、ちょっと違うっぽいことが以下のサイトに書いてあった。
https://blog.shin1x1.com/entry/openssl-add-pkcs7-padding

要約すると
<ブロック暗号化の場合>
option指定Padding方式(paddingデータ)Base64変換
0(PKCS#7)0x01~0xffのいずれか
固定でパディングサイズを表す
OPENSSL_ZERO_PADDING0x00固定
OPENSSL_RAW_DATA(PKCS#7)
両方0x00固定

となります。
まあ、よく使う組合せをデフォルトにしたとは思いますが、分かり難い。
しかも、クライアント側では、パディングはPKCS#5と指定してました。(それしかないと書いてあった。)
・・・大丈夫なんだろうか。

結局、以下の内容で、クライアント側作成のAES-256-ECB(sha256/PKCS#5パディング)を復号できました。
//-----------------------------------------

define('CRYMETHOD', 'AES-256-ECB');
define('MY_KEYHASH', 'sha256');
define('CRYOPTION', OPENSSL_RAW_DATA);


$hashed_key = hash(MY_KEYHASH, $key_word, true); //出力はrawデータ。長さは32バイト
$decstream = openssl_decrypt($recv_data, CRYMETHOD, $hashed_key, CRYOPTION);
$crypt_err = openssl_error_string();
if ($decstream == false) goto exit_enc_xxxxx;

//-----------------------------------------


データをエンコードする場合は、
//-----------------------------------------

$hashed_key = hash(MY_KEYHASH, $key_word, true);
$encstream = openssl_encrypt($datstream, CRYMETHOD, $hashed_key, CRYOPTION);
$crypt_err = openssl_error_string();
if ($encstream == false) goto exit_enc_zzzzz;

//-----------------------------------------



クライアント側のCのサンプルコードはこちらからダウンロード可能です。
(フィッシングの懸念があるとブラウザが警告するかも。)


◆一段落
「VS2017-はじめの1/10歩」と題して長々と書いてきましたが、VisualStudio2017の使い方とかは、全部入ってませんでしたね。
「どこがVS2017なんだ!」とお怒りの向きもあったかと思いますが、VS2017の使い方に関しては他のサイトを参考にしてください。
そちらの方が詳しいしはずです。

さて、これまでの一連の説明は、「持ち歩きのWinタブレットにサーバからデータを一時的に引っ張ってきて、通信環境のない別の場所で編集する」ようなプログラムを想定したものです。しかも、時代遅れのWin32アプリ。

当然、サーバとのやり取りが前提なので、サーバ側のスクリプト環境も作り込む必要がありました。
このあと、何回かはその環境構築と動作評価でのすったもんだをまた備忘録しようかと思っています。ぼやきが多いです。
いままでよりもさらに参考にならない内容になるかと思います。
読む価値ないかと思います。悪しからず。

では、この辺で。
m(__)m



スポンサーサイト





コメントの投稿

非公開コメント

カレンダー
10 | 2019/11 | 12
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
プロフィール

さるもすなる

Author:さるもすなる
さるです。別HPサイト「さるもすなる」から侵食してきました。 山菜/きのこ、それとタイトルにしたPPバンド籠のことをメインに徒然に・・・・暇を持て余したさるの手仕事:男手芸のブログってことで。

最新記事
最新コメント
月別アーカイブ
カテゴリ
天気予報

-天気予報コム- -FC2-








本家のHPのトップ
山菜や茸の話です
PPバンドの籠作品と作り方です
投稿をお待ちしております



ブログランキング・にほんブログ村へ にほんブログ村 ハンドメイドブログへ



マニュアルのお申し込み



検索フォーム
リンク
RSSリンクの表示
ブロとも申請フォーム

この人とブロともになる

QRコード
QR