VOYAGE GROUP エンジニアブログ

voyagegroup_techのブログ
VOYAGE GROUPエンジニアブログです。

2012年04月

androidとiOSで共通で使える暗号方式

こんにちは、VOYAGE GROUPのしんばし(@shinbashi)です。

昨今何につけてもスマートフォンですよね。
かくいう僕もPDAからのW-ZERO3という王道を通って来ました。

さて、最近は特にスマートフォン対応とか、アプリ化する機会が増えてきたと思います。
android版を作ればiOS版も出すよ!みたいな話になりますよね。
「android版だけでいい」
なんて言葉を信じて設計すると、後で痛い目を見るのは火を見るより明らかです。

前フリが長くなりました。
android版だけだと信じて僕が痛い目を見たのは暗号化・復号処理の部分です。
Javaはともかく、Objective-Cをよく知らなかったのでライブラリに頼るわけですが、
Objective-Cの暗号化・復号処理をしてくれるライブラリでは扱えないアルゴリズムとかあるんですね。

ざっくり調べた感じだと以下な感じです

表1 アルゴリズム比較表
AES ARCFOUR Blowfish DES DESede ECIES RC2 RC4 RC5 RSA CAST
javax.crypt(android)
CCCrypt(iOS)

表2 パディング比較表
no padding PKCS7 PKCS5 PKCS1 PAEP
javax.crypt(android)
CCCrypt(iOS) ※1

※1 PKCS7 ≒ PKCS5 (ブロック長の違いなのでPKCS7でPKCS5形式のものをunpad出来る)

実際、パディング処理は暗号化前、復号後に自前でやってしまえばいいのでなんとでもなりますね。
こうしてみると、暗号化アルゴリズムはAESで実装するのが妥当そうです。
Objective-Cで自前でPKCS5でunpadする場合は以下な感じになると思います。
+ (NSData *) pkcs5_unpad:(NSData *)data
{
    int pad = [[[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(data.length - 1, 1)] encoding:NSASCIIStringEncoding] characterAtIndex:0];
    if (pad > data.length) return nil;
    return [data subdataWithRange:NSMakeRange(0, data.length - pad)];
}
ざっくりまとめると
  • アルゴリズム:AES(鍵長は128でも256でもいいと思います)
  •  ブロック形式:CBC(EBCも使えます)
  • パディング:PKCS5(独自で実装できるのでお好きにどうぞ)
な感じで暗号化しておけば、android(java)でもiOS(Objective-C)でも取り扱いできます。
javax.cryptやCCCryptの使い方は色々な方が解説していらっしゃるのでそちらを参考にしていただければと思います。決してJavaのコード長すぎて写すのを面倒臭がっているわけではありません。

また、僕の場合だけかもしれませんが、CCCryptを使った時に、末尾に改行コードが含まれていて、NSDataからNSStringに変換しようとした時にエラーが発生したので、トリムする必要があるかもしれません。
また、WindowsPhoneに関してですが
「C#だし」
ってことで割愛させて頂きました。


おまけ

mixi Engineers' Blog » OpenSSLの暗号文をJava/Perl/Rubyで開く
http://alpha.mixi.co.jp/blog/?p=91

こちらでJavaでOpenSSLのパスフレーズから鍵を導出する処理が書かれていたので、せっかくなのでObjective-Cで実装するとどうなるのか書いてみました。

