Functionsと呼ばれる関数群を取り上げます。そのデータは多くのアプリケーションによって認識されることになります。前者が署名データのエンコード形式、後者が暗号化データのエンコード形式となります。7形式によるエンコードを検討するとよいでしょう。SignedData型に含まれる情報は主に、署名対象のデータ、署名、ID(SerialNumberとIssuer)、そして証明書です。これら全てのデータが必ずしも存在するとは限りません。この秘密鍵は証明書から参照されることになります。署名者の証明書には秘密鍵が関連付けられている必要があります。Functionsの中で署名を行う関数は、CryptSignMessageです。*pcbSignedBlob);pSignParaは、署名情報を含むCRYPT_SIGN_MESSAGE_PARA構造体のアドレスを指定します。fDetachedSignatureは、署名されたハッシュ値のみを取得したい場合はTRUEを指定します。PKCS#7形式で署名データを取得したい場合は、FALSEを指定します。cToBeSignedは、rgpbToBeSignedの要素数を指定します。rgpbToBeSignedは、署名したいデータの配列を指定します。rgcbToBeSignedは、署名したいデータのサイズを格納した配列を指定します。pbSignedBlobは、署名されたデータを受け取るバッファを指定します。pcbSignedBlobは、バッファのサイズを格納した変数のアドレスを指定します。pbSignedBlobにNULLを指定した場合、バッファのサイズが返ることになります。CRYPT_SIGN_MESSAGE_PARA構造体の定義を次に示します。*PCRYPT_SIGN_MESSAGE_PARA;cbSizeは、構造体のサイズをバイト単位で指定します。dwMsgAndCertEncodingTypeは、エンコーディングタイプを指定します。pSigningCertは、署名に使用する証明書を指定します。この証明書には、CSPの情報が関連付けられている必要があります。HashAlgorithmは、ハッシュアルゴリズムを格納したCRYPT_ALGORITHM_IDENTIFIER構造体のアドレスを指定します。pvHashAuxInfoは、使用されないためNULLを指定します。cMsgCertは、rgpMsgCertの要素数を指定します。rgpMsgCertは、署名データに含みたい証明書の配列を指定します。cMsgCrlは、rgpMsgCrlの要素数を指定します。rgpMsgCrlは、署名データに含みたいCRLの配列を指定します。cAuthAttrは、rgAuthAttrの要素数を指定します。rgAuthAttrは、認証済み属性の配列を指定します。cUnauthAttrは、rgUnauthAttrの要素数を指定します。rgUnauthAttrは、認証されていない属性の配列を指定します。dwFlagsとdwInnerContentTypeは、基本的に0を指定します。今回のプログラムは、CryptSignMessageでSignedData型のデータを作成し、それをファイルに保存します。署名のため、MY証明書ストアに、関連する秘密鍵を持った証明書を用意しておいてください。TEXT("証明書の取得に失敗しました。TEXT("署名に失敗しました。TEXT("署名に失敗しました。TEXT("署名に成功しました。CertFindCertificatesInStoreで証明書を取得します。MDハッシュを表すszOID_RSA_MD5を指定しています。ここで取得した証明書とハッシュアルゴリズムをCRYPT_SIGN_MESSAGE_PARA構造体に指定します。CRYPT_SIGN_MESSAGE_PARA構造体には、証明書を受け取るメンバが2つあります。rgpMsgCertは何のために指定することになるのでしょうか。答えは、署名を検証するための証明書を含めるためです。pSigningCertが指している証明書を含めておく必要があります。仮にrgpMsgCertが初期化されていなくても関数は成功するので注意してください。次に、CryptSignMessageの呼び出しを確認します。&dwSignedBlobSize);第2引数のFALSEは、署名されたハッシュ値をデータに含めることを意味します。第3引数の1は、署名の対象とするデータが1つであることを意味します。試してみたところ、複数データへの署名はエラーとなるように思えます。その分のメモリを確保し、次のCryptSignMessageの呼び出しでSignedData型のデータを取得できることになります。