ラベル OpenSSL の投稿を表示しています。 すべての投稿を表示
ラベル OpenSSL の投稿を表示しています。 すべての投稿を表示

2013年5月4日土曜日

[OpenSSL]AES コマンド

AES 256 CBC モードで暗号化する手順
$ openssl enc -aes-256-cbc -e -in null.dat -out enc_aes256cbc.dat -p -nosalt
enter aes-256-cbc encryption password:
Verifying - enter aes-256-cbc encryption password:
key=EA703E7AA1EFDA0064EAA507D9E8AB7E63413AFCBF321FFB9618A9336087C322
iv =AD804FC4942C79B8E7A3F5C26B1E599E


復号化する手順
$ openssl enc -aes-256-cbc -d -in enc_aes256cbc.dat -out dec_aes256cbc.dat -p -nosalt
enter aes-256-cbc decryption password:
key=EA703E7AA1EFDA0064EAA507D9E8AB7E63413AFCBF321FFB9618A9336087C322
iv =AD804FC4942C79B8E7A3F5C26B1E599E

br/ Key と IV を生成する方法
passphase = "hoge" から Key と IV を生成する。 passphase から MD5 値をとる。
00 | 68 6F 67 65
-- (MD5) -->
00 | EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E
MD5 を 1 回行った結果に hoge を追加して再び MD5 値をとる。
00 | EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E
10 | 68 6F 67 65
-- (MD5) -->
00 | 63 41 3A FC BF 32 1F FB 96 18 A9 33 60 87 C3 22
その結果に hoge を追加して再び MD5 値をとる。
00 | 63 41 3A FC BF 32 1F FB 96 18 A9 33 60 87 C3 22
10 | 68 6F 67 65
-- (MD5) -->
00 | AD 80 4F C4 94 2C 79 B8 E7 A3 F5 C2 6B 1E 59 9E
以上から 3 つの MD5 値が得られる。
MD5 1回目 EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E
MD5 2回目 63 41 3A FC BF 32 1F FB 96 18 A9 33 60 87 C3 22
MD5 3回目 AD 80 4F C4 94 2C 79 B8 E7 A3 F5 C2 6B 1E 59 9E
1 回目 MD5 値と 2 回目 MD5 値を連結した値が Key となり、3 回目 MD5 値が IV となる。
Key = EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E 63 41 3A FC BF 32 1F FB 96 18 A9 33 60 87 C3 22
IV = AD 80 4F C4 94 2C 79 B8 E7 A3 F5 C2 6B 1E 59 9E


OpenSSL コマンドで passphase に hoge を指定した時の Key と IV
$ openssl enc -aes-256-cbc -e -in null.dat -out enc_aes256cbc.dat -p -pass pass:hoge -nosalt
key=EA703E7AA1EFDA0064EAA507D9E8AB7E63413AFCBF321FFB9618A9336087C322
iv =AD804FC4942C79B8E7A3F5C26B1E599E

[OpenSSL]AES 暗号モード

AES には以下の 4 モードがある。
  • ECB (Electronic Code Block)
  • CBC (Cipher Block Chaining)
  • OFB (Output FeedBack)
  • CFB (Cipher FeedBack)
また鍵長 (Bit 数) が 3 種選べる。
  • 128bit
  • 192bit
  • 256bit
以上から AES のモードには以下のパターンが存在する (表中の文字列は OpenSSL コマンドでAES 暗号を行う場合の引数)
Table: AES モードの組み合わせ
ECBCBCOFBCBB
128bitaes-128-ecbaes-128-cbcaes-128-ofbaes-128-cfb
192bitaes-192-ecbaes-192-cbcaes-192-ofbaes-192-cfb
256bitaes-256-ecbaes-256-cbcaes-256-ofbaes-256-cfb

[OpenSSL]Triple DES

Triple DES EDE CBC モードで暗号化の手順
$ openssl enc -des-ede3-cbc -e -in null.dat -out enc_des_e
de3_cbc.dat -p -nosalt
enter des-ede3-cbc encryption password:
Verifying - enter des-ede3-cbc encryption password:
key=EA703E7AA1EFDA0064EAA507D9E8AB7E63413AFCBF321FFB
iv =9618A9336087C322


復号化の手順
$ openssl enc -des-ede3-cbc -d -in enc_des_ede3_cbc.dat -o
ut dec_des_ede3_cbc.dat -p -nosalt
enter des-ede3-cbc decryption password:
key=EA703E7AA1EFDA0064EAA507D9E8AB7E63413AFCBF321FFB
iv =9618A9336087C322


