wolfCryptの使用法
wolfCryptは、主にwolfSSLが使用する暗号ライブラリです。 速度、小さなフットプリント、移植性のために最適化されています。 wolfSSLは、必要に応じて他の暗号ライブラリと交換します。
実装例で使用する型は次の通りです。
typedef unsigned char byte;
typedef unsigned int word32;
ハッシュ関数
MD4
注意:MD4は古く、安全でないと考えられています。 可能であれば、異なるハッシュ関数を使用してください。
MD4を使用するには、MD4ヘッダーwolfssl/wolfcrypt/md4.hをインクルードします。
使用する構造体はMd4で、これはtypedefです。
使用する前に、wc_InitMd4()を実行してハッシュの初期化を行う必要があります。
ハッシュを更新するにはwc_Md4Update()を使用し、最終的なハッシュを取得するにはwc_Md4Final()を使用します。
byte md4sum[MD4_DIGEST_SIZE];
byte buffer[1024];
/* fill buffer with data to hash*/
Md4 md4;
wc_InitMd4(&md4);
wc_Md4Update(&md4, buffer, sizeof(buffer)); /*can be called again
and again*/
wc_Md4Final(&md4, md4sum);
md4sumには、bufferのハッシュ化されたデータのダイジェストが含まれます。
MD5
注意:MD5は古く、安全でないと考えられています。 可能であれば、異なるハッシュ関数を使用してください。
MD5を使用するには、MD5ヘッダーwolfssl/wolfcrypt/md5.hをインクルードします。
使用する構造体はMd5で、これはtypedefです。
使用する前に、wc_InitMd5()を実行してハッシュの初期化を行う必要があります。
ハッシュを更新するにはwc_Md5Update()を使用し、最終的なハッシュを取得するにはwc_Md5Final()を使用します。
byte md5sum[MD5_DIGEST_SIZE];
byte buffer[1024];
/*fill buffer with data to hash*/
Md5 md5;
wc_InitMd5(&md5);
wc_Md5Update(&md5, buffer, sizeof(buffer)); /*can be called again
and again*/
wc_Md5Final(&md5, md5sum);
md5sumには、bufferのハッシュ化されたデータのダイジェストが含まれます。
SHA / SHA-224 / SHA-256 / SHA-384 / SHA-512
SHAを使用するには、SHAヘッダーwolfssl/wolfcrypt/sha.hをインクルードします。
使用する構造体はShaで、これはtypedefです。
使用する前に、wc_InitSha()を実行してハッシュの初期化を行う必要があります。
ハッシュを更新するにはwc_ShaUpdate()を使用し、最終的なハッシュを取得するにはwc_ShaFinal()を使用します。
byte shaSum[SHA_DIGEST_SIZE];
byte buffer[1024];
/*fill buffer with data to hash*/
Sha sha;
wc_InitSha(&sha);
wc_ShaUpdate(&sha, buffer, sizeof(buffer)); /*can be called again
and again*/
wc_ShaFinal(&sha, shaSum);
shaSumには、bufferのハッシュ化されたデータのダイジェストが含まれます。
SHA-224、SHA-256、SHA-384、SHA-512のいずれかを使用するには、上記と同じ手順に従います。
ただし、wolfssl/wolfcrypt/sha256.hまたはwolfssl/wolfcrypt/sha512.h(SHA-384もこちら)のいずれかを使用します。
SHA-256、SHA-384、SHA-512関数は、SHA関数と同様に名付けられています。
SHA-224の場合、構造体Sha224と共にwc_InitSha224()、wc_Sha224Update()、wc_Sha224Final()関数が使用されます。
SHA-256の場合、構造体Sha256と共にwc_InitSha256()、wc_Sha256Update()、wc_Sha256Final()関数が使用されます。
SHA-384の場合、構造体Sha384と共にwc_InitSha384()、wc_Sha384Update()、wc_Sha384Final()関数が使用されます。
SHA-512の場合、構造体Sha512と共にwc_InitSha512()、wc_Sha512Update()、wc_Sha512Final()関数が使用されます。
SHAインターリービングはデフォルトで有効になっています。
(通常は、それをサポートするハードウェアアクセラレーションでのみ使用されます。)
無効にするにはNO_WOLFSSL_SHA256_INTERLEAVEを定義します。
ソフトウェアSHAは常にインターリービングをサポートしています。
BLAKE2b
BLAKE2b(SHA-3ファイナリスト)を使用するには、BLAKE2bヘッダーwolfssl/wolfcrypt/blake2.hをインクルードします。
使用する構造体はBlake2bで、これはtypedefです。
使用する前に、wc_InitBlake2b()を実行してハッシュの初期化を行う必要があります。
ハッシュを更新するにはwc_Blake2bUpdate()を使用し、最終的なハッシュを取得するにはwc_Blake2bFinal()を使用します。
byte digest[64];
byte input[64]; /*fill input with data to hash*/
Blake2b b2b;
wc_InitBlake2b(&b2b, 64);
wc_Blake2bUpdate(&b2b, input, sizeof(input));
wc_Blake2bFinal(&b2b, digest, 64);
wc_InitBlake2b()の2番目のパラメータは、最終的なダイジェストサイズです。
digestには、bufferのハッシュ化されたデータのダイジェストが含まれます。
使用例はwolfCryptテストアプリケーション(wolfcrypt/test/test.c)のblake2b_test()関数内にあります。
RIPEMD-160
RIPEMD-160を使用するには、ヘッダーwolfssl/wolfcrypt/ripemd.hをインクルードします。
使用する構造体はRipeMdで、これはtypedefです。
使用する前に、wc_InitRipeMd()を実行してハッシュの初期化を行う必要があります。
ハッシュを更新するにはwc_RipeMdUpdate()を使用し、最終的なハッシュを取得するにはwc_RipeMdFinal()を使用します。
byte ripeMdSum[RIPEMD_DIGEST_SIZE];
byte buffer[1024];
/*fill buffer with data to hash*/
RipeMd ripemd;
wc_InitRipeMd(&ripemd);
wc_RipeMdUpdate(&ripemd, buffer, sizeof(buffer)); /*can be called
again and again*/
wc_RipeMdFinal(&ripemd, ripeMdSum);
ripeMdSumには、bufferのハッシュ化されたデータのダイジェストが含まれます。
鍵付きハッシュ関数
HMAC
wolfCryptは現在、メッセージダイジェストのニーズに対してHMACを提供しています。
構造体Hmacはヘッダーwolfssl/wolfcrypt/hmac.hにあります。
HMACの初期化はwc_HmacSetKey()で行われます。
HMACでは、MD5、SHA、SHA-256、SHA-384、SHA-512をサポートしています。
以下は、SHA-256の例です。
Hmac hmac;
byte key[24]; /*fill key with keying material*/
byte buffer[2048]; /*fill buffer with data to digest*/
byte hmacDigest[SHA256_DIGEST_SIZE];
wc_HmacSetKey(&hmac, SHA256, key, sizeof(key));
wc_HmacUpdate(&hmac, buffer, sizeof(buffer));
wc_HmacFinal(&hmac, hmacDigest);
hmacDigestには、bufferのハッシュ化されたデータのダイジェストが含まれます。
GMAC
wolfCryptはメッセージダイジェストのニーズに対してGMACも提供しています。
構造体Gmacはヘッダーwolfssl/wolfcrypt/aes.hにあります(AES-GCMのアプリケーションです)。
GMACの初期化はwc_GmacSetKey()で行われます。
Gmac gmac;
byte key[16]; /*fill key with keying material*/
byte iv[12]; /*fill iv with an initialization vector*/
byte buffer[2048]; /*fill buffer with data to digest*/
byte gmacDigest[16];
wc_GmacSetKey(&gmac, key, sizeof(key));
wc_GmacUpdate(&gmac, iv, sizeof(iv), buffer, sizeof(buffer),
gmacDigest, sizeof(gmacDigest));
gmacDigestには、bufferのハッシュ化されたデータのダイジェストが含まれます。
Poly1305
wolfCryptはメッセージダイジェストのニーズに対してPoly1305も提供しています。
構造体Poly1305はヘッダーwolfssl/wolfcrypt/poly1305.hにあります。
Poly1305の初期化はwc_Poly1305SetKey()で行われます。
wc_Poly1305Final()が呼び出された後、次にPoly1305を使用する際には、Poly1305での鍵の設定プロセスを新しい鍵で再度行う必要があります。
Poly1305 pmac;
byte key[32]; /*fill key with keying material*/
byte buffer[2048]; /*fill buffer with data to digest*/
byte pmacDigest[16];
wc_Poly1305SetKey(&pmac, key, sizeof(key));
wc_Poly1305Update(&pmac, buffer, sizeof(buffer));
wc_Poly1305Final(&pmac, pmacDigest);
pmacDigestには、bufferのハッシュ化されたデータのダイジェストが含まれます。
ブロック暗号
AES
wolfCryptは16バイト(128ビット)、24バイト(192ビット)、32バイト(256ビット)の鍵サイズのAESをサポートしています。 サポートされるAESモードには、CBC、CTR、GCM(GCM-ストリーミング)、OFB、CFB(1、8、128)、SIV、XTS(XTS-ストリーミング)、GMAC、CMAC、ECB、KW(KeyWrap)、CCM-8が含まれます。
注意:wc_AesSetKey()やwc_AesGcmSetKey()などの他のAes API関数を呼び出す前に、必ずはじめにwc_AesInit()を呼び出し、Aes構造体を初期化する必要があります。
CBCモードは暗号化と復号の両方でサポートしており、wc_AesSetKey()、wc_AesCbcEncrypt()、wc_AesCbcDecrypt()関数を通じて提供されます。
AESを使用するには、ヘッダーwolfssl/wolfcrypt/aes.hをインクルードしてください。
AESのブロックサイズは16バイトで、IVも16バイトである必要があります。
関数の使用方法は通常、次のとおりです。
Aes enc;
Aes dec;
const byte key[] = { /*some 24 byte key*/ };
const byte iv[] = { /*some 16 byte iv*/ };
byte plain[32]; /*an increment of 16, fill with data*/
byte cipher[32];
wc_AesInit(&enc, HEAP_HINT, INVALID_DEVID);
wc_AesInit(&dec, HEAP_HINT, INVALID_DEVID);
/*encrypt*/
wc_AesSetKey(&enc, key, sizeof(key), iv, AES_ENCRYPTION);
wc_AesCbcEncrypt(&enc, cipher, plain, sizeof(plain));
cipherには、平文から生成された暗号文が入ります。
/*decrypt*/
wc_AesSetKey(&dec, key, sizeof(key), iv, AES_DECRYPTION);
wc_AesCbcDecrypt(&dec, plain, cipher, sizeof(cipher));
plainには、暗号文を復号することで生成された平文が入ります。
wolfCryptはAESの動作モードとしてCTR(カウンター)、GCM(ガロア/カウンター)、CCM-8(CBC-MAC付きカウンター)もサポートしています。
CBCと同様に、これらのモードを使用する場合は、ヘッダーwolfssl/wolfcrypt/aes.hをインクルードしてください。
GCMモードはwc_AesGcmSetKey()、wc_AesGcmEncrypt()、wc_AesGcmDecrypt()関数を通じて暗号化と復号の両方で利用できます。
使用例については、<wolfssl_root>/wolfcrypt/test/test.cのaesgcm_test()関数をご参照ください。
CCM-8モードはwc_AesCcmSetKey()、wc_AesCcmEncrypt()、wc_AesCcmDecrypt()関数を通じて暗号化と復号の両方でサポートしています。
使用例については、<wolfssl_root>/wolfcrypt/test/test.cのaesccm_test()関数をご参照ください。
CTRモードはwc_AesCtrEncrypt()関数を通じて暗号化と復号の両方で利用できます。
暗号化と復号のアクションは同一であるため、両方に同じ関数が使用されます。
使用例については、ファイルwolfcrypt/test/test.cのaes_test()関数をご参照ください。
DESおよび3DES
wolfCryptはDESおよび3DESをサポートしています。
(ただし、C言語では先頭に数字を使用できないため、Des3と示しています。)
これらを使用するには、ヘッダーwolfssl/wolfcrypt/des.hをインクルードします。
使用できる構造体はDesおよびDes3です。
初期化はwc_Des_SetKey()またはwc_Des3_SetKey()を通じて行われます。
CBC暗号化/復号はwc_Des_CbcEnrypt() / wc_Des_CbcDecrypt()およびwc_Des3_CbcEncrypt() / wc_Des3_CbcDecrypt()を通じて提供されます。
Desの鍵サイズは8バイト(3DESでは24)で、ブロックサイズは8バイトなので、暗号化/復号関数には8バイトの倍数のみを渡してください。
データがブロックサイズの倍数でない場合は、確実にそうなるようにパディングを追加する必要があります。
各SetKey()は、IV(鍵サイズと同じサイズの初期化ベクトル)も取ります。
使用方法は通常、次のとおりです。
Des3 enc;
Des3 dec;
const byte key[] = { /*some 24 byte key*/ };
const byte iv[] = { /*some 24 byte iv*/ };
byte plain[24]; /*an increment of 8, fill with data*/
byte cipher[24];
/*encrypt*/
wc_Des3_SetKey(&enc, key, iv, DES_ENCRYPTION);
wc_Des3_CbcEncrypt(&enc, cipher, plain, sizeof(plain));
cipherには、平文から生成された暗号文が入ります。
/*decrypt*/
wc_Des3_SetKey(&dec, key, iv, DES_DECRYPTION);
wc_Des3_CbcDecrypt(&dec, plain, cipher, sizeof(cipher));
plainには、暗号文を復号することで生成された平文が入ります。
Camellia
wolfCryptはCamelliaブロック暗号をサポートしています。
Camelliaを使用するには、ヘッダーwolfssl/wolfcrypt/camellia.hをインクルードします。
使用できる構造体はCamelliaと呼ばれます。
初期化はwc_CamelliaSetKey()を通じて行われます。
CBC暗号化/復号はwc_CamelliaCbcEnrypt()およびwc_CamelliaCbcDecrypt()を通じて提供され、直接の暗号化/復号はwc_CamelliaEncryptDirect()およびwc_CamelliaDecryptDirect()を通じて提供されます。
使用例については、<wolfssl_root>/wolfcrypt/test/test.cのcamellia_test()関数をご参照ください。
ストリーム暗号
ARC4
注意:ARC4は古く、安全でないと考えられています。 他のストリーム暗号を使用してください。
当時、インターネットで最も一般的に使用されるストリーム暗号はARC4でした。
wolfCryptはヘッダーwolfssl/wolfcrypt/arc4.hを通じてそれをサポートしています。
ブロックサイズがなく、鍵の長さも任意の長さにできるため、使用方法はブロック暗号よりも簡単です。
以下はARC4の典型的な使用方法です。
Arc4 enc;
Arc4 dec;
const byte key[] = { /*some key any length*/};
byte plain[27]; /*no size restriction, fill with data*/
byte cipher[27];
/*encrypt*/
wc_Arc4SetKey(&enc, key, sizeof(key));
wc_Arc4Process(&enc, cipher, plain, sizeof(plain));
cipherには、平文から生成された暗号文が入ります。
/*decrypt*/
wc_Arc4SetKey(&dec, key, sizeof(key));
wc_Arc4Process(&dec, plain, cipher, sizeof(cipher));
plainには、暗号文を復号することで生成された平文が入ります。
ChaCha
20ラウンドのChaChaはARC4よりもわずかに高速であり、高いレベルのセキュリティを維持しています。
wolfCryptで使用するには、ヘッダーwolfssl/wolfcrypt/chacha.hをインクルードしてください。
ChaChaは通常32バイト(256ビット)の鍵を使用しますが、16バイト(128ビット)の鍵も使用できます。
CHACHA enc;
CHACHA dec;
const byte key[] = { /*some key 32 bytes*/};
const byte iv[] = { /*some iv 12 bytes*/ };
byte plain[37]; /*no size restriction, fill with data*/
byte cipher[37];
/*encrypt*/
wc_Chacha_SetKey(&enc, key, keySz);
wc_Chacha_SetIV(&enc, iv, counter); /*counter is the start block
counter is usually set as 0*/
wc_Chacha_Process(&enc, cipher, plain, sizeof(plain));
cipherには、平文から生成された暗号文が入ります。
/*decrypt*/
wc_Chacha_SetKey(&enc, key, keySz);
wc_Chacha_SetIV(&enc, iv, counter);
wc_Chacha_Process(&enc, plain, cipher, sizeof(cipher));
plainには、暗号文を復号することで生成された平文が入ります。
wc_Chacha_SetKeyは一度設定するだけで済みますが、送信される各情報パケットごとに新しいiv(ノンス)を使用してwc_Chacha_SetIV()を呼び出す必要があります。
カウンターは、暗号化/復号プロセスを実行するときに異なるブロックから開始することで、部分的に情報を暗号化/復号できるように引数として設定されますが、ほとんどの場合は0に設定されます。
ChaChaはMACアルゴリズム(例:Poly1305、HMAC)なしで使用しないでください。
公開鍵暗号
RSA
wolfCryptはヘッダーwolfssl/wolfcrypt/rsa.hを通じてRSAをサポートしています。
RSA鍵には、公開鍵と秘密鍵の2種類があります。
公開鍵を使用すると、秘密鍵の保持者のみが復号できるように暗号化できます。
また、秘密鍵の保持者が何かに署名することを可能にし、公開鍵を持つ誰もが、秘密鍵の保持者が署名したことを確認できます。
使用方法は通常、次のとおりです。
RsaKey rsaPublicKey;
byte publicKeyBuffer[] = { /*holds the raw data from the key, maybe
from a file like RsaPublicKey.der*/ };
word32 idx = 0; /*where to start reading into the buffer*/
RsaPublicKeyDecode(publicKeyBuffer, &idx, &rsaPublicKey, sizeof(publicKeyBuffer));
byte in[] = { /*plain text to encrypt*/ };
byte out[128];
RNG rng;
wc_InitRng(&rng);
word32 outLen = RsaPublicEncrypt(in, sizeof(in), out, sizeof(out), &rsaPublicKey, &rng);
これでoutには、平文inからの暗号文が含まれます。
wc_RsaPublicEncrypt()は、outに書き込まれたバイト数を返すか、エラーの場合は負の数を返します。
wc_RsaPublicEncrypt()には、暗号化に使用されるパディング用のRNG(乱数ジェネレータ)が必要であり、使用する前に初期化する必要があります。
出力バッファが十分な大きさであることを確認するために、最初にwc_RsaEncryptSize()を使用します。
これにより、wc_RsaPublicEnrypt()の成功した呼び出しが書き込むバイト数が返されます。
エラーが発生した場合、wc_RsaPublicEnrypt()またはwc_RsaPublicKeyDecode()から負の戻り値が返されます。
その場合、wc_ErrorString()を呼び出して、発生したエラーを説明する文字列を取得できます。
void wc_ErrorString(int error, char* buffer);
バッファが少なくともMAX_ERROR_SZバイト(80)であることを確認してください。
続いて、outを復号します。
RsaKey rsaPrivateKey;
byte privateKeyBuffer[] = { /*hold the raw data from the key, maybe
from a file like RsaPrivateKey.der*/ };
word32 idx = 0; /*where to start reading into the buffer*/
wc_RsaPrivateKeyDecode(privateKeyBuffer, &idx, &rsaPrivateKey,
sizeof(privateKeyBuffer));
byte plain[128];
word32 plainSz = wc_RsaPrivateDecrypt(out, outLen, plain,
sizeof(plain), &rsaPrivateKey);
これで、plainにはplainSzバイトまたはエラーコードが含まれます。
wolfCryptでの各タイプの完全な例については、ファイルwolfcrypt/test/test.cをご参照ください。
wc_RsaPrivateKeyDecode関数は、生のDER形式の鍵のみを受け入れます。
DH (Diffie-Hellman)
wolfCryptはヘッダーwolfssl/wolfrypt/dh.hを通じてDiffie-Hellmanをサポートしています。
Diffie-Hellman鍵交換アルゴリズムにより、2人の当事者間で共有秘密鍵を確立できます。
使用方法は通常、次の例のようになります。
ここでsideAとsideBは2つの当事者を示します。
以下の例では、dhPublicKeyには認証局によって署名された(または自己署名された)Diffie-Hellman公開パラメータが含まれています。
privAはsideAに対して生成された秘密鍵、pubAはsideAに対して生成された公開鍵を保持します。
agreeAは、両者が合意した相互鍵を保持します。
DhKey dhPublicKey;
word32 idx = 0; /*where to start reading into the
publicKeyBuffer*/
word32 pubASz, pubBSz, agreeASz;
byte tmp[1024];
RNG rng;
byte privA[128];
byte pubA[128];
byte agreeA[128];
wc_InitDhKey(&dhPublicKey);
byte publicKeyBuffer[] = { /*holds the raw data from the public key
parameters, maybe from a file like
dh1024.der*/ }
wc_DhKeyDecode(tmp, &idx, &dhPublicKey, publicKeyBuffer);
wc_InitRng(&rng); /*Initialize random number generator*/
wc_DhGenerateKeyPair()は、dhPublicKeyの初期公開パラメータに基づいて公開鍵と秘密鍵のDH鍵を生成します。
wc_DhGenerateKeyPair(&dhPublicKey, &rng, privA, &privASz,
pubA, &pubASz);
sideBが彼らの公開鍵(pubB)をsideAに送信した後、sideAはwc_DhAgree()関数を使用して相互に合意された鍵(agreeA)を生成できます。
wc_DhAgree(&dhPublicKey, agreeA, &agreeASz, privA, privASz,
pubB, pubBSz);
これで、agreeAはsideAの相互に生成された鍵(サイズはagreeASzバイト)を保持します。
同じプロセスがsideBでも行われています。
wolfCryptでのDiffie-Hellmanの完全な実装例については、ファイルwolfcrypt/test/test.cをご参照ください。
EDH (Ephemeral Diffie-Hellman)
wolfSSLサーバーはEphemeral Diffie-Hellmanを実行できます。 この機能を追加するためにビルドの変更は必要ありませんが、EDH暗号スイートを有効にするためにはサーバー側でアプリケーションが一時的なグループパラメータを登録する必要があります。 これには、次のAPIを使用します。
int wolfSSL_SetTmpDH(WOLFSSL* ssl, unsigned char* p,
int pSz,unsigned char* g,int gSz);
実装例として提供しているサーバーとechoserverは、SetDH()からこの関数を使用します。
DSA (デジタル署名アルゴリズム)
wolfCryptはヘッダーwolfssl/wolfcrypt/dsa.hを通じてDSAとDSSをサポートしています。
DSAは、与えられたデータハッシュに基づいてデジタル署名を作成することを可能にします。
DSAはSHAハッシュアルゴリズムを使用してデータブロックのハッシュを生成し、その後署名者の秘密鍵を使用してそのハッシュに署名します。
標準的な使用方法は次のようになります。
まず、DSA鍵構造(key)を宣言し、署名される初期メッセージ(message)を初期化し、DSA鍵バッファ(dsaKeyBuffer)を初期化します。
DsaKey key;
Byte message[] = { /*message data to sign*/ }
byte dsaKeyBuffer[] = { /*holds the raw data from the DSA key,
maybe from a file like dsa512.der*/ }
次に、SHA構造体(sha)、乱数ジェネレータ(rng)、SHAハッシュを格納する配列(hash)、署名を格納する配列(signature)、idx(dsaKeyBufferの読み込み開始位置を示す)、検証後の戻り値を保持するint型の変数(answer)を宣言します。
Sha sha;
RNG rng;
byte hash[SHA_DIGEST_SIZE];
byte signature[40];
word32 idx = 0;
int answer;
SHAハッシュを設定して作成します。 wolfCryptのSHAアルゴリズムの詳細については、本章の「SHA / SHA-224 / SHA-256 / SHA-384 / SHA-512」節をご参照ください。
messageのSHAハッシュは、変数hashに格納されます。
wc_InitSha(&sha);
wc_ShaUpdate(&sha, message, sizeof(message));
wc_ShaFinal(&sha, hash);
DSA鍵構造体を初期化し、構造体の鍵値を設定し、乱数ジェネレータ(rng)を初期化します。
wc_InitDsaKey(&key);
wc_DsaPrivateKeyDecode(dsaKeyBuffer, &idx, &key,
sizeof(dsaKeyBuffer));
wc_InitRng(&rng);
wc_DsaSign()関数は、DSA秘密鍵、ハッシュ値、および乱数ジェネレータを使用して署名(signature)を作成します。
wc_DsaSign(hash, signature, &key, &rng);
署名を検証するには、wc_DsaVerify()を使用します。
検証が成功すると、answerは「1」となります。
完了したら、wc_FreeDsaKey()を使用してDSA鍵構造体を解放します。
wc_DsaVerify(hash, signature, &key, &answer);
wc_FreeDsaKey(&key);