2012-01-04 13 views
2

私はPython(Google App Engine)からいくつかのデータを暗号化し、iOSで解読しようとしています。Google App Engine(Python)のAES暗号化とiOS(Objective-C)の復号化

これを取り巻くいくつかの問題は、AES暗号化では非常に多くのオプションがあり、PythonとObjective-Cではさまざまなフォーマットが利用できるという事実に基づいています。

Google App EngineのPyCryptoライブラリと、PKCS7Paddingを必要とするiOS/Objective-C側のAESコードの利用が限られているため、Python側でslowAESを使用することに決めました。

私は16ビットキー、CBCモード、PKCS7Paddingも使用しています。 Pythonの側で、私はデータを符号化、その後BASE64梱包、暗号化、および午前こと

def str2nums(s): 
    return map(ord, s) 

key = "hjt4mndfy234n5fs" 
moo = aes.AESModeOfOperation() 
iv = [12, 34, 96, 15] * 4 
CBC_mode = moo.modeOfOperation['CBC'] 
nkey = str2nums(key) 


def encrypt(plaintext): 
    funcName = inspect.stack()[0][3] 
    logging.debug("Enter " + funcName) 
    logging.debug("Input string: " + plaintext) 
    m, s, encData = moo.encrypt(plaintext, CBC_mode, nkey, len(nkey), iv) 
    fmt = len(encData)*'B' 
    dataAsStr = "" 
    for j in encData: 
     dataAsStr = dataAsStr + str(j) + "," 
    logging.debug("Output encrypted data:[" + dataAsStr + "]") 
    encoded = base64.b64encode(struct.pack(fmt, *encData)) 
    logging.debug("Output encrypted string: " + encoded) 
    decoded = struct.unpack(fmt, base64.b64decode(encoded)) 
    decrypted = moo.decrypt(decoded, s, CBC_mode, nkey, len(nkey), iv) 
    logging.debug("Output decrypted back: " + decrypted) 
    return encoded 

注:ことを考えると

が、これは私の暗号化機能とヘルパー変数/関数です。この暗号化されたデータを返す前に、私はまた、ログにそれが実際に動作することを示すために、復号化時にテストを実行しています。そのように/パック/暗号化されたデータを

- (NSData *)AES128DecryptWithKey:(NSString *)key { 
    // 'key' should be 16 bytes for AES128, will be null-padded otherwise 
    char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused) 
    bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding) 

    // fetch key data 
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSASCIIStringEncoding]; 

    NSUInteger dataLength = [self length]; 

    //See the doc: For block ciphers, the output size will always be less than or 
    //equal to the input size plus the size of one block. 
    //That's why we need to add the size of one block here 
    size_t bufferSize = dataLength + kCCBlockSizeAES128; 
    void *buffer = malloc(bufferSize); 

    size_t numBytesDecrypted = 0; 
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding, 
              keyPtr, kCCKeySizeAES128, 
              NULL /* initialization vector (optional) */, 
              [self bytes], dataLength, /* input */ 
              buffer, bufferSize, /* output */ 
              &numBytesDecrypted); 

    if (cryptStatus == kCCSuccess) { 
     //the returned NSData takes ownership of the buffer and will free it on deallocation 
     return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted]; 
    } 

    free(buffer); //free the buffer; 
    return nil; 
} 

そして、私はBASE64をプルダウンするとき、私はこれを利用しています:iOSの側では

、私は次のAES NSDataの加算を使用してい

