Notice
Recent Posts
Recent Comments
Link
«   2025/02   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28
Tags
more
Archives
Today
Total
관리 메뉴

US0

[OpenSSL/RSA] 나눴던 Private Key로 다시 RSA구조체 만들고 암/복호화 하기!!(Deserialization) 본문

Security/Cryptography

[OpenSSL/RSA] 나눴던 Private Key로 다시 RSA구조체 만들고 암/복호화 하기!!(Deserialization)

us0 2018. 11. 24. 03:49

[OpenSSL/RSA] 나눴던 Private Key로 다시 RSA구조체 만들고 암/복호화 하기!!(Deserialization)


우리는 저번 포스팅때 RSA keypair를 char * 형 문자열로 바꿔서 공개키와 비밀키를 나누는

과정을 해보았다!!! 

2018/11/21 - [Security/Cryptography] - [OpenSSL/RSA] RSA Private key와 Public key 나누기!!(Serialization)


이과정 다음을 바로 이어서 설명 하겠다.(이전 단계의 변수들 그대로 사용!!)


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, NULLNULL)){

        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!!<<