1 | 2 | 3 | 4 | 5 |最初 次ページ >>
2015年11月05日(木) 12時01分54秒

iPhoneアプリ開発 暗号 その2

テーマ:iPhoneアプリ開発ドリル
 というわけで、今回はMacのコマンドラインツールを作り、CCCryptを使い平文を暗号文にしてみます。
 使う暗号化アルゴリズムはアメリカ合衆国の新暗号規格AES
 なのでプロダクト名もAESにしましょう。

 Macのコマンドラインツール用プロジェクトの作り方がわからん人は、ちと古いけど「ブートキャンプ(3)Xcodeを使ったC言語の学習」あたりを参考にしてください。

 ちなみに、ブートキャンプ(1)で紹介している無料開発者登録は、もう必要ありません。
 今は登録無しで、AppStoreからXcodeをインストールできるようになってる。
 手順をビデオにしてみますた。
   ↓


人類の夜明けだ

 今回のコマンドラインツールで暗号化する平文は

const char* text = "Hello cipher\n";

 とします。
 ここでは平文らしく英語の文字列にしたけど、暗号化自体はバイト列ならなんでもよくて、テキスト、画像、音楽データにも適用できます。

 この平文を、キーを決めてAESアルゴリズムで暗号化するわけですな。
 AESのキー長は128、192、256ビットの長さを選べるようになっていて、長い方がより強力な暗号となります。今回はMAXの256ビット=32バイトのキーを用意することにしました。

int8_t key[] = {0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7};

  int8_tという型は1バイトを使った整数用の型で-128~127の値を記憶します。ぶっちゃけchar型と同じですが、キーは文字列にする必要はないので区別する意味でint8_tを指定しています。AESに指定するキーは必要なバイト長さえあれば画像データでもなんでもかまわない。
 今回は0~7の値を4回繰り返して32バイト分にしたので、16進表記だと

 0001020304050607000102030405060700010203040506070001020304050607

という256ビット長のキーを用意したことになる。
 ここまで準備できたら、暗号文を受け取るためのバッファを用意してCCCryptの呼び出しです。
 CCCryptを使うときは以下のヘッダーをインクルードするように。

 #include <CommonCrypto/CommonCrypto.h>

 でもって、作成された暗号文を受け取るために用意するバッファの大きさですが、AESの場合、暗号化は128ビット=16バイトのブロック単位でおこないます。

1

 なので、暗号文用のバッファのバイト長は、平文側のバイト長ではなく、それより大きく、かつ16バイト境界で区切られた大きさ、またはそれ以上が必要となります。
 というわけで、次の計算で、平文に対して、AES暗号化で必要となる暗号文受け取り用バッファが必要とするバイト数は計算できる。

必要となる暗号文のバイト数 = (平文のバイト数 + 15) / 16 * 16

 ぶっちゃけ、それ以上なら問題ないです。なので今回は平文が短いので暗号文用バッファは100バイトと適当に確保しました。

size_t cipher[100];

 これでCCCryptを呼び出します。

暗号化
size_t numBytesEncrypted; 暗号文のバイト数が設定される
CCCryptorStatus cryptStatus = CCCrypt(
kCCEncrypt, 暗号化
kCCAlgorithmAES, AES使用
kCCOptionPKCS7Padding
AESは128ビットごとのブロックで暗号化する。
そのため平文が、128ビット境界にぴったり収まらないなら
後ろに詰め物をして128ビット境界にする必要がある。
その詰め方としてPKCS7を指定した

| kCCOptionECBMode,
ECBは圧縮方法のオプション。
暗号強度は少し落ちるが初期化ベクタを必要としないので指定

key, 32, キーとキーの大きさをバイト単位で指定(32=256ビット)
NULL, ECBを指定したので不要。NULLを指定
text, strlen(text), 平文と、その大きさをバイト単位で指定
cipher, 100, 暗号文を入れてもらうバッファと
その大きさをバイト単位で指定

&numBytesEncrypted); 暗号文の大きさをバイト単位で受け取る


 第1引数が、平文を暗号文にする指定です。CCCryptは暗号文を平文に戻すときにも使い

kCCEncrypt 平文→暗号文
kCCDecrypt 暗号文→平文

となっています。

 第2引数が暗号化アルゴリズム、今回はAESを使うので