+(NSDictionary*) pass2keyInfo:(NSData *)pass salt:(NSData *)salt
{
    int keySize = 256;
    int ivSize  = 128;
    int keyAndIvSize = (keySize/8) + (ivSize/8);
    NSMutableData* result = [[NSMutableData alloc] init];
    NSMutableData* keyAndIv = [[NSMutableData alloc] init];
    while (keyAndIv.length < keyAndIvSize) {
        [result appendData:pass];
        [result appendData:salt];
        [result setData:[result MD5Digest]];
        [keyAndIv appendData: result];
    }
    NSData* key = [keyAndIv subdataWithRange:NSMakeRange(0, keySize/8)];
    NSData* iv  = [keyAndIv subdataWithRange:NSMakeRange(keySize/8, ivSize/8)];
    return [NSDictionary dictionaryWithObjectsAndKeys:key, @"key", iv, @"iv", nil];
}
参考
Java ™ 暗号化アーキテクチャー標準アルゴリズム名のドキュメント
http://java.sun.com/javase/ja/6/docs/ja/technotes/guides/security/StandardNames.html#AlgorithmParameterGenerator

CommonCryptor.c
http://opensource.apple.com/source/CommonCrypto/CommonCrypto-36064/Source/CommonCryptor.c

Jumvoの作り方

genesixの永野です。
弊社では定期的に社内の発表イベントをやっていまして、先日
「Jumvo 2.0 における デザイナーとエンジニアの連携」
と題して、Jumvoをどうやって作ったのかを発表しました。 当日のSlideはこちら

Jumvoとは
Jumvoはgenesixからリリースしている、簡単に言えば声のSMSができるiOSアプリケーションです。声を送りあうことに特化しているため、シンプルな操作性が売りになっています。こちらから無料でダウンロードできます

icon_201201

発表はデザイナーの伊野と二人で行ったのですが、この記事ではプログラマーの立場から、Jumvoで取った開発方法を紹介します。

具体的には、Jumvoでは「プロトタイピング」と「UXデザイン定義書に法った開発」を行いました。まず最初に、これに到るまでの経緯をお話します。


自己紹介とこれまでにやってきたこと
genesix入社前は、フリーランスで通販サイトを作ったり(PHP/Java)、時間とお金があればMacのアプリを書いたりしていました。genesix入社直前の1年ぐらいはMac/iOS系会社で主に受託案件をやっていました。受託という性質上、仕様の受け入れ、工数見積もり、というようなことがよくありましたが、その中で感じていたのが「iOSアプリは仕様を決めるのが難しい」そして「仕様が頻繁に変わる」ということです。


「仕様」が決まらない
そんなのiOSに限ったことじゃないだろう、と思われる方もいると思いますが、Webアプリケーションの受託案件と比べても変更が多い印象でした。実際に画面に触ってみないと分からない点が後から色々出てくる、のが一番の理由だと思われます。
象徴的な話としては自機を触って操作するシューティングゲームで、完成してみると、自機が指で隠れてしまうのでお蔵入りになった、という冗談みたいな話も聞いたことがあります。

そのため、いつも「後で変更しやすいようにしておかないと、納品前に仕様が変わって間に合わなくなるだろう」とか「この見積もりでは変更できないからクライアントが納得しないだろ」「最初にこの操作だけは決めておかないと完成前に変わると全部がひっくりかえる」といったよく心配をしていました。

全画面の構成程度の仕様が決まったと思っても、使っているうちに問題点が浮き彫りになり、修正したくなる。よくあるのが、ここの仕様が曖昧だと思っていると、後でデザイナーから(もしくはクライアントから)指摘がある。しかし、仕様が決まりさえすれば、たいていのものは作るのは難しくありません。しかし、どんなに優秀なデザイナーでさえ、動かなければ分からないことが多い、どうすればいいだろう?ということをずっと考えてきました。


「ユーザー」とは誰なのか?
もう一点、仕様を決めていくプロセスにおいても問題を感じていました。
たとえば、クライアント、エンジニア、デザイナーで新しいアプリの仕様を検討していても、それぞれがそれぞれの立場で、この機能が必要だ、これはこの位置だ、という話になりますが、その主張の根拠が「ユーザー」という正体不明なものであることでした。
正体不明な「ユーザー」? 何を言っているんだ!と言う方もいらっしゃると思いますので説明します。

