3.4 電子署名
電子署名の方法を説明します。
電子署名では、署名されたデータが変更されていないこと(改竄(改ざん)されていないこと)を検知できますし、その有効期間を設定することもできます。例えば、重要な計算に利用するデータで、それを変更されたくない場合などは、利用するデータに電子署名しておき利用する際にその署名を検証してから利用するようにすれば常に正しい結果を導き出すアプリケーションを作成できます。
前提となる、公開鍵については、以下のページを参照してください。
電子署名では、署名されたデータが変更されていないこと(改竄(改ざん)されていないこと)を検知できますし、その有効期間を設定することもできます。例えば、重要な計算に利用するデータで、それを変更されたくない場合などは、利用するデータに電子署名しておき利用する際にその署名を検証してから利用するようにすれば常に正しい結果を導き出すアプリケーションを作成できます。
前提となる、公開鍵については、以下のページを参照してください。
3.4.1 電子署名と検証
電子証明は、署名者の私有鍵で署名すべきデータ(以下メッセージと記します。)のハッシュ値を暗号化します。署名の検証とは、メッセージのハッシュ値を計算し、その値と暗号化されたハッシュ値を復号して得られたハッシュ値を比較することです。また、検証の際に利用した公開鍵の有効性を確かめるのも検証作業です。
電子署名されたデータには、メッセージ、ハッシュ値の暗号化データ以外に署名を検証する公開鍵証明書(電子証明書)が含まれます。
ただし、メッセージや、電子証明書は必ず含まれるものではありませんので注意してください。
検証では、電子証明書の有効性を確認しますが、電子証明書の有効性はその有効期間だけではありません。電子証明書を発行した証明機関(CA)によって失効されていないことを確認します。もし、その証明機関に上位の証明機関がある場合は、その上位の証明機関によって下位の証明機関の電子証明書が失効されていないことも確認します。この作業は、ルート証明機関(最上位の証明機関)に達するまで確認します。
電子署名されたデータには、メッセージ、ハッシュ値の暗号化データ以外に署名を検証する公開鍵証明書(電子証明書)が含まれます。
ただし、メッセージや、電子証明書は必ず含まれるものではありませんので注意してください。
検証では、電子証明書の有効性を確認しますが、電子証明書の有効性はその有効期間だけではありません。電子証明書を発行した証明機関(CA)によって失効されていないことを確認します。もし、その証明機関に上位の証明機関がある場合は、その上位の証明機関によって下位の証明機関の電子証明書が失効されていないことも確認します。この作業は、ルート証明機関(最上位の証明機関)に達するまで確認します。
3.4.2 電子署名の準備
電子証明書は、2.3.3 証明書を取り出す の方法で取り出しておきます。GUIを使って証明書を取り出すには、2.5.3電子証明書を選択する を参照しいてください。WindowsXP以前でGUIを使う場合は、Windows98で利用可能なダイアログ を参照してください。
次に、電子署名のパラメータを設定します。
pSigningCertには、メッセージに署名する電子証明書を指定します。
HashAlgorithmには、メッセージのハッシュ値を算出するアルゴリズムを指定します。
cMsgCertには、署名に含める電子証明書の数を指定します。
rgpMsgCertには、署名に含める電子証明書を指定します。
署名に含まれる電子証明書は、必ずしも署名に使った電子証明書である必要はありません。他にも特筆すべき点はありますが、ここでは簡単に署名とその検証の処理を実装するため詳細は別項で説明を予定しています。
次に、電子署名のパラメータを設定します。
// 電子署名の準備 CRYPT_SIGN_MESSAGE_PARA sigPara; memset(&sigPara, 0, sizeof(sigPara)); sigPara.cbSize = sizeof(sigPara); sigPara.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; sigPara.pSigningCert = pcCert; // 署名に使う、電子証明書 sigPara.HashAlgorithm.pszObjId = szOID_RSA_MD5; // ハッシュ計算のアルゴリズム sigPara.HashAlgorithm.Parameters.cbData = NULL; // アルゴリズムに必要なパラメーター sigPara.cMsgCert = 1; // 署名値に含める電子証明書の数 sigPara.rgpMsgCert = &pcCert; // 署名値に含める電子証明書cbSizeには、構造体のサイズを指定します。
pSigningCertには、メッセージに署名する電子証明書を指定します。
HashAlgorithmには、メッセージのハッシュ値を算出するアルゴリズムを指定します。
cMsgCertには、署名に含める電子証明書の数を指定します。
rgpMsgCertには、署名に含める電子証明書を指定します。
署名に含まれる電子証明書は、必ずしも署名に使った電子証明書である必要はありません。他にも特筆すべき点はありますが、ここでは簡単に署名とその検証の処理を実装するため詳細は別項で説明を予定しています。
3.4.3 電子署名
メッセージ(署名されるデータ)を用意して、電子署名を実施します。電子署名の関数は、2回コールします、1回目は、電子署名されたデータのサイズを知るため、2回目は、電子署名されたデータを受け取るためです。
まず、メッセージを定義します。
第2引数には、FALSEをセットして署名データにメッセージを含めます。
第3引数には、署名するメッセージの数
第4引数には、メッセージの配列
第5引数には、メッセージサイズの配列
第6引数には、署名されたデータの格納ポインター
第7引数には、署名されたデータのサイズが戻ります。
まず、メッセージを定義します。
// メッセージ(署名されるデータ) BYTE *pbMessage = (BYTE*)"電子署名されるデータです。"; DWORD cbMessage = (DWORD)strlen((char*)pbMessage)+1; const BYTE *messageArray[] = {pbMessage}; DWORD msgSizeArray[1]; msgSizeArray[0] = cbMessage;メッセージは、1つだけではありませんので、配列に必要なメッセージの数とそれらのポインターをセットします。関数には、この配列を渡して電子署名します。
// 電子署名 BYTE *pbSignedMsgBlob; DWORD cbSignedMsgBlob; if(!CryptSignMessage( &sigPara, // 署名のパラメータ FALSE, // 電子署名にメッセージを含めます 1, // メッセージの数 messageArray, // メッセージの配列 msgSizeArray, // メッセージサイズの配列 NULL, // 署名データの大きさがわからないのでNULL &cbSignedMsgBlob)) // 署名データのサイズが戻る { fprintf(stderr, "Error: CryptSignMessage\n"); return 4; } printf("Data size = %d\n", cbSignedMsgBlob); // 領域を確保して2回目のコール pbSignedMsgBlob = new BYTE [cbSignedMsgBlob]; if(!CryptSignMessage( &sigPara, FALSE, 1, messageArray, msgSizeArray, pbSignedMsgBlob, // 署名データの格納領域 &cbSignedMsgBlob)) { fprintf(stderr, "Error: CryptSignMessage\n"); return 5; }関数の、第1引数には、パラメータをセットします
第2引数には、FALSEをセットして署名データにメッセージを含めます。
第3引数には、署名するメッセージの数
第4引数には、メッセージの配列
第5引数には、メッセージサイズの配列
第6引数には、署名されたデータの格納ポインター
第7引数には、署名されたデータのサイズが戻ります。
3.4.4 署名検証の準備
まず、署名検証のパラメーターを設定します。
// 署名検証の準備 CRYPT_VERIFY_MESSAGE_PARA vrfyPara; memset(&vrfyPara, 0, sizeof(vrfyPara)); vrfyPara.cbSize = sizeof(vrfyPara); vrfyPara.dwMsgAndCertEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING;暗号化データを復号するときと同様に、ごく少ない情報を設定します。
3.4.5 署名検証
署名されたデータをセットして、2回コールします。
電子署名は、多重に行えます。検証では、何番目の電子署名を検証するかを指定します。
第2引数には、何番目の署名を検証するかを指定します、署名がひとつだけの場合は、0(ゼロ)を指定します。
第3引数には、署名されたデータのポインター
第4引数には、署名されたデータのサイズ
第5引数には、デコードされたメッセージの格納領域のポインター
第6引数には、デコードされたメッセージのサイズ
第7引数には、署名者の証明書が戻ります。
// 署名の検証 BYTE *pbDecodedMsgBlob; DWORD cbDecodedMsgBlob; if(!CryptVerifyMessageSignature( &vrfyPara, // 検証のパラメーター 0, // 最初の署名を検証 pbSignedMsgBlob, // 署名されたデータのポインター cbSignedMsgBlob, // 署名されたデータのサイズ NULL, // デコードされたメッセージ &cbDecodedMsgBlob, // デコードされたメッセージの大きさ NULL)) // 署名を検証した証明書 { fprintf(stderr, "Error: CryptVerifyMessageSignature\n"); return 6; } // 領域を確保して、2回目のコール pbDecodedMsgBlob = new BYTE [cbDecodedMsgBlob]; if(!CryptVerifyMessageSignature( &vrfyPara, 0, pbSignedMsgBlob, cbSignedMsgBlob, pbDecodedMsgBlob, // デコードされたメッセージ &cbDecodedMsgBlob, NULL)) { fprintf(stderr, "Error: CryptVerifyMessageSignature\n"); return 7; } printf("Verified Data is \"%s\"\n", pbDecodedMsgBlob);関数の第1引数には、署名検証のパラメーターをセットします。
電子署名は、多重に行えます。検証では、何番目の電子署名を検証するかを指定します。
第2引数には、何番目の署名を検証するかを指定します、署名がひとつだけの場合は、0(ゼロ)を指定します。
第3引数には、署名されたデータのポインター
第4引数には、署名されたデータのサイズ
第5引数には、デコードされたメッセージの格納領域のポインター
第6引数には、デコードされたメッセージのサイズ
第7引数には、署名者の証明書が戻ります。
3.4.6 後始末
delete [] pbDecodedMsgBlob; delete [] pbSignedMsgBlob; CertFreeCertificateContext(pcCert); CertCloseStore(hStore, 0); CryptReleaseContext(hProv, 0);
3.4.7 サンプルコード
メッセージに署名して、それを検証するサンプルです。
サンプルコードの商業利用および転載を禁止します。
サンプルコードの商業利用および転載を禁止します。
3.4.8 ご質問・ご要望
ご質問やご要望は、こちらからお送りください。(匿名でも可能です。)
(記載の会社名および製品名は、各社の登録商標および商標です。)