Key, IV の生成方法
passphase = "hoge" から Key と IV を生成する。 passphase から MD5 値をとる。
00 | 68 6F 67 65
-- (MD5) -->
00 | EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E
MD5 を 1 回行った結果に hoge を追加して再び MD5 値をとる。
00 | EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E
10 | 68 6F 67 65
-- (MD5) -->
00 | 63 41 3A FC BF 32 1F FB 96 18 A9 33 60 87 C3 22
以上から 2 つの MD5 値が得られる。
1 回目 MD5 値 EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E
2 回目 MD5 値 63 41 3A FC BF 32 1F FB 96 18 A9 33 60 87 C3 22
Key は 1 回目 MD5 値に 2 回目 MD5 値の上位 8 バイトをくっつけた値になる。
IV は 2 回目 MD5 値の下位 8 バイトとなる。
Key = EA 70 3E 7A A1 EF DA 00 64 EA A5 07 D9 E8 AB 7E 63 41 3A FC BF 32 1F FB
IV = 96 18 A9 33 60 87 C3 22
passphase に hoge を指定して Triple DES EDE CBC モードを行った結果
$ openssl enc -des-ede3-cbc -e -in null.dat -out enc_des_ede3_cbc.dat -p -nosalt -pass pass:hoge
key=EA703E7AA1EFDA0064EAA507D9E8AB7E63413AFCBF321FFB
iv =9618A9336087C322

[OpenSSL]DES コマンド

暗号化手順
$ openssl des -e -in test.txt -out test_enc_des.txt
enter des-cbc encryption password:
Verifying - enter des-cbc encryption password:
Key と IV を指定する場合
$ openssl enc -des-ecb -e -in null.dat -out null_enc_des.dat -iv 00000000 -K 00000000
Key と IVを表示する
$ openssl des -e -in test.txt -out test.enc -p -nosalt
enter des-cbc encryption password:
Verifying - enter des-cbc encryption password:
key=EA703E7AA1EFDA00
iv =64EAA507D9E8AB7E
Keyを作成するための方法を指示する
$ openssl enc -des-ecb -e -in test.txt -out test.enc -iv 0000000000000000 -p -nosalt -md md5
enter des-ecb encryption password:
Verifying - enter des-ecb encryption password:
key=EA703E7AA1EFDA00
iv =0000000000000000


復号化手順
$ openssl des -d -in test_enc_des.txt -out test_dec_des.txt
enter des-cbc decryption password:
Key と IV (Initial Vector) を指定する場合
$ openssl enc -des-ecb -d -in null_enc_des.dat -out null_dec_des.dat -iv 00000000 -K 00000000


Key, IV の作り方
$ openssl enc -des-ecb -e -in test.txt -out test.enc -p -nosalt
enter des-ecb encryption password:
Verifying - enter des-ecb encryption password:
key=EA703E7AA1EFDA00
iv =64EAA507D9E8AB7E
password を hoge にすると key, iv は以下のようになる
key=EA703E7AA1EFDA00
iv =64EAA507D9E8AB7E
hoge と書いたテキストファイル hoge.txt (末尾に改行なしで保存) を準備して MD5 ダイジェスト値を取ると以下のようになる。
$ openssl dgst -md5 hoge.txt
MD5(hoge.txt)= ea703e7aa1efda0064eaa507d9e8ab7e
MD5 ダイジェスト値の前半が key に該当し、後半が iv に該当する。すなわち
passphase = hoge
hoge -- (MD5) --> ea703e7aa1efda0064eaa507d9e8ab7e
上位8byte = ea703e7aa1efda00 = key
下位8byte = 64eaa507d9e8ab7e = iv

[OpenSSL]DES 暗号モード

DES のモードには以下のパターンが存在する(表中の文字列は OpenSSL コマンドで DES 暗号を行う場合の引数)
Table: DES モードの組み合わせ
ECBCBCCFBOFB
DESdes-ecbdes-cbcdes-cfbdes-ofb
3DES two keydes-ededes-ede-cbcdes-ede-cfbdes-ede-ofb
3DES three keydes-ede3des-ede3-cbcdes-ede3-cfbdes-ede3-cfb

[OpenSSL]DES 暗号

DES には以下の 4 モードがある。
  • ECB (Electronic Code Block)
    • 基本となるモード。
    • 暗号ブロック間の関連性はなく、単に平文をブロックごとに区切り、暗号化する方式。
    • 各ブロックが独立しているので、並列処理が可能で高速。
    • 暗号の強度は低い。
  • CBC (Cipher Block Chaining)
    • 既に暗号化されたデータを利用して次のブロックを暗号化する。
    • 一つ前の平文ブロックの暗号結果(暗号ブロック)と次の平文ブロックをXOR演算子、その結果を暗号化する方式。暗号には、外部から与えた初期ベクトル (Initial Vecotr: IV)を使う。
    • ECB モードよりも暗号強度が高い
  • CFB (Cipher FeedBack)
    • まず最初にIVを暗号化し、それと1番目の平文ブロックとのXOR演算によって1番目の暗号ブロックを生成する。続いて1番目の 暗号ブロックを暗号化し、それと2番目の平文ブロックとのXOR演算によって、2番目の暗号ブロックを生成する。
  • OFB (Output FeedBack)
    • まず最初にIVを暗号化し、それと1番目の平文ブロックとのXOR演算によって1番目の暗号ブロックを生成する。続いて暗号化さ れたIVを更に暗号化し、それと2番目の平文ブロックとのXOR演算によって2番目の暗号化ブロックを生成する。

[OpenSSL]公開鍵暗号方式