何かBtoCのサービスを作るのであれば、それは顧客であるユーザーのためである、これに異論がある方は居ないと思いますが、その「ユーザーのためを考える」のは各人共通であったとしても、実は対象としているユーザーがそれぞれ(の立場)によって異なるのです。

iOSアプリを作るとすれば、対象ユーザーの範囲は多岐に渡るにも関わらず、ある人は若い女性を想定しているかもしれませんし、ある人は中年のサラリーマンを想定しているかもしれません。ある人は非常にリテラシーの高い人を想定、もしくは逆、ということがあり得ます。対象をきっちり決めていない場合はほぼそうだと考えるべきだと思います。

そのため、ある機能を決定する場合でも、想定しているリテラシーが異なるため、ある人はこれぐらいは分かると言い、ある人は逆にこれは理解できないはずだと言い、という出口の無い議論をすることになります。
実際、前職で「ユーザー」という参加者全員が頻発する言葉に、それって誰?と言ったことがあります。そして、各人の「ユーザー」像を少しでも近づけるべく実際に使ってくれているユーザーに来てもらって話を聞こう、と提案したりしました(それは叶いませんでしたが)。

Jumvo 1.0では、以上の二つの問題に対して次のような方法で解決を試みました。


まず

1.「仕様」が決まらない
この点については、最初から「仕様をかちっと決めてから開発する」ということは不可能である、という前提で開発することにしました。つまり仕様は決まらないので、決めずにやるということです。しかし何も決まらなければ進まないので、いつでも変更される前提のプロトタイプをベースに、動くものを見ながら意見を交換し、進めました。具体的には、iPhoneの実機で実際に動作するものを基本に進めました。これは簡単に言えばプロトタイピングと言えると思います。つまり、Jumvoは最初から他のiPhoneと声を送りあえる状態から作っていったのです。下の写真のように紙にメモを書きながら、最初は僕が必要な機能を考え、UX/UIデザイナーと意見を交換しながら、実際に動作するものを修正しつつ進めていきました。
jumvo1


これによって実際に手に取って声を発して、それを実際に相手に送信する、という一連の操作と、何よりその操作性が重要であるということをチームのメンバーに最初に伝えることができたと思います。それはその後のスムーズな開発(のための仕様の検討)に繋がったと考えています。つまり、プロトタイプベースで進めることによって、ユーザー体験のコア部分が速い段階で検証できた、ということになります。

また、事業責任者やプロデューサーに、Jumvoが面白いのかどうか、最初の段階で確認してもらえたことも大きな利点であったと思います。

このようなプロトタイピング期間が1ヶ月程あった後、UIデザイナーが正式にアサインされ、それまでのプロトタイプを元に、具体的なデザイン案が出来てきました。その案も実際に実機で動かし、再度修正し、またさらに動かし、という工程を1ヶ月で3度ほど繰り返し、最初のv1.0が完成しました。ここまでで2ヶ月ほどの時間がかかっています。




2.「ユーザー」とは誰なのか?

これは実は当初は想定していなかったのですが、genesixには選任のUXデザイナーがおり、UXデザインにおいてペルソナを採用していました。
そして、アプリは「アプリケーション定義ステートメント」にそって作られる、という一環した手法を採用していたのです。
アプリケーション定義ステートメントとは、詳細はこちらを参照いただきたいのですが、簡単に言えば、誰が何を達成するため(=使う人のゴール)のアプリケーションなのか、を1行程度で表したものです。Jumvoの場合「もっと気持ちを伝え合いたい人のためのもっと気軽で手軽なボイスメッセージングアプリ」がそれであり、仕様等で迷ったときには定義ステートメントはこれだから..と復唱することで目的を、もっと言えばユーザーのゴールを確認することができます。

