RSA 署名と検証
私密鍵(private key)で何らかのデータを署名する.この署名を証明書(certification)に含まれている公開鍵(public key)で検証する.
準備するもの
- Shining Light版 OpenSSL 1.0.0a
- Visual Studio 2008 Express Edition
- Windows XP
openssl.exe で鍵を作成する
鍵を3種1個ずつ作る.private key(pKey: certpKey.pem),certification(cert: cert.pem),public key(pubKey: pubKey.pem).pubKey を作るのは,私がテストしている中で問題があって,原因の切り分けのために作った.だから,署名検証の成立だけを見届ける場合はいらない.
openssl rsa -inform pem -outform pem -in pKey.pem -out pubKey.pem -pubout openssl req -outform pem -out cert.pem -nodes -key certpkey.pem -keyform pem -subj /C=JP/ST=Sendai/L=Morio/CN=ssl.example.com -new -x509 openssl rsa -inform pem -outform pem -in certpKey.pem -out pubKey.pem -pubout
プログラム
「The quick brown fox jumps over the lazy dog」というテキストに署名する.実際にはこのテキストから生成されるハッシュ値に署名する.ハッシュ関数は SHA-256 を使用した.
署名(検証)の関数は RSA_sign(),RSA_verify()を使用する.署名(検証)に問題ない場合,関数は 1 を返す.
ここで示しているソースコードでは,署名検証について,公開鍵 PEM ファイルから公開鍵を取り出す A 方式と,自己署名証明書 PEM ファイルから公開鍵を取り出す B 方式の2とおりある.
#ifdef _DEBUG #pragma comment(lib, "libeay32MDd.lib") #pragma comment(lib, "ssleay32MDd.lib") #else #pragma comment(lib, "libeay32MD.lib") #pragma comment(lib, "ssleay32MD.lib") #endif #include <stdlib.h> #include <string.h> #include <openssl/sha.h> #include <openssl/rsa.h> #include <openssl/evp.h> #include <openssl/pem.h> #include <openssl/x509.h> // openssl/applink.c 内の fopen() への warning C4996 の抑制 #ifdef _WIN32 #ifdef WIN32 #define WIN32_PREDEFINED #else #define WIN32 #endif #pragma warning( disable: 4996 ) #endif #include <openssl/applink.c> #ifdef WIN32 #ifdef WIN32_PREDEFINED #undef WIN32_PREDEFINED #else #undef WIN32 #endif #pragma warning( default: 4996 ) #endif // warning C4996 の抑制はここまで const char *pKeyFilename = "C:\\data\\PEM\\Private\\certpKey.pem"; // 署名鍵 const char *pubKeyFilename = "C:\\data\\PEM\\Public\\pubKey.pem"; // 署名鍵から生成した公開鍵 const char *certFilename = "C:\\data\\PEM\\Signature\\cert.pem"; // 署名鍵から生成した自己署名証明書 int main ( int argc, char *argv[] ) { FILE *fp; // PEMファイル読み込みしに使用するファイルポインタ RSA *pKey; // 私密鍵 RSA *pubKey; // 公開鍵 X509 *cert; // 証明書 char *text = "The quick brown fox jumps over the lazy dog"; // 平文.(unsigned char *)にキャストする unsigned char hash[SHA256_DIGEST_LENGTH]; // 署名対象.平文のSHA-1 unsigned char signature[2048/8]; // 署名情報 unsigned int signatureLength; // 署名情報のサイズ int sigret; // sign,verify の返り値を格納する // 署名対象を作る SHA256( (unsigned char *)text, strlen( text ), hash ); // 私密鍵を読み込む.署名に使用する fopen_s( &fp, pKeyFilename, "r"); pKey = PEM_read_RSAPrivateKey( fp, 0, 0, 0 ); fclose( fp ); // 署名する sigret = RSA_sign( NID_sha256, hash, SHA256_DIGEST_LENGTH, signature, &signatureLength, pKey ); printf("%d\n", sigret); // A. 公開鍵を読み込む //fopen_s( &fp, pubKeyFilename, "r" ); //pubKey = PEM_read_RSA_PUBKEY( fp, 0, 0, 0 ); //fclose( fp ); //RSA_print_fp( stdout, pubKey, 0 ); // B. 証明書から公開鍵を取り出す fopen_s( &fp, certFilename, "r" ); cert = PEM_read_X509( fp, 0, 0, 0 ); fclose( fp ); EVP_PKEY *evp = X509_get_pubkey( cert ); evp = X509_get_pubkey( cert ); pubKey = EVP_PKEY_get1_RSA( evp ); // RSA_print_fp( stdout, pubKey, 0 ); // 検証する sigret = RSA_verify( NID_sha256, hash, SHA256_DIGEST_LENGTH, signature, signatureLength, pubKey ); printf("%d\n", sigret); return 0; }