kCCAlgorithmAES

を指定。

 第3引数が暗号化アルゴリズム別のオプション指定。
 AESの場合、128ビット単位での暗号化になるので、平文が128ビット境界にぴったり収まらないなら後ろに詰め物をして128ビット境界にする必要がある。で、その詰め物の設定方法としてPKCS7を使えって指示が

kCCOptionPKCS7Padding

です。で、もう一つの

kCCOptionECBMode

は、AESの動作モードの指定で、128ビットのブロックごとに、前のブロックの情報を合成するかどうかの指定。
 合成すると暗号化されたバイト列のばらつきがより上がるんだけど、その場合、初期化ベクタという、最初の128ビットブロックに適用する値(128ビット=16バイト分)が必要になるので、ここでは、それを使わないように合成しないモードを指定しています。これを指定しないとCCCryptではCBCモードという前のブロックの情報を合成するモードが適用されます。

 第4、第5引数はキーの指定。第4がキーの先頭番地、第5引数がキーのバイト長。

key, 32


 第6引数が初期化ベクトル。ECBモードを指定したんで必要ありません。なので

NULL


 第7、第8引数は平文→暗号文指定なんで平文のバッファ情報をわたします。第7に平文の先頭番地、第8引数にそのバイト長を渡します。

text, strlen(text)


 第9、第10引数が平文→暗号文指定なんで暗号文のバッファ情報をわたします。第9に暗号文の先頭番地、第10引数にそのバイト長を渡します。
 このさい第10引数には、平文のバイト長以上で128ビット境界となるバイト長以上の値を渡さないとエラーになるんで注意。

cipher, 100


 最後は、実際に暗号文化されたバイト長を受け取るための変数の番地をわたす。

&numBytesEncrypted


 これでcipherに暗号文が入る。
 できあがった暗号文をCCCryptで平文に戻すのは簡単だけど、それじゃあ、ちゃんと他のアプリで平文に戻せるかの確認にはならない。
 なので、暗号文をファイルにしてみます。
 そのため暗号文のcipherをfwriteでstderrに書き出すようにしてます。

fwrite(cipher, sizeof(int8_t), numBytesEncrypted, stderr);

 これで、このAESをビルドして作成されたAESのディレクトリをターミナルでカレントにして

./AES 2>hello.enc

とすれば暗号文をhello.encというファイルにできる。fopenでちゃんとファイルに書き出してもいいけど手抜き。

 ↓ 実際のサンプルはここ
https://github.com/Takahiro-Kunii/AES

 あとは、書き出したファイルを、そのままターミナル上でopensslを使って平文に戻してみる。
 opensslは指定した暗号化アルゴリズムで、平文を暗号化したり、その逆をおこなったりできるコマンドラインツールです。
 まあ、もっといろいろな機能があるわけですが、とりあえず今回はCCCryptで作った暗号文を平文に戻すのに使います。
 openssl渡す情報としては、暗号文がhello.encというファイルに入っていること、暗号化アルゴリズムにAESを使ったこと、キー長は256ビットで、ECBモードで暗号化していること、そしてキーの値となります。

openssl enc -d -aes-256-ecb -in hello.enc -nosalt -K 0001020304050607000102030405060700010203040506070001020304050607

 これでhello.encの内容が読み込まれ平文がターミナル画面に出力される。
 実際の手順をYouTubeにアップしたんで見てね。
  ↓


 次回はopensslで暗号化したファイルを平文に戻してみる。
AD
いいね!した人  |  コメント(0)  |  リブログ(0)
2015年10月29日(木) 23時54分45秒

iPhoneアプリ開発 暗号 その1

テーマ:iPhoneアプリ開発ドリル
 暗号です。

1
通信の秘匿がサンダース校戦での勝因。
まあ、携帯メール使っただけなんですけどね。by武部沙織


 個人情報がどうのこうのと世知辛い昨今、アンケート結果ひとつWebサーバーにアップするにしても、住所とか氏名があるなら漏洩の対策を考えないといかんわけですよ。
2
 iPhoneとサーバ間とのやりとり自体は、httpsを使えば勝手に暗号化してくれるんだけど、問題は受け取った情報をサーバー側に保存する場合っす。