RSA (Rivest Shamir Adleman)Ron Rivest, Adi Shamir, LeonardAdleman の三氏によって 1978 年に公開された公開鍵暗号方式。3 人の名前の頭文字をとって RSA と名付けられた。公開鍵暗号方式の標準として広く普及している。桁数の大きな整数の素因数分解が困難であるということを安全性の根拠にしている。1024 ビットの鍵が標準的に使用されていたが、危殆化が懸念されており、2048 ビット以上の鍵への移行が進められている。
楕円曲線暗号 (Elliptic Curve Cryptosystem)楕 円曲線状の離散対数問題 (ECDLP: Elliptic Curve Discrete Logarithm Problem) の難しさを安全性の根拠にする公開鍵暗号化方式。RSA よりも短い鍵長で同程度の暗号強度を実現でき、その分処理が高速に行えるという長所があるが、条件の選び方によっては逆に脆弱になってしまうという欠点も 指摘されている。160 ビットの鍵長で、鍵長 1024 ビットの RSA と同程度の安全性を保つとされている。

[OpenSSL]ブロック暗号方式

DES (Data Enryption Standard)1975年米国商務省標準局 で公表され、1977年以降米国政府の標準として採用された。ブロック長は64ビットで56ビットの鍵を使用する。
3DES (Triple DES)DESを三重に適用するこ とによって強度を高めたもの。
3DES には使用する 2 つの鍵を使用する場合と 3 つの鍵を使用する場合がある
  • 2 つの鍵を使用する場合
    鍵 A で暗号化 → 鍵 B で複合化 → 鍵 A で暗号化
  • 3 つの鍵を使用する場合
    鍵 A で暗号化 → 鍵 B で複合化 → 鍵 C で暗号化
上記の「暗号→復号→暗号」の流れを EDE (Encrypt-Decrypt-Encrypt) という
AES (Advanced Encryption Standard)DESの後継となる米国政府 の標準暗号方式。NIST(米国標準技術 局)の公募で集まった15の方式が審査を受けていたが、ベルギーのJoan Daemen氏とVincent Rijmen氏が開発した「Rijndael」という方式が選ばれた。ブロック長は128ビットで、使用する鍵の長さは128/192/256ビットの中 から選択できる。
IDEA (International Data Encryption Algorithm)スイス工科大学の James L.Massey 氏と Xuejia Lai 氏によって考案された方式。ブロック長は 64 ビットで 128 ビットの鍵を使用する。PGP や SSH などで使用されている。
FEAL (Fast data Enciphement ALgorithm)NTT が開発した方式であり、IC カードや携帯電話などで利用されている。ブロック長は 64 ビットで、64 ビットもしくは 128 ビットの鍵を使用する。
MISTY三菱電機が開発した方式であ り、携帯電話の W-CDMA 用暗号 KASUMI はこれがベースになっている。ブロック長は 64 ビットで 128 ビットの鍵を使用する。
RC2Ron Rivest 氏が開発したブロック暗号方式。ブロック長は 64 ビットえ可変長鍵(最大 128 ビット)を使用する。
RC5Ron Rivest 氏が開発したブロック暗号方式。ブロック長、鍵長ともに可変である。

2013年2月24日日曜日

[OpenSSL]OpenSSL ライブラリを使用したプログラム

テストプログラム
#include <iostream>
#include <iomanip>
#include <openssl/md5.h>
#include <openssl/sha.h>
#include <openssl/des.h>
#include <openssl/aes.h>
using namespace std;
static unsigned char test_data[32]={
        0x37,0x36,0x35,0x34,0x33,0x32,0x31,0x20,
        0x4E,0x6F,0x77,0x20,0x69,0x73,0x20,0x74,
        0x68,0x65,0x20,0x74,0x69,0x6D,0x65,0x20,
        0x66,0x6F,0x72,0x20,0x00,0x00,0x00,0x00,
};
static unsigned char cbc_key [8]={0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef};
static unsigned char cbc_iv [8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};
static unsigned char cbc2_key[8]={0xf1,0xe0,0xd3,0xc2,0xb5,0xa4,0x97,0x86};
static unsigned char cbc3_key[8]={0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10};

/* DES CBC 用 encode 済み確認データ */
static unsigned char cbc_ok[32]={
    0xcc,0xd1,0x73,0xff,0xab,0x20,0x39,0xf4,
    0xac,0xd8,0xae,0xfd,0xdf,0xd8,0xa1,0xeb,
    0x46,0x8e,0x91,0x15,0x78,0x88,0xba,0x68,
    0x1d,0x26,0x93,0x97,0xf7,0xfe,0x62,0xb4
};

/* 3DES CBC 用 encode 済み確認データ */
static unsigned char cbc3_ok[32]={
    0x3F,0xE3,0x01,0xC9,0x62,0xAC,0x01,0xD0,
    0x22,0x13,0x76,0x3C,0x1C,0xBD,0x4C,0xDC,
    0x79,0x96,0x57,0xC0,0x64,0xEC,0xF5,0xD4,
    0x1C,0x67,0x38,0x12,0xCF,0xDE,0x96,0x75
};

static unsigned char aes_cbc_key[] = {
    0x01,0x23,0x45,0x67,0x89,0xab,0xcd,0xef,
    0xfe,0xdc,0xba,0x98,0x76,0x54,0x32,0x10
};

