Posts Tagged ‘復号化’

{ 2010.12.5 }

iPhone で暗号化

    はてなブックマーク - iPhone で暗号化
    このエントリーをはてなブックマークに追加

    初めまして、Fusic 河野です。
    わたくし、IT 系のバスケの社会人チームやiPhone アプリ系のコミュニティとかを
    やってたりするので、ご興味のある方はぜひご参加ください。

    弊社にはもう一人河野というものがおり、そっちとは違う方と
    覚えて頂けると溜飲が下がります。。。

    最近、プライベートではこんなことやってたりして遊んでます。
    Fusic では、主に ruby on rails をやっており、ZENPRE の iPhone アプリを
    担当させていただいてたりします。

    さて、昨日行われました安元の結婚式も無事に終わり、本日はとっても天気の良い日曜日です。
    それにしても、とても良い結婚式でした。

    「おめでとうございます。お二人とも末永くお幸せに!」

    で、そんな幸せに包まれつつな日曜日も Advent Calendar です。
    こんな日にバトンがまわってくるとは、、な気分ではございますがさっそく。

    ご結婚されたばかりのお二人には、なんとも、、な話かもしれませんが、
    いくら仲睦まじい関係だとしても、時には隠蔽する必要が出てくる事が
    あるやも知れません。
    そんな時に必要になってくること。

    “暗号化”についてです。

    前に山本が「as3cryptoで暗号化」 という記事を書いてますが、
    その記事の iPhone 版だと思っていただければ幸いです。

    暗号化

     objective-c で暗号化をする場合、CCCrypt() という関数を使います。

     [CCCrypt(3cc) Mac OS X Manual Page]
     developer.apple.com/library/mac/#DOCUMENTATION/Darwin/Reference/ManPages/man3/CCCrypt.3cc.html
     
     iPhone 用のサンプルコードはこちらになるのですが、見ていただくと分かるのですが、
     まー、as のように楽じゃないなというのが分かって頂けるかなと。

     CCCrypt() を使用して、NSData クラスに AES256EncryptWithKey, AES256DecryptWithKey のメソッドを追加します。
     (※ こちらを参考にしました)

     NSDataAdditions.m というファイルを作成し、以下を追加します。

    #import <CommonCrypto/CommonCryptor.h>
     
    @implementation NSData (Additions)
     
    @class NSString; 
     
    - (NSData *)AES256EncryptWithKey:(NSString *)key {
            char keyPtr[kCCKeySizeAES256+1];
            bzero(keyPtr, sizeof(keyPtr));
     
            [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
     
            NSUInteger dataLength = [self length];
     
            size_t bufferSize = dataLength + kCCBlockSizeAES128;
            void *buffer = malloc(bufferSize);
     
            size_t numBytesEncrypted = 0;
            CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128,       
                                                                             kCCOptionPKCS7Padding | kCCOptionECBMode,
                                                                             keyPtr, kCCKeySizeAES256,
                                                                             NULL,
                                                                             [self bytes], dataLength,
                                                                             buffer, bufferSize,
                                                                             &numBytesEncrypted);
            if (cryptStatus == kCCSuccess) {
                    return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
            }
            free(buffer);
            return nil;
    }
     
    - (NSData *)AES256DecryptWithKey:(NSString *)key {
            char keyPtr[kCCKeySizeAES256+1];
            bzero(keyPtr, sizeof(keyPtr));
     
            [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
     
            NSUInteger dataLength = [self length];
     
            size_t bufferSize = dataLength + kCCBlockSizeAES128;
            void *buffer = malloc(bufferSize);
     
            size_t numBytesDecrypted = 0;
            CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, 
                                                                             kCCOptionPKCS7Padding | kCCOptionECBMode,
                                                                             keyPtr, kCCKeySizeAES256,
                                                                             NULL,
                                                                             [self bytes], dataLength,
                                                                             buffer, bufferSize,
                                                                             &numBytesDecrypted);
     
            if (cryptStatus == kCCSuccess) {
                    return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
            }
            free(buffer);
            return nil;
    }
    @end

     使う側でファイルをインポートすれば、NSData クラスのメソッドとして使えます。

    base64encoding

     暗号化したデータを ZENPRE とかのように、サーバにデータを送る必要があるなら、
     base64 エンコードも実装する必要があります。
     同じく NSData クラスに newStringInBase64FromData というメソッドを追加します。
     (※ こちらを参考にしました)

     先程のファイルに下記を追加します。

    - (NSString *)newStringInBase64FromData {
            NSMutableString *dest = [[NSMutableString alloc] initWithString:@""];
            unsigned char * working = (unsigned char *)[self bytes];
            int srcLen = [self length];
     
            for (int i=0; i<srcLen; i += 3) {
                    for (int nib=0; nib<4; nib++) {
                        int byt = (nib == 0)?0:nib-1;
                            int ix = (nib+1)*2;
     
                            if (i+byt >= srcLen) break;
     
                            unsigned char curr = ((working[i+byt] << (8-ix)) & 0x3F);
     
                            if (i+nib < srcLen) curr |= ((working[i+nib] >> ix) & 0x3F);
     
                            [dest appendFormat:@"%c", base64[curr]];
                    }
            }
            return dest;
    }

     同じく使う側でファイルをインポートすれば、NSData クラスのメソッドとして使えます。

    実行

     上記の追加したコードを含めたサンプルコードを実行します。

     

     入力した値が、base64 に変換されている事(真ん中のグレー領域)と
     暗号化されたものが復元されている事(下の白領域)を確認します。

    おわりに

     やはり、どうしても as と比べるとなんだかメンドクサイですね。
     暗号化の話は、コードも含め長文にどうしてもなってしまうので
     駆け足で進めていってしまいました。
     今回、objective-c の醍醐味の一つでもあるかなと個人的に思ってる、
     既存クラスへのメソッドの追加ができるってだけでも実感頂ければと思います。

     今回使用したサンプルのソースコードはココにあげております。
     お役に立てれば幸いです。

     それと、近々 ZENPRE の iPhone アプリの新版がリリースされる予定です。
     ご期待下さい。

    { 2010.9.29 }

    as3cryptoで暗号化

      はてなブックマーク - as3cryptoで暗号化
      このエントリーをはてなブックマークに追加

      こんにちは。
      ユニコーン好きのruby使い、ヤマモトです。

      今回は、ActionScriptで暗号化した文字列を、rubyで複合化して受け取る、というのをやります。

      ActionScriptには as3crypto という便利なライブラリが提供されていて、aesやdesなどのアルゴリズムを使用しての暗号化・複合化が可能です。
      code.google.com/p/as3crypto/

      デモページも用意されていて、コードを書く前にあれこれ試すことができます。
      crypto.hurlant.com/demo/

      SecretKeyからデモが行えますが、簡単な説明としては以下のとおりです。

      Encryption : 暗号アルゴリズム選択(AES,3DESなど)
      Mode : 暗号利用モード選択(CBC,CFBなど)
      Padding : 公開鍵暗号技術規格(PKCS#5)

      KeyFormat に秘密鍵を、
      PlainText に変換したい文字列を入力して Encrypto を押すと暗号化された文字列がCipherTextに表示されます。
      このとき、表示モードをText以外にしないと、バイナリデータとして表示されますので、Hex等でシリアライズするのがいいでしょう。

      で、これの実装方法ですが、
      以下の通り書きました。
      前提として、
      秘密鍵 : “hogehoge”
      暗号化する文字列 : “fugafuga”
      暗号アルゴリズム : AES
      暗号利用モード : ECB
      を使用します。

      as側

      public function encrypt(str:String):ByteArray {
      	var e:ByteArray = new ByteArray();
      	var key:ByteArray = Hex.toArray(Hex.fromString("hogehoge"));
      	var src:ByteArray = Hex.toArray(Hex.fromString(str));
      	var pad:IPad = new PKCS5();
      	var cipher:ICipher = Crypto.getCipher("aes-ecb", key, pad);
      	pad.setBlockSize(cipher.getBlockSize());
      	cipher.encrypt(src);
      	e.writeObject(src);
      	return src;
      }

      これで、

      encrypt_data = encrypt("fugafuga")

      で暗号化の文字列がバイナリで返されます。
      これを、Base64コードに変換してXMLにてrubyに渡し、復号化を行ないます。

      rubyではOpenSSL::Cipherクラスを使用して復号化を行ないますが、
      その前に、受け取るデータのデシリアライズをしなくてはいけません。
      as側で、暗号化文字列をBase64コードに変換していましたので、これを元に戻します。

      require 'base64'
      # encrypt_data = 暗号化された文字列
      encrypt_data_byte = decode64(URI.decode(encrypt_data))

      あとは以下の要領で復号化です。

      def decrypt(data, key)
          c = OpenSSL::Cipher::Cipher.new("aes-128-ecb")
          begin
            c.decrypt
            c.key = "hogehoge"
            c.update(data) + c.final
          rescue Error =&gt; e
            logger.error("#{e.message}")
          end
        end
       
      # 復号化された文字列
      decrypt_data = decrypt(encrypt_data_byte)
       
      puts decrypt_data
      ⇒ "fugafuga"

      ロジック中にアルゴリズムや秘密鍵を直接指定していますが、
      そこは定数化などで汎用的にしてください。

      今回は、as・ruby間で行ないましたが、JavaやObjective-Cでも可能です。