3
 誰でも触れるところに保存するのは論外として、そうでなくても、あの手この手で取り出そうとする個人情報大好きっ子ちゃんはいるわけでして、実際に漏洩した場合に、暗号化してませんでした~テヘペロじゃあ、言い訳がたたんわけですな。
 でまあ、そういう場合サーバー側が暗号化の面倒をみてくれる場合がほとんどなんですが…
4
 諸所の事情でファイルの保存しかできない中継用のサーバーを立てて、そこにファイルを置かざるを得ない場合、iPhone側で暗号化しておく必要が出てくるわけです。
5
6
 これに加えて、サーバー経由で情報をやりとりしようって場合、やりとりする相手はiPhoneじゃない場合が多いわけでして…
 結果、暗号化アルゴリズムには、独自のものじゃなく、Win32やPHPやJavaといったメジャーどころでも扱えるものを選ぶ必要がでてきます。

 暗号化アルゴリズムてのは、例えば

 文章を暗号化するさいには、各文字ごとにアルファベットの順序を3文字ずらした文字を使う

といったように、暗号化するさいの手法を指します。
 ここで挙げた暗号化アルゴリズムは、シーザー暗号という(ブートキャンプで紹介したの覚えてるかな~)んですが、この場合、各文字は3文字ずつずれて、それぞれ

  ABCDEFGHIJKLMNOPQRSTUVWXYZ
   ↓
  DEFGHIJKLMNOPQRSTUVWXYZABC

となり、例えば

  "HELLO CIPHER"

を暗号文にすると

  "KHOOR FLSKHU"

となって、ぱっとみ意味不明の文章、いわゆる暗号文になるわけです。
7
ちなみに暗号文に対して、暗号化される前の文を平文といいます。
8
 え、じゃあ「暗号化アルゴリズム公開しちゃったらまずいじゃん」と思った人、大正解。まずいんですよ。
 で、さすがにシーザーも、こりゃ使えね~って思ったのか軍事には使用せず、私信に用いていたそうです、Wikiによると。てか単なる遊びじゃね?2ちゃんねらーがよくやる縦読みにすると別の文章が浮き上がるたぐいの、シーザー元祖VIPPER?
 まあ、そんなこんなで、使ってることがバレたら一発アウトの欠陥暗号化アルゴリズム・シーザー暗号なわけですが、だがしかし、現代の最新最強の暗号化アルゴリズムに通じる基本がすでに組み込まれているんですな。

 注目すべきは「アルファベットを何文字分ずらすか」という情報っす。
 先に示したシーザー暗号の「3文字ずらす」て部分を「K文字ずらす」に変えるわけですよ。
9
 で、このKを、暗号をやり取りする者同士で決めることで、シーザー暗号化アルゴリズムを使っているとわかっても、Kがわからなければ暗号は解かれないようになるわけです。
10

 このKのことを業界用語でキー(鍵)といいます。

 え、でも「アルファベット26文字なんて、最大25種類のずらし量しか指定できないんだから、1~25のずらし量を総当りで試せば解読できるんじゃ」と思った人、大正解。解読できるんですよ。総当たり攻撃(Brute-force attack)といいます。
 なんですが、このKの取り得る値の範囲を1億とか1兆、1京とかに広げられて、その値ごとに暗号文が異なるようなら、さすがに解読側もヨイショがいるわけでして、そうなると暗号化アルゴリズムが公開されても、キーがバレなければ暗号文は解かれないって理屈も通ることになるわけです。
 そのためにキーの値は、ズラす量にとどまらず、平文とXORをとったりとか、暗号文を作るための、いろいろな計算式のパラメタとして使われます。
 で、どれだけキーなしで暗号文から平文を再現できないようになっているか、また、どれだけキー自体が暗号文から再現できないかを競い合ってるのが、現代の暗号化アルゴリズムってことになります。
 あと、どれだけ軽快(少ないメモリ、遅いマシンでも使える)に暗号・平文化できるかとかも競ってる。
 ちなみに、キーを生成する種となるのが、いわゆる暗号化のさいにユーザーが入力するパスワードです。なかにはパスワードをそのままキーとして使う暗号化アルゴリズムもあるかもしれんけど、普通はワンクッションおきます。

 アルゴリズムではなくキーを秘匿する。

 これが現代の暗号の基本みたいっす。
 なので、基本、暗号化アルゴリズム自体はバンバン公開されてます。
 なかには隠してたけど漏洩したってのもあるみたいだけど…
 そもそもアルゴリズムを隠したくても、アプリやライブラリ、フレームワークといったバイナリコードは公開しないと誰も使えないわけだから、暗号化された情報に億といった金が絡めば、犯罪行為だろうがなんだろうがリバースエンジニアリングされて解析されるだろうし、アルゴリズムを隠すことにはあんまり効果は期待できないでしょうな~。むしろ公開することで、第三者からアルゴリズムの欠陥の指摘なんかも期待できるんじゃないかと思われ。
 まあ、それなりの数学者が作るアルゴリズムてのが前提の話だけどね。
 一般プログラマが作る独自の暗号化アルゴリズムなんて、穴だらけで、アルゴリズム公開しちゃうと、簡単に暗号文からキーなしで平文が取り出されるのがオチでしょう。その場合は隠すしかないでしょうな。
 というわけで、よほどの天才の自負でもない限り、独自の暗号化アルゴリズムなんかは使わずにメジャーな暗号化アルゴリズムに頼りましょう。
 で、こういった場合に利用するのが

  CCCrypt