static unsigned char aes_cbc_iv[] = {
    0x23,0x45,0x67,0x89,0xab,0xcd,0xef,0x01,
    0x98,0x76,0x54,0x32,0x10,0xfe,0xdc,0xba
};

/* AES 128 bit CBC 用 encode 済み確認データ */
static unsigned char aes128_cbc_ok[] = {
    0xea,0xca,0xd1,0x95,0xf1,0x00,0xf8,0x77,
    0x5d,0x8b,0xb8,0x2a,0x5e,0xb7,0x04,0xf6,
    0x0f,0x8f,0x2c,0x09,0xaf,0xf6,0x76,0x06,
    0xbd,0x1e,0x19,0xac,0x57,0x68,0xfc,0x2d
};

/**
 * @brief バッファの dump を表示する
 *
 * @param p バッファポインタ
 * @param len バッファ長
 */
static void disp_dump(unsigned char* p, int len)
{
    int i;

    for (i = 0; i < len; i++) {
        cout << hex << setw(2) << setfill('0') << (unsigned int)(*(p + i)) << " ";
        if (((i+1)%16==0) && ((i+1) != len)) {
            cout << endl;
        }
    }
    cout << endl;
    cout << endl;
}

/**
 * @brief MD5 のテスト
 *
 * コマンドラインでの MD5 値を求める方法
 * @code
 * $ openssl dgst -md5 test_data.dat
 * MD5(test_data.dat)= c7e05d2749805b61e43ddf7a4e73aa3d
 * @endcode
 *
 * @retval 0
 */
static int digest_md5_test(void)
{
    MD5_CTX ctx;
    unsigned char md[MD5_DIGEST_LENGTH];

    cout << "Digest MD5" << endl;
    MD5_Init(&ctx);
    MD5_Update(&ctx, test_data, sizeof(test_data));
    MD5_Final(md, &ctx);
    disp_dump(md, sizeof(md));

    return 0;
}

/**
 * @brief SHA1 のテスト
 *
 * コマンドラインでの SHA1 値を求める方法
 * @code
 * $ openssl dgst -sha1 test_data.dat
 * SHA1(test_data.dat)= 3f115bbb9bc96fed0fe2b5b3f2a50442203d3599
 * @endcode
 *
 * @retval 0
 */
static int digest_sha1_test(void)
{
    SHA_CTX ctx;
    unsigned char sha[SHA_DIGEST_LENGTH];

    cout << "Digest SHA1" << endl;
    SHA1_Init(&ctx);
    SHA1_Update(&ctx, test_data, sizeof(test_data));
    SHA1_Final(sha, &ctx);
    disp_dump(sha, sizeof(sha));

    return 0;
}

/**
 * @brief DES CBC モードのテスト
 *
 * コマンドラインでのエンコード * @code
 * $ openssl enc -des-cbc -e -in test_data.dat -out enc.out
 * -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
 * key=0123456789ABCDEF
 * iv =FEDCBA9876543210
 * @endcode
 *
 * コマンドラインでのデコード
 * @code
 * $ openssl enc -des-cbc -d -in enc.out -out dec.out
 * -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
 * key=0123456789ABCDEF
 * iv =FEDCBA9876543210
 * @endcode
 *
 * @retval 0
 */
static int enc_des_cbc_test(void)
{
    int i;

    unsigned char des_enc[32];
    unsigned char des_dec[32];
    DES_cblock iv3;
    des_key_schedule schedule;

    memset(des_enc, 0, sizeof(des_enc));
    memset(des_dec, 0, sizeof(des_dec));

    /*** 暗号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule);
    if (i != 0) {
        cout << "Key error " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Encode */
    cout << "DES CBC encrypt" << endl;
    des_ncbc_encrypt((const unsigned char*)test_data, des_enc, sizeof(test_data), schedule, &iv3, DES_ENCRYPT);
    if (memcmp(des_enc, cbc_ok, sizeof(cbc_ok)) != 0) {
        cout << "cbc_encrypt encrypt error" << endl;
    }
    disp_dump(des_enc, sizeof(des_enc));

    /*** 復号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule);
    if (i != 0) {
        cout << "Key error " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Decode */
    cout << "DES CBC decrypt" << endl;
    des_ncbc_encrypt((const unsigned char*)des_enc, des_dec, sizeof(test_data), schedule, &iv3, DES_DECRYPT);
    if (memcmp(des_dec, test_data, sizeof(test_data)) != 0) {
        cout << "cbc_encrypt decrypt error" << endl;
    }
    disp_dump(des_dec, sizeof(des_dec));

    return 0;
}

/**
 * @brief 3DES CBC モードのテスト
 *
 * コマンドラインでのエンコード
 * @code
 * $ openssl enc -des-ede3-cbc -e -in test_data.dat -out enc.out -p -nosalt
 * -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
 * key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
 * iv =FEDCBA9876543210
 * @endcode
 * * コマンドラインでのデコード
 * @code
 * $ openssl enc -des-ede3-cbc -d -in enc.out -out dec.out -p -nosalt
 * -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
 * key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
 * iv =FEDCBA9876543210
 * @endcode
 *
 * @retval 0
 */
