US0
[OpenSSL/RSA] 나눴던 Private Key로 다시 RSA구조체 만들고 암/복호화 하기!!(Deserialization) 본문
[OpenSSL/RSA] 나눴던 Private Key로 다시 RSA구조체 만들고 암/복호화 하기!!(Deserialization)
us0 2018. 11. 24. 03:49[OpenSSL/RSA] 나눴던 Private Key로 다시 RSA구조체 만들고 암/복호화 하기!!(Deserialization)
우리는 저번 포스팅때 RSA keypair를 char * 형 문자열로 바꿔서 공개키와 비밀키를 나누는
과정을 해보았다!!!
이과정 다음을 바로 이어서 설명 하겠다.(이전 단계의 변수들 그대로 사용!!)
RSA *keyPair
/ \
/ \
/ \
BIO *pri BIO *pub
/ \
/ \
/ \
char *pri_key char *pub_key
그럼 이렇게 공개키와 비밀키를 나눴으니 private key(비밀키)로 다시 RSA keypair 구조체를 복원 시켜보자!!
그럼 그림 반대인 이 순서로 각각의 키를 이용해서 RSA 구조체를 다시 복원시켜야한다.
(그래야 복호화/ 암호화 가능!! / char *형으로 만들어 줬던건 private key와 public key를 나눠주는 과정!!)
char *pri_key / pub_key
|
|
BIO *pri / pub
|
|
RSA *rsa_prikey / rsa_pubkey
그럼 코드를 한번 따라가보자!!!
지금 pri_key라는 변수는 (char *)형이고 private key가 담겨져있다.
BIO구조체 rpri 는 BIO_new_mem_buf() 함수를 통해 rpri 라는 BIO구조체형식의 메모리영역을 pri_key의 길이만큼 할당해준다.
(2번째 매개변수가 -1이면 딱 첫번째매개변수의 길이만큼이라는 뜻이다!!!)
//Deserialize private key: (char*)pri_key => (RSA *)rsa_prikey
BIO *rpri =BIO_new_mem_buf(pri_key,-1);
BIO_write(rpri, pri_key,(int)pri_len);
RSA *rsa_prikey =NULL;
그리고 BIO_write를 통해 rpri (BIO구조체)에 pri_key에 들어있는 문자열을 pri_len(=strlen(pri_key)) 만큼 써준다.
그럼 BIO구조체인 rpri 스트림버퍼에는 pri_key값이 생성이된다.
마지막에 최종적으로는 RSA 구조체를 만들어줘야하니까 일단 RSA 변수를 생성해준다.
if(!PEM_read_bio_RSAPrivateKey(rpri, &rsa_prikey, NULL, NULL)){
printf("PEM_read_bio_RSAPrivateKey error\n");
return -1;
}
PEM_read_bio_RSAPrivateKey() 함수를 통해 PEM형식으로 bio(지금은 rpri에 해당) 에서 RSA의 Private key를 추출하여
RSA구조체(지금은 RSA_prikey변수에 해당) 에 private key값을 지정해준다.
그럼 우리는 복호화에 필요한 private key값을 가지고 있는 상태에 해당된다!!!
그럼 이제 한번 복호화를 해보자 복호화 하기위해서는 일단 복호화된 값이 들어갈만한 공간을 할당해준다
근데 여기서 RSA_size(rsa_prikey)만큼의 크기가 할당 되어있다. 이 이유는 RSA는 블록암호화 방식이 아닌
비밀키에 해당하고 이 특징은 키의 길이보다 작아야만 암호화를 시킬수 있다는 것이다. 그래서 private keyd의 길이만큼 메모리를 할당해 주는것이다.
unsigned char *decrypt =(unsigned char*) malloc(RSA_size(rsa_prikey));
int decrypt_len=-1;
아래 선언된 RSA_private_decrypt()함수는 rsa구조체를 통해 cipher_txt(암호문)을 복호화시키는 함수이다.
여기서 끝 매개변수로 RSA_PKCS1_OAEP_PADDING 이러한 매개변수가 들어왔는데 이는 OAEP형식의 패딩이라고 생각하면된다.
실험을 해보았더니 이 패딩의 길이는 43Byte인것 같다!!! RSA_private key의 크기는 256바이트이기 때문에 따라서 214바이트 이상이되면 복호화가 실패한다!!
// RSA_private_decrypt(<int flen>, <const unsigned char *from>, <unsigned char *to>, <RSA *rsa>, <int padding>)
if((decrypt_len=RSA_private_decrypt(encrypt_len, (unsigned char*)ciphertxt, decrypt, rsa_prikey, RSA_PKCS1_OAEP_PADDING)) == -1){
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr,"Error Decrypting message : %s\n", err);
printf("RSA_public_encrypt error!!\n");
return -1;
}
이 함수들은 ERR_load_crypto_strings(); ERR_error_string(ERR_get_error(), err);
openssl에서 지원하는 error check함수들로 #include<openssl/err.h> 이 헤더파일에 함수가 정의되어있으며 어떤 종류의 오류가 발생했는지
자세히 설명해준다
ex)
plain_txt len = 218
Error Encrypting message : error:2007507E:BIO routines:MEM_WRITE:write to read only BIORSA_public_encrypt error!!
이렇게 에러 코드와 함께 무엇이 문제였는지 출력해준다ㅎ.ㅎ
Key를 이용해 decrypt 잘되었는지 확인하기 위해 출력을 해보자!!!
printf("decrypt_len = %d\n", decrypt_len);
printf("decrypt: >>%s<<", decrypt);
쨔잔~~~
여기까지 Deserialization 과정에다가 마지막에 복호화까지 해보는 시간을 가졌었다.
아래에는 Serialization을 통해 공개키와 비밀키로 나누어 암호화를 할땐 public key를 따로 추출시켜 다시 Desrialization을하여 rsa_pubkey를 통해 암호화시키고
암호화한 암호문을 해독하기위해 나눠주었던 private key를 다시 RSA로 되돌리기 위해 Deserialization 과정을 거쳐 rsa_prikey를 생성하여 이를 통해 복호화를 한다.
아래는 전체적인 코드의 흐름이다.
어떤식으로 프로그램이 돌아 가는지 차근차근 살펴보자!!
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
#include<openssl/rsa.h>
#include<openssl/pem.h>
#include<openssl/err.h>
//읽어 들이는 바이트 수
#define KEY_LENGTH 2048
#define PUB_EXP 3
//void ErrorCheck_malloc();
char *msg="Welcome to Zerous0 Blog!! hello hello nice to meet you!! hahahahahahaha";
int main(int argc, char **argv){
//keypair생성!!
//RSA_generate_key(<int bits>, <unsigned long e>, <void (*callback)(int, int, void *)>, <void *cb_arg>)
/*
* 각각 public key와 private key를 담을수 있는 스트림을 생성 해준다.
* Serialization하는 과정
*/
RSA *keypair= RSA_generate_key(KEY_LENGTH, PUB_EXP, NULL, NULL);
BIO *pri = BIO_new(BIO_s_mem());
BIO *pub = BIO_new(BIO_s_mem());
if(keypair==NULL){
printf("RSA_keygenerate_key error!! \n");
return -1;
}
if( pri ==NULL){
printf("allocated error!!\n");
return -1;
}
if( pub ==NULL){
printf("allocated error!!\n");
return -1;
}
//keypair에게 pri와 pub의 존재를 알려주는 역할들!!
//BIO공간에 keypair에 속한 정보들을 pri와 pub 스트림에 써준당
//PEM_write_bio_RSAPrivateKey(<BIO *bp>, <RSA *x>, <const EVP_CIPHER *enc>, <unsigned char *kstr>,
<int klen>, <pem_password_cb *cb>, <void *u>)
//PEM_write_bio_RSAPublicKey(<BIO *bp>, <const RSA *x>)
PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);
PEM_write_bio_RSAPublicKey(pub, keypair);
size_t pri_len = BIO_pending(pri);
size_t pub_len = BIO_pending(pub);
char *pri_key= malloc(pri_len + 1);
char *pub_key= malloc(pub_len + 1);
BIO_read(pri,pri_key, (int)pri_len);
BIO_read(pub, pub_key, (int)pub_len);
pri_key[pri_len]='\0';
pub_key[pub_len]='\0';
printf("\n%s\n%s\n", pri_key,pub_key);
/*
*
* Deserialization of public key (char* pub ==> RSA *rpub)
* & Encryption
*
*/
BIO *rpub = BIO_new_mem_buf(pub_key, -1);
BIO_write(rpub, pub_key, (int)pub_len);
RSA *rsa_pubkey = NULL;
if (!PEM_read_bio_RSAPublicKey(rpub, &rsa_pubkey, NULL, NULL)) {
printf("PEM_read_bio_RSAPublicKey error\n");
//goto free_stuff;
}
unsigned char *ciphertxt= (unsigned char*) malloc(RSA_size(rsa_pubkey));
char *err= (char *)malloc(130);
printf("\nplain_txt len = %d\n", (int)strlen(msg));
int encrypt_len =0;
//RSA_PKCS1_OAEP_PADDING은 43byte정도 붙는다...
if((encrypt_len=RSA_public_encrypt((int)strlen(msg)+1, (unsigned char*)msg, ciphertxt, rsa_pubkey, RSA_PKCS1_OAEP_PADDING)) == -1){
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr,"Error Encrypting message : %s", err);
printf("RSA_public_encrypt error!!\n");
return -1;
}
printf("RSA_size(rsa_pubkey = %d, strlen(msg) = %d, encrypt_len = %d\n", RSA_size(rsa_pubkey), (int)strlen(msg), encrypt_len);
/*
*
* Deserialization of private key (char* pri ==> RSA *rpri)
* & Decryption
*
*/
BIO *rpri =BIO_new_mem_buf(pri_key,-1);
BIO_write(rpri, pri_key,(int)pri_len);
RSA *rsa_prikey =NULL;
if(!PEM_read_bio_RSAPrivateKey(rpri, &rsa_prikey, NULL, NULL)){
printf("PEM_read_bio_RSAPrivateKey error\n");
return -1;
}
unsigned char *decrypt =(unsigned char*) malloc(RSA_size(rsa_prikey));
int decrypt_len=-1;
// RSA_private_decrypt(<#int flen#>, <#const unsigned char *from#>, <#unsigned char *to#>, <#RSA *rsa#>, <#int padding#>)
if((decrypt_len=RSA_private_decrypt(encrypt_len, (unsigned char*)ciphertxt, decrypt, rsa_prikey, RSA_PKCS1_OAEP_PADDING)) == -1){
ERR_load_crypto_strings();
ERR_error_string(ERR_get_error(), err);
fprintf(stderr,"Error Decrypting message : %s\n", err);
printf("RSA_public_encrypt error!!\n");
return -1;
}
printf("RSA_size(rsa_prikey = %d, strlen(msg) = %d, encrypt_len = %d\n", RSA_size(rsa_prikey), (int)strlen(msg), encrypt_len);
printf("decrypt_len = %d\n", decrypt_len);
printf("decrypt: >>%s<<\n", decrypt);
return 0;
}
<<Output>>
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAuM3iHY9xbY5W6fJtS40n45/1qWYU4jSMRYkos5W4hHh62n1W
FSrTHS+gppXcovcAY2URrWLBRsBkPLPTOpOhi3TbyKANuiAQcFjuAROWsQDbAXRE
YPICl0BiJ2YWw2W+WmR21Sk+W9IYWFBuK1XuYpNt7ZLQitEiBW1NoOQr/ApoxTDD
ELqWBaTq4K94Z0cBCtYmbIbB+VUeQFR+YWeTYUMacw0Px5ZzqlnB8S7JA0eWyQ6I
oMtaj+yOA0kiJPFOzP/l+oUMZ1Z3oyd4Fv84XtN6X9a/+QbAjHa2Tv7gSb2bY6pC
dVQPFbSsrBs2XtSwWVFQLOrMZ5v0Cm5V64EqEwIBAwKCAQB7M+wTtPZJCY9GoZ4y
XhqXv/kbmWNBeF2DsMXNDnsC+vyRqOQOHIy+H8BvDpMXT1WXmLZzlyuEgELTIozR
t8EHoz0warPRarWgO0lWDQ8gqzyrothAoVcPgEFvmWSCQ9Q8QvnjcNQ9NrrlivQc
4/RBt56eYeBci2wDnjPAmB1SsHiDB/9q+LYSIkrYXs/c7jNKXP9q0RUmVtQJN1Ip
9tkZ6V8e2LXmKgezkydyFxP4h/nIkucx73L9Owla7RvIu+joz+QG0wHjFj+TNZga
3LaMq0LjCJBDVE44/tHmwxbPYbf0y43NS9JA3/l4G3YpubkNpr+EjEhjiM6I533D
8sy7AoGBAOinF22BsL/cVu5igvLcXwyAX7+m78PSfcSDXWinoc9HriW/rZRCjV7d
i/ooPeX0tc9jW48TT3wEn5Nbqs61jyl97v0LC6F/9aUsJZ7flMOU128nGXyUh9q9
QMleRHO8IrYC5bMt0N1isqo0eHufem2LWcpEGmmMFtIAnEejd4KlAoGBAMtZjVZu
lMUOGow5nk2/gqea6uelXV5tVRuvJBp6035ytuYFGmqrygk/cQydzkUZxdC41p7C
lLIPdGyfOqnCSEfx2RLlPOgSv3MaMXUPH2L2+ybkMGr/gHB5t7IWlcpWiFFxkzqT
kXZRsgxDeYmAw605fWah/fZGN+w8dtGiHXRXAoGBAJsaD55WddU9j0mXAfc9lLMA
P9UZ9S02/oMCPkXFFoovyW5/yQ2Bs5STsqbFfplNzopCPQoM36gDFQznxzR5Chup
Sf4HXRZVTm4dbmnqYy0N5PTEu6hjBTx+KzDpgvfSwc6smSIeiz5BzHF4UFJqUZ5c
5obYEZuyueFVvYUXpQHDAoGBAIeRCORJuINevF17vt5/rG+8nJpuPj7zjhJ0wrxR
4lRMee6uEZxyhrDU9ghpNC4RLosl5GnXDcwKTZ2/fHEsMC/2kLdDffAMf6IRdk4K
FOykp29CyvH/qvWmena5uTGPBYuhDNG3tk7hIV2CUQZV18jQ/kRr/qQuz/LS+eEW
vk2PAoGABSFzVqDSFJH3bxXO7MLEX64jEWAO9cxDSzOq9Phw7deFhqJWW9DsEYan
TBtw/qavAhMOavda2DW4HNcghR6glVAdi+uadMY5q75theBtM2Wtm7SgfM6fxNHQ
58O9fvzYiHTGE2ivTh8BC6RPslk1qCdlBVsGpb5qrTwrQZiN3Q4=
-----END RSA PRIVATE KEY-----
-----BEGIN RSA PUBLIC KEY-----
MIIBCAKCAQEAuM3iHY9xbY5W6fJtS40n45/1qWYU4jSMRYkos5W4hHh62n1WFSrT
HS+gppXcovcAY2URrWLBRsBkPLPTOpOhi3TbyKANuiAQcFjuAROWsQDbAXREYPIC
l0BiJ2YWw2W+WmR21Sk+W9IYWFBuK1XuYpNt7ZLQitEiBW1NoOQr/ApoxTDDELqW
BaTq4K94Z0cBCtYmbIbB+VUeQFR+YWeTYUMacw0Px5ZzqlnB8S7JA0eWyQ6IoMta
j+yOA0kiJPFOzP/l+oUMZ1Z3oyd4Fv84XtN6X9a/+QbAjHa2Tv7gSb2bY6pCdVQP
FbSsrBs2XtSwWVFQLOrMZ5v0Cm5V64EqEwIBAw==
-----END RSA PUBLIC KEY-----
plain_txt len = 41
RSA_size(rsa_pubkey = 256, strlen(msg) = 41, encrypt_len = 256
decrypt_len = 42
decrypt: >>Hello my name is Nugu??!!!! helhelhelhllo!!<<
'Security > Cryptography' 카테고리의 다른 글
(미완) [OpenSSL/ECDH] ECDH Cryptography Part1. (Serialization /Deserialization) (0) | 2018.11.29 |
---|---|
[OpenSSL/RSA] RSA Private key와 Public key 나누기!!(Serialization) (0) | 2018.11.21 |
[OpenSSL/RSA] RSA Sructure & Function (0) | 2018.11.15 |
CH.5 Openssl를 활용한 암호화 프로그래밍<EVP API를 활용한 AES_CBC 암호화 ver.1.> (1) | 2018.11.10 |
[OpenSSL] <openssl/evp.h>EVP 함수 정리 (0) | 2018.11.10 |