というAPIでして、こいつを使うと

  DES、トリプルDES、AES、CAST、RC4、RC2、Blowfish

 といったメジャーな暗号化アルゴリズムでバイト列を暗号化できます。
 興味がわいた人は上にあげた名前でググるといいでしょう。

てことで、次回、USA標準のAESで平文を暗号化してみる!
AD
いいね!した人  |  コメント(0)  |  リブログ(0)
2011年06月16日(木) 01時32分23秒

【iPhoneアプリ開発ドリル】Aqua風ボタンを作る

テーマ:iPhoneアプリ開発ドリル
目的
UIControlを継承しターゲットアクションメカニズムを持つクラスを作る方法を理解する。

主要クラス
UIControl,CALayer

使用テンプレートプロジェクト
Window-based Application

プロジェクトの名称
aquabutton

事前に体験しておくべきドリル

サンプル実装説明


 このドリルではUIControlを継承し、描画に「CALayerのcontentsを理解する」で使ったCAGradientLayerを使う事でAquaライクなボタンを作成する。
 まずはプロジェクトaquabuttonを作成し、UIControlを継承したAquaButtonクラスを作成する。
 作成時はUIViewを継承クラスとして選び、AquaButton.hができた時点でUIViewをUIControlに書き換える。CAGradientLayerのインスタンスはハイライト状態、ディスエーブル状態などでグラデーションを変化させるので、internalButtonという名称でインスタンス変数として持つ。
 プロパティtextLabelは「CALayerのcontentsを理解する」を参照。その他にボタンの色相を指定できるようにhueプロパティを用意した。
#import
@class CAGradientLayer;

@interface AquaButton : UIControl {
CAGradientLayer* internalButton;
}
@property (readonly) UILabel* textLabel;
@property (assign) float hue;
@end

 今回、ボタンの状態ごとにグラデーションを作りなおせるよう、グラデーションカラー配列を作る部分をメソッドとして独立させた。内容自体は「CALayerのcontentsを理解する」と同じ。
- (NSArray*)gradientArrayWithHue:(float)hue_
saturation:(float)saturation
brightness:(float)brightness
{
CGColorRef halationTop = [UIColor colorWithHue:hue_
saturation:saturation * 0.2
brightness:brightness
alpha:1].CGColor;
CGColorRef halationBottom = [UIColor colorWithHue:hue_
saturation:saturation * 0.8
brightness:brightness * 0.8
alpha:1].CGColor;
CGColorRef normalTop = [UIColor colorWithHue:hue_
saturation:saturation
brightness:brightness * 0.8
alpha:1].CGColor;
CGColorRef normalBottom = [UIColor colorWithHue:hue_
saturation:saturation
brightness:brightness
alpha:1].CGColor;
NSMutableArray *colors = [NSArray arrayWithObjects:
(id)halationTop,
(id)halationBottom,
(id)normalTop,
(id)normalBottom, nil];
return colors;
}

 initWithFrame:メソッドも、グラデーション色配列をgradientArrayWithHue:saturation:brightness:メソッドで作るようにした以外は特に違いはない。

