暗号と復号のアルゴリズム - 1 / 2 -
BREW の暗号化・復号化アルゴリズム
ICipher と IRSA は、暗号化と復号化のアルゴリズムが実装された BREW インターフェースです。暗号キーは、ハッシュ値を計算する IHash インターフェースを使います。これらのインターフェースは外部サーバと安全に通信したいときなどに便利です。
共通鍵、公開鍵、ハッシュ
共通鍵暗号は、暗号化と復号化で同一の鍵を使う方式です。
公開鍵暗号は、公開されている公開鍵で暗号化されたデータを、非公開の秘密鍵で復号化する方式です。
暗号文の改竄を検出したり、鍵を生成するときにハッシュを使います。
関連情報:" Wikipedia : 暗号 "
アプリの概要
- 最初に、"Push Select Key to test MD5 and ARC4 Push 1 Key to test RSA... " を表示します。
- セレクトキーが押されると、MD5 と ARC4 を使った暗号化と復号化を行い、ログを表示します。
- 「1」キーが押されると、RSA を使った暗号化と復号化を行い、ログを表示します。
準備
アプレット構造体には、IRSA インターフェースのインスタンス変数と暗号化と復号化に使う変数などを追加します。
■アプレット構造体の宣言
typedef struct CipherApp { AEEApplet a; // アプレット構造体の先頭メンバは必ず AEEApplet 型にすること。 Common common; //描画用 IRSA* rsa; // IRSA インターフェースのインスタンス変数 byte source[64]; byte* encode; byte* decode; int size; uint32 result; AEECallback callback; } CipherApp;
MD5 の使用例
ハッシュ値を取るためのアルゴリズムは、BREW に各種用意されています。
MD5、MD2、SHA1、HMAC_MD5、HMAC_MD2、HMAC_SHA1 などです。
今回は MD5 を使ってバッファのハッシュ値を取り、それを ARC4 で使う鍵とします。
最初は MD5 の使用例です。
// MD5 を使って鍵をハッシュ static void ARC4MakeKeyHash(CipherApp* app, const char* key, byte* hashKey) { IShell* shell = app->a.m_pIShell; IHash* hash; char buffer[256]; int keySize = STRLEN(key); int hashSize = MD5_LENGTH; int i; int j; // IHash インスタンス作成 hash = NULL; ISHELL_CreateInstance(shell, AEECLSID_MD5, (void**)&hash); // Hash 実行 IHASH_Update(hash, (byte*)key, keySize); // 結果取得 IHASH_GetResult(hash, hashKey, &hashSize); // 結果表示 i = SPRINTF(buffer, ""); j = 0; while (j < MD5_LENGTH) { i += SPRINTF(buffer + i, "%02x ", hashKey[j++]); } COMMON_WriteString(&app->common, "key source : \""); COMMON_WriteString(&app->common, key); COMMON_WriteString(&app->common, "\"\nkey : "); COMMON_WriteString(&app->common, buffer); COMMON_WriteString(&app->common, "\n"); IHASH_Release(hash); return; }
コードの中央部、IHASH_... から始まる関数が、ハッシュ値を取る例です。
元は文字列ですが、ハッシュ値はバイナリなので、コードではハッシュ値を 16 進数で表示します。
ARC4 の使用例 ( 暗号化 )
共通鍵暗号のアルゴリズムは、ARC4、DES_ENCRYPT、DES_DECRYPT、3DES_ENCRYPT、3DES_DECRYPT があります。
先ほど計算したハッシュ値を鍵にして、ARC4 を使って暗号化します。
// ArcFour ( RC4 互換 ) を使った暗号化 static void ARC4Encrypt(CipherApp *app, const byte* hashKey, const char* source, int size, byte* encode) { IShell* shell = app->a.m_pIShell; ICipher* cipher; int hashSize = MD5_LENGTH; char buffer[256]; int i; int j; // ICipher インターフェイスを作成 cipher = NULL; ISHELL_CreateInstance(shell, AEECLSID_ARC4, (void**)&cipher); // 暗号化で使用する鍵を設定 ICIPHER_Init(cipher, hashKey, hashSize); // 暗号化する前のデータを出力 COMMON_WriteString(&app->common, "source : \""); COMMON_WriteString(&app->common, source); COMMON_WriteString(&app->common, "\"\n"); // 暗号化 ICIPHER_Cipher(cipher, (byte*)source, size, encode, &size); // 暗号化したデータを出力 i = SPRINTF(buffer, ""); j = 0; while (j < size) { i += SPRINTF(buffer + i, "%02x ", encode[j++]); } COMMON_WriteString(&app->common, "encode : "); COMMON_WriteString(&app->common, buffer); COMMON_WriteString(&app->common, "\n"); // ICipher インターフェイス解放 ICIPHER_Release(cipher); return; }
IHash インターフェースと同様、ICipher インターフェースも、プログラマが入力パラメーターで指定したバッファ内に計算結果が書き込まれます。
ARC4 の使用例 ( 復号化 )
暗号化したバッファを復号化してみましょう。
// ArcFour (RC4 互換) を使った復号化 static void ARC4Decrypt(CipherApp *app, const byte* hashKey, const byte* encode, int size) { IShell* shell = app->a.m_pIShell; ICipher* cipher; int hashSize = MD5_LENGTH; byte* decode = (byte*)MALLOC(size); // ICipher インターフェイスを作成 cipher = NULL; ISHELL_CreateInstance(shell, AEECLSID_ARC4, (void**)&cipher); // 復号化で使用する鍵を設定 ICIPHER_Init(cipher, hashKey, hashSize); // 復号化 ICIPHER_Cipher(cipher, encode, size, decode, &size); // 復号化したデータを出力 COMMON_WriteString(&app->common, "decode : "); COMMON_WriteString(&app->common, (char*)decode); COMMON_WriteString(&app->common, "\n"); // バッファ解放 FREE(decode); // ICipher インターフェイス解放 ICIPHER_Release(cipher); return; }
ARC4 は暗号化と同じアルゴリズムで復号化されます。
RSA
RSA は公開鍵方式の暗号アルゴリズムです。
BREW に用意されている RSA アルゴリズムでは、モジュラと呼ばれる数、公開鍵、秘密鍵の 3 つを使い、モジュラと公開鍵を暗号化用、モジュラと秘密鍵を解読用に使います。
モジュラ、公開鍵、秘密鍵のセットは BREW では生成するアルゴリズムが提供されないので、UNIX の openssl コマンドなどを使用して事前に鍵を生成してください。
RSA 使用例(公開鍵を使用した暗号化)
BREW で RSA を使用するには、IRSA インターフェースを使用します。
RSA の暗号化 / 復号化には時間がかかるので、処理はコールバックで行います。
その場で処理をするブロッキングする関数 IRSA_RSA もありますが、非推奨となっています。
// RSA を使った暗号化 static void RSACipher(CipherApp* app) { const unsigned char mod512[] = { 0xA9, 0x59, 0x31, 0x2E, 0xBA, 0x86, 0xDB, 0x0B, 0x2B, 0x98, 0xAE, 0x0A, 0x15, 0x9F, 0xF6, 0x3E, 0x01, 0x77, 0x0D, 0xBC, 0xBB, 0xDA, 0xEA, 0x47, 0xFB, 0x7E, 0xF5, 0xB6, 0xB1, 0xA1, 0xE9, 0xC9, 0x57, 0x9D, 0x2A, 0xBD, 0xA8, 0x46, 0x1C, 0x44, 0x89, 0x3F, 0x52, 0xBD, 0x13, 0x84, 0xE4, 0x37, 0x7C, 0xDD, 0x67, 0x2E, 0xD9, 0xC5, 0x0B, 0xC2, 0xC5, 0x63, 0x6E, 0xC9, 0xEE, 0x5F, 0xE2, 0xBB }; // モジュラ unsigned char publicE = 0x03; // 公開鍵 IShell* shell = app->a.m_pIShell; if (app->rsa == NULL) { COMMON_ClearBuffer(&app->common); COMMON_WriteString(&app->common, "Push Select Key to test MD5 and ARC4\nPush 1 Key to test RSA\n"); COMMON_WriteString(&app->common, "source : \""); COMMON_WriteString(&app->common, (char*)app->source); COMMON_WriteString(&app->common, "\n"); CALLBACK_Init(&app->callback, RSAEncrypt, app); // IRSA インスタンス作成 app->rsa = NULL; ISHELL_CreateInstance(shell, AEECLSID_RSA, (void**)&app->rsa); // 初期化 IRSA_Init(app->rsa, mod512, 64, &publicE, sizeof(publicE)); // 暗号化 IRSA_ModExp(app->rsa, app->source, 64, &app->encode, &app->size, &app->result, &app->callback); // 結果の取得と表示はコールバックを待つ。 } return; }
512 ビットのモジュラと公開鍵で IRSA インターフェースを初期化した後、暗号化します。ここでは 入力文字列の長さに関わらず 64 バイト ( 512 ビット) の入力を渡しています。
モジュラの長さと暗号化する入力の長さは同じでなければなりません。入力が大きすぎる場合は、モジュラの長さで分割して、それぞれを処理する必要があります。短い場合、パディングをいれて処理する関数 IRSA_Encrypt, IRSA_Decrypt も使えます。
上のコードで登録したコールバック関数に、暗号化後の処理を記述します。暗号処理に成功したかどうか等を示すエラーコードが result に代入されています。
ICipher インターフェースと違い、暗号文のバッファは IRSA インターフェースが提供します。IRSA_ModExp 関数には、バッファのポインタを得るため、「バッファへのハンドル」である「バッファのポインタへのポインタ」を渡すところに注意してください。
■暗号化終了時に呼び出されるコールバック関数
// RSA を使った暗号化終了後の処理 static void RSAEncrypt(CipherApp* app) { const unsigned char mod512[] = { 0xA9, 0x59, 0x31, 0x2E, 0xBA, 0x86, 0xDB, 0x0B, 0x2B, 0x98, 0xAE, 0x0A, 0x15, 0x9F, 0xF6, 0x3E, 0x01, 0x77, 0x0D, 0xBC, 0xBB, 0xDA, 0xEA, 0x47, 0xFB, 0x7E, 0xF5, 0xB6, 0xB1, 0xA1, 0xE9, 0xC9, 0x57, 0x9D, 0x2A, 0xBD, 0xA8, 0x46, 0x1C, 0x44, 0x89, 0x3F, 0x52, 0xBD, 0x13, 0x84, 0xE4, 0x37, 0x7C, 0xDD, 0x67, 0x2E, 0xD9, 0xC5, 0x0B, 0xC2, 0xC5, 0x63, 0x6E, 0xC9, 0xEE, 0x5F, 0xE2, 0xBB }; // モジュラ unsigned char exp512[] = { 0x70, 0xE6, 0x20, 0xC9, 0xD1, 0xAF, 0x3C, 0xB2, 0x1D, 0x10, 0x74, 0x06, 0xB9, 0x15, 0x4E, 0xD4, 0x00, 0xFA, 0x09, 0x28, 0x7D, 0x3C, 0x9C, 0x2F, 0xFC, 0xFF, 0x4E, 0x79, 0xCB, 0xC1, 0x46, 0x85, 0x24, 0x2E, 0x9C, 0x9E, 0xBD, 0xBA, 0x97, 0xB0, 0x37, 0xC7, 0x26, 0x6C, 0x41, 0xDB, 0x5B, 0x16, 0xD7, 0xB1, 0x76, 0x03, 0xF0, 0xEA, 0xAF, 0x23, 0xFC, 0x19, 0x82, 0x8E, 0x1E, 0x3A, 0xFA, 0x9B }; // 秘密鍵 char buffer[256]; int i; int j; // 結果表示 i = SPRINTF(buffer, ""); j = 0; while (j < app->size) { SPRINTF(buffer + i, "%02x ", app->encode[j++]); i += 3; } COMMON_WriteString(&app->common, "encode : "); COMMON_WriteString(&app->common, buffer); COMMON_WriteString(&app->common, "\n"); COMMON_Draw(&app->common); //(略) }
RSA 使用例 ( 秘密鍵を使用した復号化 )
コールバック関数の中での復号化処理です。
以下は先のコードの最後の略された部分です。
CALLBACK_Init(&app->callback, RSADecrypt, app); // 再初期化 IRSA_Init(app->rsa, mod512, 64, exp512, 64); // 解読 IRSA_ModExp(app->rsa, app->encode, app->size, &app->decode, &app->size, &app->result, &app->callback); // 結果の取得と表示はコールバックを待つ。 return;
暗号化の処理とほぼ同様ですが、初期化がモジュラと秘密鍵になっています。
■復号化終了時に呼び出されるコールバック関数
// RSA を使った復号化終了後の処理 static void RSADecrypt(CipherApp* app) { // 結果表示 COMMON_WriteString(&app->common, "decode : \""); COMMON_WriteString(&app->common, (char*)app->decode); COMMON_WriteString(&app->common, "\"\n"); // IRSA 解放 IRSA_Release(app->rsa); app->rsa = NULL; COMMON_Draw(&app->common); return; }