NSMutableString * result = [[NSMutableString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding]; 
if (LOG) { NSLog(@"Base64 encoded/Encrypted string: %@", result); } 

NSData* encryptedData = [NSData decodeBase64ForString:result]; // base64 decode 

if (LOG) { NSLog(@"Encrypted string: %@", encryptedData); } 

NSData* decryptedData = [encryptedData AES128DecryptWithKey:@"hjt4mndfy234n5fs"]; // AES Decrypt 

問題は、サーバー上で(Pythonで)復号化しても、クライアント(iOS)側でデータを正しく復号化できないようです。

復号化中、cryptStatusは常に終了します。kCCAlignmentError。私はそれほど理解していません。

私はAES 256を使いこなしましたが、私は思うに32ビットのキーが必要です。それはCBCモードのslowAESのオプションではないようです(少なくとも例によると?)。 。。クライアント(iOS版)の

サーバーのログが(実際の暗号化されていないデータは、単に空のセット[]であることに注意してクライアントに返すために、このようなのJSON表現です

2012-01-04 08:48:13.962 
Enter encrypt 
D 2012-01-04 08:48:13.962 
Input string: [] 
D 2012-01-04 08:48:13.967 
Output encrypted data:[4,254,226,26,101,240,22,113,44,54,209,203,233,64,208,255,] 
D 2012-01-04 08:48:13.967 
Output encrypted string: BP7iGmXwFnEsNtHL6UDQ/w== 
D 2012-01-04 08:48:13.971 
Output decrypted back: [] 

ロギング:

2012-01-04 12:45:13.891 Base64 encoded/Encrypted string: BP7iGmXwFnEsNtHL6UDQ/w== 
2012-01-04 12:45:13.892 Encrypted string: <04fee21a 65f01671 2c36d1cb e940d0ff> 
2012-01-04 12:45:29.126 Decrypted string: 

だから私の質問は以下のとおりです。

  1. それが「アラインメントエラー」によって何を意味するのか、私が間違って何をやっています?それはクライアントで復号化したくないということですか?
  2. データの展開を心配する必要はありませんか?もしそうなら、CやObjective-Cのunpack()関数についてどうすればよいでしょうか?
  3. Google App EngineとiOSの間でAES暗号化を行うより良い方法はありますか?

編集:同じ初期化ベクトルを使用する答えの他に、pythonとパッドのiOSコードの間に矛盾があることがわかりました。暗号化/復号化は少量のデータに対してはうまく機能しましたが、大きなものでは復号化に失敗しました。私は、iOS側をPKCS7Paddingを使用しないように変更し、代わりに0を設定することでこれを修正しました。

+0

暗号化した後、パッキング/エンコードする前にデータのビューをキャプチャし、電話機側でデコードするようにしてください。また、「梱包」とは何を意味するのかを明確にしてください。通常、暗号化されたデータを処理する用語ではありません。 –

+0

私はパッキングと言うとき、私は示されているpythonコードで使用されているstruct.pack()関数を参照しています。 – valheru

+0

これは何ですか? –

答えて

0

IVは両端で一致する必要があります。

IV(初期化ベクトル)は、「実」データが送信される前に、擬似ランダム状態に「メモリ」を置くために暗号化/復号化器を介して送信されるバイト列です。暗号化の結果は以前に何が行われたかに依存するため、この初期化によって、悪意のある第三者に対して、(クリアテキストなしで)指定されたクリアテキストとキーが所定のサイテキストを生成できたかどうかを知ることが不可能になります。

理想的には、IVは、おそらく、シリアル番号またはサイファーテキストと一緒に送信される他のテキストや、両端で同期されたカウンタに基づいて、何らかの形で可変です。

IVの存在は(半予測可能であっても)「既知のクリアテキスト」攻撃を使用する難しさを大幅に増加させます。これは、比較的短く頻繁なメッセージに対して特に重要です。

+2

IVは完全にランダムでなければなりません。あなたの2番目のパラグラフが暗示するように、どちらも秘密にするつもりはありません。 –

+0

問題はIVを「無作為」にすることですが、もう一方の側では予測可能です。これは、IVが暗号文と共に送信されない限り、ある程度まで決定論的でなければならないことを意味する。そして、私はIVが秘密であることを意図していたとは言わなかった。それを知らずに基本的な平文攻撃スキームは本質的に不可能になっているということだけである。 –

+1

暗号文を使ってIVを送信することは、これを行うための標準的な方法です。 IVを知らない攻撃者は、誰の脅威モデルの一部であってはならない。 –