@implementation AquaButton
@synthesize textLabel, hue;
 ・
 ・
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
internalButton = [CAGradientLayer layer];
internalButton.frame = self.bounds;
internalButton.borderWidth = 1;
internalButton.cornerRadius = self.bounds.size.height / 4.0;
NSMutableArray *locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.0],
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:0.5],
[NSNumber numberWithFloat:1.0],nil];
[internalButton setLocations:locations];
[internalButton setColors:[self gradientArrayWithHue:hue saturation:1 brightness:1]];
[self.layer addSublayer:internalButton];
textLabel = [[[UILabel alloc] initWithFrame:self.bounds] autorelease];
textLabel.font = [UIFont boldSystemFontOfSize:18];
textLabel.textColor = [UIColor whiteColor];
textLabel.textAlignment = UITextAlignmentCenter;
textLabel.shadowColor = [UIColor grayColor];
textLabel.backgroundColor = [UIColor clearColor];
[self addSubview:textLabel];
}
return self;
}

 あとはsetEnabled:、setHighlighted:メソッドをオーバーライドすればUIButtonと同じ動きをするAqua風ボタンが完成する。
- (void)setEnabled:(BOOL)enabled
{
[super setEnabled:enabled];
[internalButton setColors:[self gradientArrayWithHue:hue
saturation:enabled?1:0.3
brightness:1]];
internalButton.borderColor = enabled
?([UIColor blackColor].CGColor):([UIColor lightGrayColor].CGColor);
}

- (void)setHighlighted:(BOOL)highlighted
{
[super setHighlighted:highlighted];
[internalButton setColors:[self gradientArrayWithHue:hue
saturation:1
brightness:highlighted?0.7:1]];
}

 あっけないが、ボタン程度ならこれで十分機能する。
 aquabuttonAppDelegateで今回作成したAquaButton、UIButtonをそれぞれwindowに配置してUIControlEventTouchDown、UIControlEventTouchDragInside、…、UIControlEventTouchUpInsideなどのイベントに対しターゲットアクションを設定し比べてみる。

$テン*シー*シー-1

 コンソールにはAquaButton、UIButtonどちらも同じように、指(カーソル)の動きに合わせてアクションメソッドが実行されていく。
EventTouchDown
UIControlEventTouchDragInside
UIControlEventTouchDragInside
UIControlEventTouchDragInside
UIControlEventTouchDragInside
UIControlEventTouchDragInside
UIControlEventTouchDragInside
UIControlEventTouchDragInside
UIControlEventTouchUpInside


 以上、AquaButtonはボタンとしてはUIButton同等の働きができる事がわかる。

$テン*シー*シー-2

 前回の応用としてUIViewを継承しCAGradientLayerを使ったBadgeViewもサンプルソースに含めておく。shadowOffset、shadowOpacityプロパティを使っている。
 こちらは、いわゆるバッジ。

$テン*シー*シー-3

プロジェクト


検討

 contentsにCGImageRefを設定する場合、retinaディスプレイに最適化したい場合、作成するCGContextRefを UIGraphicsBeginImageContext ではなくUIGraphicsBeginImageContextWithOptions を使って作成したり、CALayerのcontentsScaleプロパティを2.0にしたりを自分で調整しなければならない。
 retinaディスプレイかどうかは[[UIScreen mainScreen].scaleで調べる。
 iOS 4.0より前のiOSでも動かす予定なら、scaleプロパティを使う前に
  [UIScreen instancesRespondToSelector:@selector(scale)]
 といったチェックも必要。

 CAGradientLayerはその点においても使う価値がある。
AD
いいね!した人  |  コメント(0)  |  リブログ(0)
1 | 2 | 3 | 4 | 5 |最初 次ページ >>

AD

Ameba人気のブログ

Amebaトピックス

      ランキング

      • 総合
      • 新登場
      • 急上昇
      • トレンド

      ブログをはじめる

      たくさんの芸能人・有名人が
      書いているAmebaブログを
      無料で簡単にはじめることができます。

      公式トップブロガーへ応募

      多くの方にご紹介したいブログを
      執筆する方を「公式トップブロガー」
      として認定しております。

      芸能人・有名人ブログを開設

      Amebaブログでは、芸能人・有名人ブログを
      ご希望される著名人の方/事務所様を
      随時募集しております。