static int enc_3des_cbc_test(void)
{
    int i;
    unsigned char des_enc[32];
    unsigned char des_dec[32];
    DES_cblock iv3;
    des_key_schedule schedule1, schedule2, schedule3;

    memset(des_enc, 0, sizeof(des_enc));
    memset(des_dec, 0, sizeof(des_dec));

    /*** 暗号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule1);
    if (i != 0) {
        cout << "Key error (1) " << i << endl;
    }
    i = DES_set_key_checked(&cbc2_key, &schedule2);
    if (i != 0) {
        cout << "Key error (2) " << i << endl;
    }
    i = DES_set_key_checked(&cbc3_key, &schedule3);
    if (i != 0) {
        cout << "Key error (3) " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Encode */
    cout << "3DES CBC encrypt" << endl;
    des_ede3_cbc_encrypt((const unsigned char*)test_data, des_enc, sizeof(test_data), schedule1, schedule2, schedule3, &iv3, DES_ENCRYPT);
    if (memcmp(des_enc, cbc3_ok, sizeof(cbc3_ok)) != 0) {
        cout << "des_ede3_cbc_encrypt encrypt error" << endl;
    }
    disp_dump(des_enc, sizeof(des_enc));

    /*** 復号化 ***/
    /* Key schedule 作成 */
    i = DES_set_key_checked(&cbc_key, &schedule1);
    if (i != 0) {
        cout << "Key error (1) " << i << endl;
    }
    i = DES_set_key_checked(&cbc2_key, &schedule2);
    if (i != 0) {
        cout << "Key error (2) " << i << endl;
    }
    i = DES_set_key_checked(&cbc3_key, &schedule3);
    if (i != 0) {
        cout << "Key error (3) " << i << endl;
    }

    /* IV 準備 */
    memcpy(&iv3, cbc_iv, sizeof(cbc_iv));

    /* Decode */
    cout << "3DES CBC decrypt" << endl;
    des_ede3_cbc_encrypt((const unsigned char*)des_enc, des_dec, sizeof(des_enc), schedule1, schedule2, schedule3, &iv3, DES_DECRYPT);
    if (memcmp(des_dec, test_data, sizeof(test_data)) != 0) {
        cout << "des_ede3_cbc_encrypt encrypt error" << endl;
    }
    disp_dump(des_dec, sizeof(des_dec));

    return 0;
}

/**
 * @brief AES 128bit CBC モードのテスト
 *
 * コマンドラインでのエンコード
 * @code
 * $ openssl enc -aes-128-cbc -e -in test_data.dat -out enc.out -p -nosalt
 * -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
 * key=0123456789ABCDEFFEDCBA9876543210
 * iv =23456789ABCDEF019876543210FEDCBA
 * @endcode
 * * コマンドラインでのデコード
 * @code
 * $ openssl enc -aes-128-cbc -d -in enc.out -out dec.out -p -nosalt
 * -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
 * key=0123456789ABCDEFFEDCBA9876543210
 * iv =23456789ABCDEF019876543210FEDCBA
 * @endcode
 *
 * @retval 0
 */
static int enc_aes128_cbc_test(void)
{
    int i;
    unsigned char aes_enc[32];
    unsigned char aes_dec[32];
    AES_KEY key;
    unsigned char iv[AES_BLOCK_SIZE];

    memset(aes_enc, 0, sizeof(aes_enc));
    memset(aes_dec, 0, sizeof(aes_dec));

    /*** 暗号化 ***/
    /* AES Key 作成 */
    i = AES_set_encrypt_key(aes_cbc_key, 128, &key);

    /* IV 準備 */
    memcpy(iv, aes_cbc_iv, sizeof(aes_cbc_iv));

    /* Encode */
    cout << "AES 128 CBC encrypt" << endl;
    AES_cbc_encrypt((const unsigned char*)test_data, aes_enc, sizeof(test_data), &key, iv, AES_ENCRYPT);
    if (memcmp(aes_enc, aes128_cbc_ok, sizeof(aes128_cbc_ok)) != 0) {
        cout << "AES_cbc_encrypt encrypt error" << endl;
    }
    disp_dump(aes_enc, sizeof(aes_enc));

    /*** 復号化 ***/
    /* AES Key 作成 */
    i = AES_set_decrypt_key(aes_cbc_key, 128, &key);

    /* IV 準備 */
    memcpy(iv, aes_cbc_iv, sizeof(aes_cbc_iv));

    /* Decode */
    cout << "AES 128 CBC decrypt" << endl;
    AES_cbc_encrypt((const unsigned char*)aes_enc, aes_dec, sizeof(aes_enc), &key, iv, AES_DECRYPT);
    if (memcmp(aes_dec, test_data, sizeof(test_data)) != 0) {
        cout << "AES_cbc_encrypt decrypt error" << endl;
    }
    disp_dump(aes_dec, sizeof(aes_dec));

    return 0;
}

int main(void)
{
    digest_md5_test();
    digest_sha1_test();
    enc_des_cbc_test();
    enc_3des_cbc_test();
    enc_aes128_cbc_test();

    return 0;
}

