在數位簽章的傳輸架構下,傳送方必須傳送檔案的明文以及Encrypted Digest(加密摘要)給接收方,接收方得到檔案之後,會用plaintext(明文)來計算的摘要訊息,以及用RSA公鑰來解密Encrypted Digest,進而比較兩者之間是否有不同,來確認檔案是否有被改寫過。底下為整個架構圖,UserA會把plaintext利用hash()計算出message digest,然後使用private key加密之後變成encrypted digest;接著把plaintext和encrypted digest傳送給UserB,UserB接收到之後,會把encrypted digest使用UserA的public key作解密,和接收到的plaintext代進hash()計算出來的message digest做比較,看看檔案是否有遭到竄改或者接收錯誤。
那OpenSSL是怎麼來計算Encrypted
Digest呢?做法是把驗證屬性(Authenticate Attributes)的部分,不包含格式前面的OID,然後把第一個byte改成0x31帶進去,利用RSA私鑰加密,就可以得到Encrypted Digest。也就是說,會影響Encrypted Digest結果的包含了content、signing time以及message digest。
A0 5D
|
[0]
AuthenticateAttributes
|
30 18
06 09 2A 86 48
86 F7 0D 01 09 03
31 0B 06 09 2A
86 48 86 F7 0D 01 07 01
|
ContentType
header
AttributeType=contentType
AttributeValue=Data
|
30 1C
06 09 2A 86 48
86 F7 0D 01 09 05
31 0F 17 0D 31
33 31 31 30 36 30 32 32 36 31 33 5A
|
SigningTime
header
AttributeType=signingType
AttributeValue=2013/11/06:02:26:13Z
|
30 23
06 09 2A 86 48
86 F7 0D 01 09 04
31 16 04 14 D2
57 F9 23 AB 54 5D F7 0C EF DE 9E B5 D2 CA 24 9C 7F BA 71
|
MessageDigest
header
AttributeType=messageDigest
AttributeValue=OOCTET
STRING Message Digest
|
30 0D
06 09 2A 86 48
86 F7 0D 01 01 01
05 00
|
SIgestEncryptedAlgorithm
header
Algorithm=RSA
Parameters=NULL
|
04 81 80
1B B6 55 0A 9A
C9 59 2B 10 AE 2F F7 57 E8 06 EE
4D 5E 1D 98 3E
22 2C 1B 6A 55 4C 81 2D 66 D4 D0
6A C0 A9 D2 2F
CD FD F0 A5 DC FD A0 AF 8F 5D 92
91 05 50 CF BF
E7 14 FD 97 EA BB 44 DE 83 AF B3
84 F7 4B 1C 72
53 D5 25 06 C0 6D 91 10 CA 7B 49
36 F0 EF 17 0F
9E 2D EA 36 14 A2 51 26 90 9D 41
40 FF C6 F0 F3
2E A3 70 A4 8C C4 C3 60 DB 96 97
2E 84 F1 E0 55
8C BB 78 E1 F6 2B 68 59 9F FC 0B
|
OCTET STRING
EncryptedDigest
1024bits
|
利用以下程式碼做RSA加解密的動作。程式碼請參考
RSA.c
#include <stdio.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/err.h>
#include <openssl/pem.h>
#include <openssl/ssl.h>
int main ()
{
int err;
int sig_len;
unsigned char sig_buf [4096];
static char certfile[] = "signer.pem";
static char keyfile[]= "signer.pem";
int data_len = 95;
unsigned char data[95]=
{0x31,0x5D,0x30,0x18,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x03,
0x31,0x0B,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x01,
0x30,0x1C,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x05,
0x31,0x0F,0x17,0x0D,0x31,0x33,0x31,0x31,0x30,0x36,0x30,0x32,0x32,0x36,0x31,0x33,0x5A,
0x30,0x23,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x09,0x04,
0x31,0x16,0x04,0x14,0xD2,0x57,0xF9,0x23,0xAB,0x54,0x5D,0xF7,0x0C,0xEF,
0xDE,0x9E,0xB5,0xD2,0xCA,0x24,0x9C,0x7F,0xBA,0x71};
EVP_MD_CTX md_ctx;
EVP_PKEY * pkey;
FILE * fp;
X509 * x509;
int ii;
printf("AuthenticateAttributes:\n");
for(ii=0;ii<data_len;ii++) {
printf("%02X ",data[ii]);
if((ii+1)%16==0&&(ii+1)!=data_len) printf("\n");
}
printf(", AuthenticateAttributesLen: %d\n",data_len);
/* Just load the crypto library error strings,
* SSL_load_error_strings() loads the crypto AND the SSL ones */
/* SSL_load_error_strings();*/
ERR_load_crypto_strings();
/* Read private key */
fp = fopen (keyfile, "r");
if (fp == NULL) exit (1);
pkey = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
fclose (fp);
if (pkey == NULL) {
ERR_print_errors_fp (stderr);
exit (1);
}
/* Do the signature */
EVP_SignInit (&md_ctx, EVP_sha1());
EVP_SignUpdate (&md_ctx, data, strlen(data));
sig_len = sizeof(sig_buf);
err = EVP_SignFinal (&md_ctx, sig_buf, &sig_len, pkey);
printf("EncryptedDigest: \n");
for(ii=0;ii<sig_len;ii++)
{
printf("%02X ",(unsigned int)sig_buf[ii]);
if((ii+1)%16==0&&(ii+1)!=sig_len) printf("\n");
}
printf(", EncryptedDigest: %d\n",sig_len);
if (err != 1) {
ERR_print_errors_fp(stderr);
exit (1);
}
EVP_PKEY_free (pkey);
/* Read public key */
fp = fopen (certfile, "r");
if (fp == NULL) exit (1);
x509 = PEM_read_X509(fp, NULL, NULL, NULL);
fclose (fp);
if (x509 == NULL) {
ERR_print_errors_fp (stderr);
exit (1);
}
/* Get public key - eay */
pkey=X509_get_pubkey(x509);
if (pkey == NULL) {
ERR_print_errors_fp (stderr);
exit (1);
}
/* Verify the signature */
EVP_VerifyInit (&md_ctx, EVP_sha1());
EVP_VerifyUpdate (&md_ctx, data, strlen((char*)data));
err = EVP_VerifyFinal (&md_ctx, sig_buf, sig_len, pkey);
EVP_PKEY_free (pkey);
if (err != 1) {
ERR_print_errors_fp (stderr);
exit (1);
}
printf ("Signature Verified Ok.\n");
return(0);
}
執行結果
從執行結果得到的Encrypted Digest,可以看到與範例格式的加密摘要相同。驗證了Encrypted Digest是由authenticate
attribute的content、signing time和message digest加密而來。
沒有留言:
張貼留言