Trusted Design

OpenSSLでRSA署名処理

概要

OpenSSLが提供しているC言語のAPIを使って公開鍵暗号方式のRSAで署名を行います。

利用するAPI

署名/署名検定を実行するためのAPIを使います。

  • EVP_SignInit_ex()
    署名処理を初期化します。
  • EVP_SignUpdate()
    署名処理用のオブジェクトに平文データを入力します。
  • EVP_SignFinal_ex()
    署名処理を実行します。
  • EVP_VerifyInit()
    署名検定処理を初期化します。
  • EVP_VerifyUpdate()
    署名検定用のオブジェクトに署名検定をしたい平文を入力します。
  • EVP_VerifyFinal()
    署名データを入力して,署名を検定します。

サンプルプログラム

署名処理の関数

上で書いた署名処理の関数を順番にコールしていきます。複数のデータを連結して署名したい場合には,EVP_SignUpdate()を複数回呼び出します。


int RSASign(const EVP_MD* md, EVP_MD_CTX* ctx, EVP_PKEY* pkey, const unsigned char* msg, int msgLen, unsigned char* sign, unsigned int* signLen)
{
	if (!EVP_SignInit_ex(ctx, md, NULL))
	{
		/* Error */
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		return 0;
	}

	if (!EVP_SignUpdate(ctx, msg, msgLen))
	{
		/* Error */
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		return 0;
	}

	if (!EVP_SignFinal(ctx, sign, signLen, pkey))
	{
		/* Error */
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		return 0;
	}
	return 1;
}

署名検定処理の関数

署名検定も呼び出し方は署名処理と同じです。


int RSAVerify(const EVP_MD* md, EVP_MD_CTX* ctx, EVP_PKEY* pkey, const unsigned char* msg, int msgLen, unsigned char* sign, unsigned int sigLen)
{
	if (!EVP_VerifyInit(ctx, md))
	{
		/* Error */
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		return 0;
	}

	if(!EVP_VerifyUpdate(ctx, msg, msgLen))
	{
		/* Error */
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		return 0;
	}

	if(!EVP_VerifyFinal(ctx, sign, sigLen, pkey))
	{
		/* Error */
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		printf("Invalid Signature\n");
		return 0;
	}

	return 1;
}

呼び出し側

入力する平文は「Trusted Design sign message.」です。署名処理で使う鍵ペアは通常は既存のものを利用します。今回はサンプルなので鍵ペアを生成して,それを使って署名を行います。


#include "openssl/evp.h"
#include "openssl/rsa.h"
#include "openssl/err.h"

/*
 バイト列を出力する関数
*/
int PrintBytes(unsigned char* bytes, unsigned int bytesLen)
{
	for (int i = 1; i <= bytesLen; i++) {
		printf("%02x ", *bytes++);
		if (i % 16 == 0) printf("\n");
	}
	printf("\n");
	return 1;
}

/*
 RSA鍵を生成しEVP_PKEYに鍵を設定する関数
*/
int GetRSAKey(RSA* rsa, EVP_PKEY* pkey)
{
	/* RSA鍵生成のためBIGNUMを利用する */
	BIGNUM* bn = NULL;
	unsigned long long e = RSA_F4; // 65537
	bn = BN_new();
	BN_set_word(bn, e);
	int bits = 1024;					// 鍵長

	rsa = RSA_new();
	/* テスト用にRSA鍵ペアを生成する。通常は既存の鍵ペアを利用する。*/
	if (!RSA_generate_key_ex(rsa, bits, bn, NULL))
	{
		/* Error */
		printf("Error: %s\n", ERR_reason_error_string(ERR_get_error()));
		RSA_free(rsa);
		return 0;
	}
	EVP_PKEY_set1_RSA(pkey, rsa);
	return 1;
}

int DestroyRSAKey(RSA* rsa)
{
	RSA_free(rsa);
	return 1;
}

/*
 メイン関数
*/
int main()
{
	/* ハッシュアルゴリズム SHA-256を利用する */
	const EVP_MD* md = EVP_sha256();
	
	EVP_MD_CTX* ctx;
	ctx = EVP_MD_CTX_new();
	EVP_PKEY* pkey = EVP_PKEY_new();
	RSA* rsa = NULL;

	const unsigned char msg[] = { "Trusted Design sign message." };
	int msgLen = sizeof(msg);
	unsigned char sign[128];			// 1024bit暗号
	unsigned int signLen = 128;

	if (!GetRSAKey(rsa, pkey))
	{
		/* Error */
		printf("GetRSAKey() Error\n");
		EVP_MD_CTX_free(ctx);
		EVP_PKEY_free(pkey);
		return 0;
	}

	if (!RSASign(md, ctx, pkey, msg, msgLen, sign, &signLen))
	{
		/* Error */
		printf("RSASign() Error\n");
		EVP_MD_CTX_free(ctx);
		EVP_PKEY_free(pkey);
		return 0;
	}
	PrintBytes(sign, signLen);

	if (!RSAVerify(md, ctx, pkey, msg, msgLen, sign, signLen))
	{
		/* Error */
		printf("RSAVerify() Error\n");
		EVP_MD_CTX_free(ctx);
		EVP_PKEY_free(pkey);
		return 0;
	}
	printf("Valid Signature!\n");

	/* 解放処理 */
	DestroyRSAKey(rsa);
	EVP_MD_CTX_free(ctx);
	EVP_PKEY_free(pkey);
}

実行結果

署名結果は鍵長の1024bit(つまり128Byte)のバイナリ列です。


64 ef 5b 2d 59 d2 15 7f c6 45 8a fd 8a 57 3e 3b
48 c5 3f a0 fc 46 a1 3f 0e 21 7c 8d 36 99 9e 99
39 a1 ec e0 de 85 b2 a4 24 18 0b 22 c8 19 87 42
3e a8 f3 a2 e2 ef 13 f2 a1 76 21 3c 41 ed 58 e9
99 4f 9f 5e 8f 73 ec 37 7a 79 36 d8 e8 e4 66 b2
cc 3d bf 3b a5 f8 dc 0b 3a 6b 63 24 c2 56 30 e8
13 0f 90 b3 32 81 1b bd db e2 f1 6b 9c 05 81 51
c5 95 ae 16 76 b8 27 dd d1 8b b6 56 ee 73 56 3b

Valid Signature!