コンパイル
$ g++ openssl_test.cpp -o openssl_test.out -lssl -Wall

実行結果
$ ./openssl_test.out
Digest MD5
c7 e0 5d 27 49 80 5b 61 e4 3d df 7a 4e 73 aa 3d
Digest SHA1
3f 11 5b bb 9b c9 6f ed 0f e2 b5 b3 f2 a5 04 42
20 3d 35 99
DES CBC encrypt
cc d1 73 ff ab 20 39 f4 ac d8 ae fd df d8 a1 eb
46 8e 91 15 78 88 ba 68 1d 26 93 97 f7 fe 62 b4
DES CBC decrypt
37 36 35 34 33 32 31 20 4e 6f 77 20 69 73 20 74
68 65 20 74 69 6d 65 20 66 6f 72 20 00 00 00 00
3DES CBC encrypt
3f e3 01 c9 62 ac 01 d0 22 13 76 3c 1c bd 4c dc
79 96 57 c0 64 ec f5 d4 1c 67 38 12 cf de 96 75
3DES CBC decrypt
37 36 35 34 33 32 31 20 4e 6f 77 20 69 73 20 74
68 65 20 74 69 6d 65 20 66 6f 72 20 00 00 00 00
AES 128 CBC encrypt
ea ca d1 95 f1 00 f8 77 5d 8b b8 2a 5e b7 04 f6
0f 8f 2c 09 af f6 76 06 bd 1e 19 ac 57 68 fc 2d
AES 128 CBC decrypt
37 36 35 34 33 32 31 20 4e 6f 77 20 69 73 20 74
68 65 20 74 69 6d 65 20 66 6f 72 20 00 00 00 00

openssl コマンドを使った場合の結 果
上記プログラム中の test_data[] と同じ内容のバイナリデータ (test_data.dat) を準備して openssl コマンドで結果を確認
  • hash
    $ openssl dgst -md5 test_data.dat
    MD5(test_data.dat)= c7e05d2749805b61e43ddf7a4e73aa3d
    $ openssl dgst -sha1 test_data.dat
    SHA1(test_data.dat)= 3f115bbb9bc96fed0fe2b5b3f2a50442203d3599
      
  • DES CBC による暗号化
    $ openssl enc -des-cbc -e -in test_data.dat -out enc.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
    key=0123456789ABCDEF
    iv =FEDCBA9876543210
      
  • DES CBC による復号化
    $ openssl enc -des-cbc -d -in enc.out -out dec.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdef -nopad
    key=0123456789ABCDEF
    iv =FEDCBA9876543210
      
  • 3DES CBC による暗号化
    $ openssl enc -des-ede3-cbc -e -in test_data.dat -out enc.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
    key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
    iv =FEDCBA9876543210
      
  • 3DES CBC による複合化
    $ openssl enc -des-ede3-cbc -d -in enc.out -out dec.out -p -nosalt -iv fedcba9876543210 -K 0123456789abcdeff1e0d3c2b5a49786fedcba9876543210 -nopad
    key=0123456789ABCDEFF1E0D3C2B5A49786FEDCBA9876543210
    iv =FEDCBA9876543210
      
  • AES 128bit CBC による暗号化
    $ openssl enc -aes-128-cbc -e -in test_data.dat -out enc.out -p -nosalt -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
    key=0123456789ABCDEFFEDCBA9876543210
    iv =23456789ABCDEF019876543210FEDCBA
      
  • AES 128bit CBC による復号化
    $ openssl enc -aes-128-cbc -d -in enc.out -out dec.out -p -nosalt -iv 23456789abcdef019876543210fedcba -K 0123456789abcdeffedcba9876543210 -nopad
    key=0123456789ABCDEFFEDCBA9876543210
    iv =23456789ABCDEF019876543210FEDCBA
      

[OpenSSL]証明書生成

作成した RSA 秘密鍵を使って証明書を生成する。証明書には RSA 公開鍵が埋め込まれる。
$ openssl req -new -x509 -out test.crt -key privateKeyRsa.pem
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Tokyo
Locality Name (eg, city) [Default City]:
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:
$ openssl x509 -text -noout -in test.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
ac:4e:6d:50:42:99:af:85
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=JP, ST=Tokyo, L=Default City, O=Default Company Ltd
Validity
Not Before: Dec 29 22:06:28 2010 GMT
Not After : Jan 28 22:06:28 2011 GMT
Subject: C=JP, ST=Tokyo, L=Default City, O=Default Company Ltd
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (512 bit)
Modulus:
00:ef:8a:45:1b:c9:08:b6:c2:c6:f2:3c:e1:d0:2c:
80:17:08:ce:03:df:e1:62:3e:fa:c5:c7:c7:40:fd:
63:7a:bd:dc:02:b9:dd:dd:e6:ae:b4:b4:e9:70:b7:
23:c7:d8:5c:68:2c:14:f5:46:31:a0:8c:dd:1a:94:
f0:58:e6:f8:95
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Subject Key Identifier:
32:D1:27:F9:75:5F:5E:F4:66:2A:9E:73:B4:D1:2F:BB:AF:A7:02:1E
X509v3 Authority Key Identifier:
keyid:32:D1:27:F9:75:5F:5E:F4:66:2A:9E:73:B4:D1:2F:BB:AF:A7:02:1E
X509v3 Basic Constraints:
CA:TRUE
Signature Algorithm: sha1WithRSAEncryption
db:47:d6:7f:4e:b0:56:11:52:0d:c7:e9:be:d7:b9:7a:a5:51:
8e:ef:b8:cc:2d:53:d1:62:4a:82:5a:83:87:e6:14:9a:e9:65:
82:62:9e:52:02:a8:f2:d9:b0:5e:88:dc:c4:c9:d3:61:4e:07:
22:bc:af:4e:e6:d9:6b:eb:38:10