僕はこの開発手法を聞いたときに正体不明のユーザーから逃れる方法だ!と目からうろこが落ちました。実際にこの手法で開発をしてみると、チーム全員が「アプリケーション定義ステートメント」に向かっており、「ユーザー」ではなくペルソナを対象として話をするため、仕様の検討でばらばらな方向を向くというとが皆無でした。
アプリの目的が明確だったというのもあると思いますが、このユーザーは分かる、分からない、という議論はまったくありませんでした。あったのはどうやればゴールに近いか、という議論だけです。その中では多くの方法が話し合われましたし、ときには難航もしましたが、誰かがひらめいたときの全員の「それだ!」という意思統一の速さはこれまでに経験したことのないものでした。
加えて、Jumvoではプロトタイピングで仕様を決めていたため「この仕様にしたら、時間がかかるから...」 といったことを考えずに自由に発言できたこと、また出た案を常に手に取って使いながら判断できたことも、議論がスムーズに進んだ一つの要因だと考えます。


問題点
さて、上記を振り返るといいことづくめなように思えますが、問題点としては以下が考えられます。

1. いつまでも仕様が決まらない

仕様は決まらないから決めない、という前提でスタートしているため、時間的、予算的余裕があれば、それこそどれだけでも開発できてしまうため終りがやってきません。現実的にはそのようなことは無いため、いつか終わりがきます。Jumvoの場合その制約はリリース目標日でした(具体的には7月頭)。目標日までに作るには、プロトタイピングといえども、明確に何を決めたくて、今何を試しているのか、を意識する必要があると思います。
ただ面白いかどうかだけを試していたら、何パターンもアニメーションを動かしてみて時間がすぎていく、ということもあるでしょう。

Jumvoの場合、具体的な例としては、送信相手を複数選んで送信する、それを最も簡単に少ない操作ステップ数で行えるUIは何か、ということを何パターンも試しました。そして分かりやすさと操作性を軸に判断していきました。

2. コーディング量が増える
Jumvoの完成形のコード量を1とすると、少なく見積もっても3倍ぐらいのコードを書きました。そのためには時間がかかります。ですが、プロトタイピングに2ヶ月かかっていては、それは機能しないでしょう。
そのため、必要な箇所を的確に判断し、最低限のコード量で最大の効果を発揮するいわば”勘”が必要になると思います。Jumvoは目的が明確なアプリであったため、それに必要なコア部分も分かりやすく、プロトタイピングに向いていたと考えられます。Jumvoに限らず、iOSアプリは目的が明確であるべきだと考えますので、プロトタイプベースでの開発に向いていると言えるかもしれません。


3. プロトタイプに仕様決定の主導権が移ってしまう
実際に動くものがあるため、その説得力は非常に高く「うん、これで動いているしいいんじゃない?」となる可能性が高くなります。実際、Jumvoでもプロトタイプにデザイナーが引っ張られ、最終的な判断ができない、という状況がありました。これを回避するには、モノを判断するモードと、モノを作るモードの切り替えが必要です。UXデザイン定義書は判断するモードに戻るために非常に有効でした。



まとめ
これまで述べてきた僕が考える問題点とそれに対するやり方を振り返ると、そもそも市場調査は的確だったのか、それで実際にアプリがヒットするのかどうか、といった根本的な問題はあります(実際、Jumvoが大ヒットしているわけではありません)。
しかし、そのために最低限必要な条件である(と僕が考える)、よいものを作るための近道の一つが試せたと思いますし、実際に効果がありました。
一つの結果としては、App Store Rewind 2011に選んでいただきました!

25


(実機のiPhoneで動くものをベースとした)プロトタイピングはコーディング量が増えるため導入の敷居は若干高いかもしれませんが、UXデザイン定義書は、採用しやすいのではないでしょうか。
以下の記事などを参考に採用を検討してみてください。

スライドの後半では、genesixのUXデザインについて具体例を交えながら書いてあるので、参考にしていただければ幸いです。また、genesixデザインプロセスも公開されていますので、合わせてごらんください。
記事検索
QRコード
QRコード