iOS, Android, perl間で AES暗号化を行った通信をする

By | 2012年3月2日

Andorid, iOS, サーバー(perl)間で暗号化して通信する必要があったのでまとめてみました。

処理の流れはこんな感じ

クライアント(iOS, Android) からの通信
         [Request]                            [Response]
        plain text                       plain text
           ↓                                   ↑
        cipher text                        cipher text
           ↓                                   ↑
        base64 text                      base64 text
           ↓                                   ↑
          WAN(POST)                       WAN
           ↓                                   ↑
        base64 text                      base64 text
           ↓                                   ↑
        cipher text                        cipher text
           ↓                                   ↑
        plain text                      plain text

鍵は事前に交換してるものとして話をすすめます。

結論からいうと iv さえあわせとけば特にハマリませんでした。
そういいつつここで大分はまったんですけどねw

とういわけで iv をそろえないといけないので今回は iOS で NULL(0x00 x 16 Byte) にあわせました。

それは「CCCrypt(Objective-C) で暗号化したデータを Crypt::OpenSSL::AES(perl) で復号化する」を参考にしただけで特に理由はありません。

本来なら C で Android, iOS 用のライブラリをつくっちゃったらよかったのだろうけどもと思いつつそこまでやってません。

あと GET で暗号化したものを通信する際は Base64 を URLSafe にして encode / decode してください。

perl

#!/usr/bin/env perl
 
use strict;
use warnings;
 
use Digest::MD5 (); 
use MIME::Base64 (); 
use Crypt::CBC (); 
 
sub main {
    my $key = 'e8ffc7e56311679f12b6fc91aa77a5eb';           #Digest::MD5::md5_hex(time); とか。
    my $cipher = Crypt::CBC->new(
        -key         => $key,
        -literal_key => 1,
        -cipher      => 'Crypt::OpenSSL::AES',
        -header      => 'none',
        -iv          => pack('C*', map {0x00} 1..16),
    );  
 
    ############## Request(decrypt) ##############
    my $base64_text = "BhSJd4mRRJo+fGzpxIOUNg==";
    my $cipher_text = MIME::Base64::decode_base64($base64_text);
    my $plain_text  = $cipher->decrypt($cipher_text);
    print "plain text for request : $plain_text\n";         # plain text for request : crypt text!!
 
    ############## Response(crypt) ##############
    $plain_text  = "I'm hungry!";
    $cipher_text = $cipher->encrypt($plain_text);
    $base64_text = MIME::Base64::encode_base64($cipher_text);
    print "base64 text for response : $base64_text\n";      # base64 text for response : 72XrlydqnUzVrDfDE7ncnQ==
 
    return 0;            
}                        
 
exit main() unless caller;

iOS

AES crypt category」と「Base64 category」をもってきて
import すれば下記の方法でいけます。

NSString *key = @"e8ffc7e56311679f12b6fc91aa77a5eb";
 
NSData *cipherData;
NSString *base64Text, *plainText;
 
//############## Request(crypt) ##############
plainText  = @"crypt text!!";
cipherData = [[plainText dataUsingEncoding:NSUTF8StringEncoding] AES256EncryptWithKey:key];
base64Text = [cipherData base64Encoding];
NSLog(@"%@", base64Text);            //BhSJd4mRRJo+fGzpxIOUNg==
 
//############## Response(decrypt) ##############
base64Text = @"72XrlydqnUzVrDfDE7ncnQ==";
cipherData = [base64Text base64DecodedData];
plainText  = [[NSString alloc] initWithData:[cipherData AES256DecryptWithKey:key] encoding:NSUTF8StringEncoding];
NSLog(@"%@", plainText);            //I'm hungry

Android

AndroidでAESの暗号化する」を参考にしてつくりました。
違うのは鍵を外部からうけとれるようにしたのと、 iv を 0x00 の 16 Byte にそろえたくらいです。
Base64 で encode / decode しないといけないので Android SDK 2.2 以上だと動きます。
2.1 以下で使用する際は別途 Base64 のライブラリを用意してください。

エラーのハンドリングとかちゃんとしていないので参考程度にしてください。

AES256 encryption on Android

String key = "e8ffc7e56311679f12b6fc91aa77a5eb";
byte[] keyBytes = key.getBytes("UTF-8");
byte[] ivBytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
 
String plainText;
byte[] cipherData;
String base64Text;
 
//############## Request(crypt) ##############
plainText  = "crypt text!!";
cipherData = AES256Cipher.encrypt(ivBytes, keyBytes, plainText.getBytes("UTF-8"));
base64Text = Base64.encodeToString(cipherData, Base64.DEFAULT);
Log.d("encrypt", base64Text);   //BhSJd4mRRJo+fGzpxIOUNg==
 
//############## Response(decrypt) ##############
base64Text = "72XrlydqnUzVrDfDE7ncnQ==";
cipherData = AES256Cipher.decrypt(ivBytes, keyBytes, Base64.decode(base64Text.getBytes("UTF-8"), Base64.DEFAULT));
plainText = new String(cipherData, "UTF-8");
Log.d("dcrypt", plainText);         //I'm hungry

いじょう。