[OpenSSL]秘密鍵生成

DH 秘密鍵の生成 (512 bit)
$ openssl dhparam 512 -out privateKeyDh.pem
Generating DH parameters, 512 bit long safe prime, generator 2
This is going to take a long time
.....................................+...........+......+......+....................++*++*++*++*++*++*
$ cat privateKeyDh.pem
-----BEGIN DH PARAMETERS-----
MEYCQQCb3DR4LDwxIb1TNVyFQ055HjEBxEigm62Let76yVJQE1hSxo1+dTWcKEEc
N4EMbJZXdMZN+RM4rieozLPvQzGzAgEC
-----END DH PARAMETERS-----

RSA 秘密鍵生成
$ openssl genrsa -out privateKey.pem
Generating RSA private key, 512 bit long modulus
...++++++++++++
....................++++++++++++
e is 65537 (0x10001)
$ cat privateKey.pem
-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBANKkXr0Ub2qwhK0s/Wor7lq5kGsOFwYxXSURgeicbI4F7GcCWyaU
60l7JjvM+d0n8piF70fuv5twxVf7ktEdsyECAwEAAQJAPCK9AVISNO1ME3yipGsC
U1hiyI1vOU9ifjCvW888lpbJvPVbikS26kuHWMcFxHO4y59mNOodZQYHP8+6yR1h
WQIhAOlu4rwQxrPIeTZemzs977Y8+UxgEy6dp81SCcij+ap3AiEA5wFwpHswhfIZ
6eTu/mrEkvMYJUu8VrAvh4AWsnB03ScCIGJV6/39szcZRLa6s/oI5WqH1R1ve6Uv
lPjRjn2PViWRAiEAjUngL3n5T7OoDdqsIogC+y4cEpOj+hGAwIujVjhaAfkCIBEQ
9hTyf0rqTJa7+0IT1WoBpRkPrLCZdU7wiWy/5ZdM
-----END RSA PRIVATE KEY-----

作成した RSA 秘密鍵から RSA 公開鍵を生成
$ openssl rsa -in privateKeyRsa.pem -pubout -out publicKeyRsa.pem
writing RSA key
$ openssl rsa -in publicKeyRsa.pem -pubin -text
Public-Key: (512 bit)
Modulus:
00:ef:8a:45:1b:c9:08:b6:c2:c6:f2:3c:e1:d0:2c:
80:17:08:ce:03:df:e1:62:3e:fa:c5:c7:c7:40:fd:
63:7a:bd:dc:02:b9:dd:dd:e6:ae:b4:b4:e9:70:b7:
23:c7:d8:5c:68:2c:14:f5:46:31:a0:8c:dd:1a:94:
f0:58:e6:f8:95
Exponent: 65537 (0x10001)
writing RSA key
-----BEGIN PUBLIC KEY-----
MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAO+KRRvJCLbCxvI84dAsgBcIzgPf4WI+
+sXHx0D9Y3q93AK53d3mrrS06XC3I8fYXGgsFPVGMaCM3RqU8Fjm+JUCAwEAAQ==
-----END PUBLIC KEY-----

[OpenSSL]RSA 公開鍵/秘密鍵で暗号化/復号化

公開鍵 (publicKeyRsa.pem) を使ってテキストファイルを暗号化する。
$ cat plain.txt
Hello, world
$ openssl rsautl -pubin -inkey publicKeyRsa.pem -in plain.txt -encrypt -out enc.dat
$ od -x enc.dat
0000000 013d 7976 bbe6 506b 3da5 a2ac 57f0 db18
0000020 6a75 afa3 0efa 0cee d4a4 4729 4285 d25b
0000040 4c17 66f0 1a98 d027 c950 640e 824d 8c43
0000060 d05b 4a82 badd 36f1 90eb c284 3707 5277
0000100

暗号化に使った公開鍵 (publicKeyRsa.pem) と対になる秘密鍵 (privateKeyRsa.pem) を使って暗号化されたファイル (enc.dat) を復号化する。
$ openssl rsautl -inkey privateKeyRsa.pem -in enc.dat -decrypt -out dec.dat
$ cat dec.dat
Hello, world

[OpenSSL]HMAC_SHA256_BASE64 を使う

OpenSSL の crypto ライブラリにある hmac と base64 を使って HMAC_SHA256_BASE64 を実行する
Example: hmac_sha256_base64.c
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
#include <openssl/md5.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
/**
 ***********************************************************************
 * @brief バッファの内容を HEX で表示
 *
 * @param[in] buff 表示するバッファのポインタ
 * @param[in] length バッファ長
 ***********************************************************************
 */
static void printDump(const unsigned char *buff, int length)
{
    int i;

    for (i = 0; i < length; i++) {
        printf("%02x", (buff[i] & 0x000000ff));
        if ((i + 1) % 16 == 0) {
            printf("\n");
        }
        else {
            printf(" ");
        }
    }
    printf("\n\n");
}

/**
 ***********************************************************************
 * @brief バッファの内容を文字列で表示
 *
 * @param[in] buff 表示するバッファのポインタ
 * @param[in] length バッファ長
 ***********************************************************************
 */
static void printChar(const unsigned char *buff, int length)
{
    int i;

    for (i = 0; i < length; i++) {
        printf("%c", buff[i]);
    }
    printf("\n\n");
}

/**
 ***********************************************************************
 * @brief BASE64 encode をする
 *
 * @param[in] buff Encode 対象バッファ
 * @param[in] length バッファ長
 ***********************************************************************
 */
static void base64(const unsigned char *input, int length)
{
    BIO *bmem, *b64;
    BUF_MEM *bptr;

    b64 = BIO_new(BIO_f_base64());
    bmem = BIO_new(BIO_s_mem());
    b64 = BIO_push(b64, bmem);
    BIO_write(b64, input, length);
    BIO_flush(b64);
    BIO_get_mem_ptr(b64, &bptr);

    printf("Base64 output:\n");
    printDump(bptr->data, bptr->length);
    printf("Base64 output(char):\n");
    printChar(bptr->data, bptr->length);
    BIO_free_all(b64);
}
/**
 ***********************************************************************
 * @brief hmac_sha256_base64.c のメイン関数
 *
 * @retval 0 正常終了
 ***********************************************************************
 */
int main(void)
{
    const char key[] = "0123456789";
    const char data[] = "abcdefghijklmnopqrstuvwxyz";
    char out[EVP_MAX_MD_SIZE];
    int key_len, data_len, out_len;

    key_len = strlen(key);
    data_len = strlen(data);
    HMAC(EVP_sha256(), key, key_len, data, data_len, out, &out_len);

    printf("hmac_sha256 output:\n");
    printDump(out, out_len);
    base64(out, out_len);

    return 0;
}

crypto ライブラリをリンクするには gdi32 ライブラリが必要となる
Example: Makefile
CC = gcc
CFLAGS = -Wall
# rand_win.c で使われている CreateDCA, GetDeviceCaps などをリンクするために gdi32 ライブラリが必要
LDFLAGS = -lcrypto -lgdi32
TARGET = \
    hmac_sha256_base64.exe

.SUFFIXES: .exe .c .o

.c.o:
    $(CC) $(CFLAGS) -c -o $@ $<

.o.exe:
    $(CC) -o $@ $< $(LDFLAGS)

default: $(TARGET)

clean:
    rm -rf *.o *.exe

実行結果
> hmac_sha256_base64.exe
hmac_sha256 output:
c3 11 d8 1f d6 71 5e 27 b0 e3 87 7e b9 79 13 c3
1b 6a 7f 41 53 ad e5 2c 7a 42 1c d7 5e 7e 7c 65
Base64 output:
77 78 48 59 48 39 5a 78 58 69 65 77 34 34 64 2b
75 58 6b 54 77 78 74 71 66 30 46 54 72 65 55 73
65 6b 49 63 31 31 35 2b 66 47 55 3d 0a
Base64 output(char):
wxHYH9ZxXiew44d+uXkTwxtqf0FTreUsekIc115+fGU=

[OpenSSL]MinGW でコンパイル

  1. OpenSSL: The Open Source toolkit for SSL/TLS から openssl-0.9.8k.tar.gz (2009/10/14 現在) をダウンロードする
  2. Perl も必要となるので perl.exe のある PATH も通しておく
    > path=C:\usr\MinGW\bin;C:\usr\msys\bin;C:\usr\Perl\bin
      
  3. コンパイル
    1. util/pl/Mingw32.pl にある以下の箇所をコメントアウトする
      $cp='copy';
      $rm='del';
      $ret.="\tif exist $target \$(RM) $target\n";
          
    2. コンパイル実行
      > ms/mingw32.bat
          
  4. Install
    1. outinc にある openssl フォルダを c:\usr\MinGW\include へコピー
    2. out\openssl.exe を c:\usr\MinGW\bin へコピー
    3. out\libssl.a, out\libcrypto.a を c:\usr\MinGW\lib へコピー
      > cp -r outinc\openssl c:\usr\MinGW\include
      > cp out\openssl.exe c:\usr\MinGW\bin
      > cp out\libssl.a out\libcrypto.a c:\usr\MinGW\lib
          

[OpenSSL]Hash

MD5
$ openssl dgst -md5 test.txt
MD5(test.txt)= 56130e4a58c1a1dff5fa92325e843fed
結果をバイナリ出力
$ openssl dgst -md5 -binary test.txt > test_md5.dat

SHA1
$ openssl dgst -sha1 test.txt
SHA1(test.txt)= f479d393efe0776a65b9523319422e0a3dfc9baf