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] RSA Private key와 Public key 나누기!!(Serialization) 본문

Security/Cryptography

[OpenSSL/RSA] RSA Private key와 Public key 나누기!!(Serialization)

us0 2018. 11. 21. 16:26

[OpenSSL/RSA] RSA Private key와 Public key 나누기!!




RSA에서 암호화 하기위해 공유키와 개인키를 각각 분리하기위해 아래의 3가지 과정을 거친다.


여기서 잠깐!!!

Q. 왜 굳이 공유키와 개인키를 분리 할까??

A. 상대방에게 내 개인키까지 굳이 보낼 필요가 없으므로!! 개인키는 나만의 것이기 때문에 public key와 private key를 각각 나눠준다!!! 



RSA *keyPair

/      \

/          \

/             \

BIO *pri           BIO *pub

/                           \

/                             \

/                               \

char *pri_key              char *pub_key




이번 포스팅은 

BIO 구조체에 PEM API를 써서 암호화 시켜서 private key 와 public key를 나눠 

char *형태 즉 문자열 형태로 반환하는 실습을 해보겠다!!


RSA 구조체같은 경우는 이미 설명을 

2018/11/15 - [Security/Cryptography] - [OpenSSL/RSA] RSA Sructure & Function

마쳤기 때문에  ...



일단 RSA 코드를 작성하기전에 BIO 라는 친구부터 무엇인지 살펴보자!! 


BIO를 할당 할때의  BIO를 살펴보자!!!! (또한 BIO가 무엇이냐??)

Q.     BIO가 뭐에용??
A.     아직 내 추측이지만 Openssl에서 제공하는 기본 Buffer Input Output 구조체로 할당전에 데이터를 
  보관하는 자료구조이다!! (스트림이라고 생각하자!!)



BIO 구조체를 어떤식으로 쓸까??

BIO의 데이터를 저장할수 있는 공간을 만들어주기 위해

#include<openssl/bio.h> 에있는 구조체를 선언해주고 BIO의 구조체에 해당하는 메모리를 할당해준다.



ex)          RSA *keypair = RSA_generate_key(KEY_LENGTH,PUB_EXP, NULL, NULL)        //RSA의 public키와 private 키 RSA구조체에 저장!!

BIO *pri = BIO_new(BIO_s_mem());

BIO *pub = BIO_new(BIO_s_mem());


BIO *pri = BIO_new(BIO_s_mem()); >> BIO 구조체인 pri메모리 공간을 steam형식의 메모리로 생성해준다라는 뜻으로 생강!!!


KEY_LENGTH란 RSA에서의 mod연산 즉 RSA 연산에 사용되는 N의 값을 할당해주는 것이다. 

PUB_EXP 는 e 를 할당해주는것!! 

(여기선 각각 2048과 3 할당)



TMI ========================================================================


여기서 말하는 N과 e란??


RSA의 공개키와 개인키를 구하는 과정인데


1)    서로 다른 큰 소수 p와 q를 선택한다. 

2)    n= p*q를 계산한다. 

3)    φ(n)=(p-1)(q-1)를 계산한다. 

4)    φ(n)보다 작고 φ(n)과 서로소인 임의의 자연수 e를 선택한다. (gcd(e, φ(n))=1, 1 < e < φ(n)에 만족하는 e 선택) 

5)    확장 유클리드 호제법을 이용하여 e mod φ(n)에 대한 곱의 역원, 즉 ed mod φ(n)=1인 d를 구한다.


 (ed≡ 1 mod φ(n), 1 < d < φ(n)에 만족하는 d 값) 6)    공개키: KU= {e, n} 7)    개인키: KR= {d, n}


여기서의 N과 e를 말한다.




============================================================================


먼저 RSA구조체의 값을 위와 같이 RSA_generate_key()함수를 통해 키값을 할당해주고 각각 

BIO_new(BIO_s_mem())의 해석을 대충 추측해 보자면 BIO_new 라는 함수를 통해 BIO자료구조를 생성해 주고 BIO_new의 매개변수인 BIO_s_mem()의 값을 리턴받아 그에 해당하는 자료구조를 pri라는 구조체 변수가 값을 갖게 되는 것ㅇㅣ다!!!

//내추측이지만 BIO_s_mem()함수는 아마 BIO메모리를 할당하는 malloc같은 존재(??)  <맞는듯??>


(함수 할당 실패 시 NULL을 반환하니 할당체크 if 문도 나중에 넣어주자 ㅎㅎ)

ex)    if( pri == NULL){

printf("allocated error!!");

return -1;

}        //이런식으루



그럼 이제 우리는 BIO이라는 자료구조 메모리 공간이 만들어진 것이다!!

그럼 메모리를 만들었으니 이친구들에게 각각 어떤 값을 할당해줘야 할것이다ㅇㅂㅇ 우리는 private 와 public을 나눈다고 했으니 아래를 봐보자 (아래는 함수 원형이다)

//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>)


이친구들은 openssl/pem.h 헤더파일에있어 #include<openssl/pem.h>를 include 시켜줘야한다!!!


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_RSPrivateKey( 입력받을 BIO자료구조 공간 , RSA의 정보를가지고있는 구조체, 어떤 암호화를 써서 비밀키를 암호화 할것인지(?), 3번째 매개변수 key의 길이, (??), (??))

라는 것을 추측해 볼수 있다.                             //(더 공부하다가 알게되면 부족한부분(물음표 부분 ㅎ.ㅎ) 더 채워야겠당)



PEM_write_bio_RSAPublicKey(<BIO *bp>, <const RSA *x>) 

그리고 이 함수의 원형은 아래와 같은 뜻을 가지겠다.

PEM_write_bio_RSAPublicKey( 입력받을 BIO자료구조 공간,  RSA구조체의 정보 );

즉, RSA구조체정보를 통해 BIO자료구조 공간에 public key를 저장한다.



따라서 우리는 이것을 코드를 쓸때


    PEM_write_bio_RSAPrivateKey(pri, keypair, NULL, NULL, 0, NULL, NULL);    //BIO구조체 pri에 keypair에서의 private키를 추출!!

    PEM_write_bio_RSAPublicKey(pub, keypair);     //BIO구조체 pub에 keypair에서의 public키를 추출!!


이런식으로 써준다.    //각각의 의미는 주석처리 되어있다.


/*******************************************************************************************************

ps. 여기서 PEM이 도대체 뭐야?? 라는 생각을 할 수 있는데

PEM이란?? Privacy Enhanced Mail의 약자로 포맷파일의 약자라고 생각하면 된다. 따라서  우리가 지정해줬던 Public key를 char * 으로 지정 후

(지금은 BIO) 끝에 '\0'(NULL)를 넣고 printf("%s", pub_key) 하면 아래처럼 base64인코딩 형식으로 나온다.


 하지만 아직 문자열 char형으로 바꿔주지 않았기때문에 이는 조금 이따 해보쟈!!


     ex)    —–BEGIN PUBLIC KEY—–

MIIBJDANBgkqhkiG9w0BAQEFAAOCAREAMIIBDAKCAQMlsYv184kJfRcjeGa7Uc/4

3pIkU3SevEA7CZXJfA44bUbBYcrf93xphg2uR5HCFM+Eh6qqnybpIKl3g0kGA4rv

tcMIJ9/PP8npdpVE+U4Hzf4IcgOaOmJiEWZ4smH7LWudMlOekqFTs2dWKbqzlC59

NeMPfu9avxxQ15fQzIjhvcz9GhLqb373XDcn298ueA80KK6Pek+3qJ8YSjZQMrFT

+EJehFdQ6yt6vALcFc4CB1B6qVCGO7hICngCjdYpeZRNbGM/r6ED5Nsozof1oMbt

Si8mZEJ/Vlx3gathkUVtlxx/+jlScjdM7AFV5fkRidt0LkwosDoPoRz/sDFz0qTM

5q5TAgMBAAE=

—–END PUBLIC KEY—–

*******************************************************************************************************/



자 여기까지 BIO구조체에 private 와 public key의 정보를 각각 받아뒀다. 그럼 이제 char형으로 변환시켜야하니


size_t pri_len = BIO_pending(pri);

size_t pub_len = BIO_pending(pub);    //size_t 는 unsigned int 자료형


를 각각 선언해준다. BIO_pending 이는 BIO 구조체 pri, pub에 들어있는 size를 반환해준다  

그리고 다음으로 이를 통해 동적할당할 공간을 생성해주고  

그 공간에 BIO구조체에 있는 public키와 private키를 각각의 문자열로 만들어보


char *pri_key = malloc(pri_len + 1);            //1을 더해준 이유는 NULL을 끝에 붙여 문자열로 만들기 위해서이다.

char *pub_key = malloc(pub_len + 1);        // pub와 pri 키를 담을수 있는 공간 할당!!


 BIO_read(pri,pri_key, (int)pri_len);            //이건 BIO구조체의 값을(매개변수 1<pri>) pri_key에 pri_len 만큼 할당해 주는 함수이다!! 

 BIO_read(pub, pub_key, (int)pub_len);    //함수의 원형은 아래에 ㅇㅂㅇ


ps. BIO_read(<BIO *b>, <void *data>, <int len>)

앞서 주석문으로 말했듯이 BIO *b에 있는 데이터를 void *data에  int len의 길이만큼 쓰는것!!!!



다시 돌아와서 마지막 인덱스에 NULL을 넣어주면 완성이다!! (문자열 끝은?? 항상 NULL!!!!) 


pri_key[pri_len]='\0';

        pub_key[pub_len]='\0';

        printf("\n%s\n%s\n", pri_key,pub_key);


이상 출력을 하게되면 이렇게 나온다!!!!



-----BEGIN RSA PRIVATE KEY-----

MIIEowIBAAKCAQEAl9divqDOSnvT9Cqtvs6ha2/toSC1AaiKr+CUqE9sc81w/ilz

25+M2M5o5fOkKwDTiLjpx8rIFch2CXzPdQ7J9jLRq2+iLl+BaSsXHsr/MuAbQTSU

FrDVJOmaw9YDmfMxcvTQhDG6KakCleK+7I/0lidjPslJRkhWUdwG8AUjJ96M581i

DJqUW+91n4vddjsjPHuMoZxeYlNxweXypoRPFXbkVlRxF9mHSLZOcUbL691/GX6m

e68zsIcbOI0ofASptR6wuszbq0ljwOYvRdCM0t3nQTHlnKt2C6IWbWQ2AWNtx1Tb

JZn6KNjg+FrRkSJ8p40hT4mWUuezrpKSi22tfwIBAwKCAQBlOkHUazQxp+Kixx5/

NGuc9UkWFc4BGwcf6w3FikhNM6CpcPfnv7M7NEXuom1yAI0F0JvahzAOhaQGUzT4

tIakIeEc9RbJlQDwx2S/Mf93QBIreGK5yzjDRmctOVe793ZMozWtdnwbxgG5QdSd

tU25b5d/MNuEMDmL6ASgA2zFPgG4xuBOVkOxOiYNW+YlS+VKDu6Cq7gds4/5/jcV

G/Bm9BNsFKcPQYv9oSObmBbA864Cd8N4t63iRZbtrWmPHRjDLRzkuJZ6+OLJHQKs

LBz13K8V0hSeXoj3y6QR9pKIJLrxNDssC9mfXUWXYFrANFITpEOYc9gtkLhNMklO

S7brAoGBAMZFebFWkO2M7mjXFLMtetnTq9Qc/7IiB2zlIy5DovQUDJPhVaCjwYqK

SS4i7fZtoRSWOJ3M9l6zHh7kTjqInm/jV3D+i0gDylHsKc5hZ02BE3jHMOcSRTMO

MQh6NeVu5px3lvxHp7RDjqueFTkMRDb5DFdXsX0ZExoY+mfNZHPPAoGBAMQNKWBA

iEFFKdO0bVEQznF5uVLAmxgTvqzlxXHDN3Jm/DNS39XdNarB+2rk9LNczuV/kmN5

pVAqAJnvus+cupStA5RlLLHvCb2nENziJxPg/2fZRd+c2HWJv5fYPHTGRbjl74Yb

4H92Pkz3NRBkj8qRCmSTKlT1e4UhzLzIl6dRAoGBAIQuUSDkYJ5d9EXkuHdzpzvi

co1oqnbBWkiYwh7XwfgNXbfrjmsX1lxcMMlsnqRJFg25exPd+ZR3aWntiXxbFEqX

j6CpsjAChuFIG97rmjOrYlCEy0S22My0ILBReUOfRGhPuf2FGngtCce+uNCy2CSm

CDo6dlNmDLwQpu/eQvffAoGBAIKzcOrVsCuDcTfNnjYLNEume4yAZ2Vifx3ug6Es

z6GZ/XeMlTk+I8cr/PHt+HeTNJj/tuz7w4rGqxFKfIpofGMeAmLuHcv0sSkaCz3s

Gg1AqkU7g+pokE5b1Q/lfaMu2SXun669QFT5ft36I2BDCocLXEMMxuNOUljBMyiF

um+LAoGBAMC1SmlaG+nqn0Rlz28UeMox1sf8F3q/ObZVzZJ0zqMJfDyzszvnZRBO

5U4O90W29Z9BpQ52BT+rcQLBCaABYY9nQ48G++XGIbrgp0DiiETRgC60Ui5cTBHb

0wX3ugLEiaVa6CpXVQRQ5LUdm5WLv7PjUBMbzi7vndgVK8O7PC0j

-----END RSA PRIVATE KEY-----


-----BEGIN RSA PUBLIC KEY-----

MIIBCAKCAQEAl9divqDOSnvT9Cqtvs6ha2/toSC1AaiKr+CUqE9sc81w/ilz25+M

2M5o5fOkKwDTiLjpx8rIFch2CXzPdQ7J9jLRq2+iLl+BaSsXHsr/MuAbQTSUFrDV

JOmaw9YDmfMxcvTQhDG6KakCleK+7I/0lidjPslJRkhWUdwG8AUjJ96M581iDJqU

W+91n4vddjsjPHuMoZxeYlNxweXypoRPFXbkVlRxF9mHSLZOcUbL691/GX6me68z

sIcbOI0ofASptR6wuszbq0ljwOYvRdCM0t3nQTHlnKt2C6IWbWQ2AWNtx1TbJZn6

KNjg+FrRkSJ8p40hT4mWUuezrpKSi22tfwIBAw==

-----END RSA PUBLIC KEY-----



이렇게 되면 이번 chapter의 목표인 private key 와 public key나누기가 완성이 된것!!!!!!!

이것을보고 Serialization이라고 한다.


그럼 이 char형의 문자열을인 key를 통해서 다시 RSA구조체 keypair 만드는 작업을 Deserialization이ㄹㅏ고 한다 



이건 다음 Chapter에서 해보자 ㅎ.ㅎ 








ps. BIO함수 더 보고싶은사람 보기

int BIO_read(BIO *b, void *buf, int len);
int BIO_write(BIO *b, const void *buf, int len);
int BIO_gets(BIO *b, char *buf, int size);
int BIO_puts(BIO *b, const char *buf);

위 함수들은 read(), write(), gets(), puts() 함수와 동일한 방법으로 사용됩니다. 에러가 발생한다면 0이나 -1을 리턴하고, select(), poll()과 같은 입출력 다중화 함수와 함께 사용이 가능합니다.





지금까지 했던 코드 결합



#include <stdio.h>

#include<stdlib.h>

#include<string.h>


#include<openssl/bio.h>

#include<openssl/rsa.h>

#include<openssl/pem.h>

#include<openssl/err.h>



//읽어 들이는 바이트 수

#define KEY_LENGTH 2048

#define PUB_EXP 3


//void ErrorCheck_malloc();


int main(int argc, char **argv){

    

    

    //keypair생성!!

    //RSA_generate_key(<#int bits#>, <#unsigned long e#>, <#void (*callback)(int, int, void *)#>, <#void *cb_arg#>)

    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의 존재를 알려주는 역할들!!

    //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);

    

    return 0;

}





<< output >>


-----BEGIN RSA PRIVATE KEY-----

MIIEowIBAAKCAQEAyTNteqvyfZlcSpEDZdwO1pm1sVaJM86Rk0v2XT6AuDxP1Ni5

IrOH3i99RnyWf8k5nUsW9P11Dbxp2Cv+GxP5SWIXv8td1ixs2/buJoovp+bdkc6k

+8ixpw5AKgLBSxbmJSN5Z/e5dt95Iv9tyDTV70LUduXXo77QmfYIQvNjYfkxo1Rb

gyzamFDpnhRu9RE+spq1kWzVNEz0bhulYmbqdMC0dCj4tBfbOc/YXocwm4h+oHiP

6q+j7in6H8kL7I9bfxH129ptROt9JjIfNuNJHVwdOL08aAfX6BRYI2SdtxocaDBM

/3wTmwhZRfNpjGeoItx3WnQn7c7gWzzUPnLIewIBAwKCAQEAhiJI/HKhqRDoMbYC

Q+gJ5GZ5IORbd98Lt4f5k38AetLf4zsmFyJalB+o2ahkVTDRE4dko1OjXn2b5XKp

Z2KmMOwP1TI+jshIkqSexFwfxUSTtonDUoXLxLQqxqyA3Lnuw2z7mqUmTz+mF1Tz

2s3j9Nc4T0PlF9SLEU6wLKJCQU+cdJ3ojbGZItSyKQ9O/hJmzuVjrd84xahyTlG2

tzdppptPUCIgnUfR2aARXqnCE6cvEgf0Sin6x2r3sxXtLiC5aTGZejGPJZzQEra0

Rz5ppWUZ4jITM1JZMJhHSTRnFvo8hx82do6F7m5EsSS64/qyfs+FZXTbD45oxwhA

IMBVywKBgQDy69+0yuAToBsS40M26y8eDKY6bysFFhAA8E9Oq+9qY8hZlVXVUuTf

uOQ0TZNLblYc1AGaqjOV9/VZ62mFgn1U7SOXGJg1WyI2VeEHlfE/SiUnyYMYztMP

HESyaHiSsmEJncRRu869qrPcV/0lFUCse0QZSLjmLegeHucjvdR0GQKBgQDUCIfJ

48JhQ/bLfTpBjMaGb5xlnXL69cBICFHEo6Rhlw9j5p/ydUdAunuKAvVCD7ebMWsG

0T0VyxQsp76ipODwdCP4i/fhMV4OtD8JNhRrWx9Om+8GzDlDAus6zR1wYkG3/70p

kdeNCq8V5D8sIS7v6WEV+Yv5KJElEclQT33TswKBgQCh8pUjMeq3wBIMl4IknMoU

CG7Rn3IDZAqrSt+Jx/Txl9rmY46ON0M/0Jgi3mIySY694qu8cXe5T/jmnPEDrFON

820PZbrOPMF5jpYFDqDU3BjFMQIQieIKEth28FBhzECxE9g2fTR+cc09j/4YuNXI

Ui1mMHtEHpq+v0TCfo2iuwKBgQCNWwUxQoGWLU8yU3wrsy8ESmhDvkynToAwBYvY

bRhBD1+X7xVMTi+AfFJcAfjWtSUSIPIEi34Oh2LIb9RsbetK+Bf7B/qWIOlfItSw

zrhHkhTfEp9Z3XuCAfInM2j1ltZ6qn4bto+zXHS5QtTIFh9Km5YOpl1QxbYYtoY1

ilPidwKBgCQQxmMNy5o56GaNUhjt7EkA4d/BXD1CLnNF9YQYUUiuVx+vPKGNqpQN

/89RAMTlsVCDmr4DIf3a6TCPQSUFlo4EvQuCzvD01AlmthPKLbsDGbc6bhzMyF3V

eUSrpElIIyYdAOzGZBjoHziNvbodiuEFB/zjc+q+4bkxUhv1fCmv

-----END RSA PRIVATE KEY-----


-----BEGIN RSA PUBLIC KEY-----

MIIBCAKCAQEAyTNteqvyfZlcSpEDZdwO1pm1sVaJM86Rk0v2XT6AuDxP1Ni5IrOH

3i99RnyWf8k5nUsW9P11Dbxp2Cv+GxP5SWIXv8td1ixs2/buJoovp+bdkc6k+8ix

pw5AKgLBSxbmJSN5Z/e5dt95Iv9tyDTV70LUduXXo77QmfYIQvNjYfkxo1Rbgyza

mFDpnhRu9RE+spq1kWzVNEz0bhulYmbqdMC0dCj4tBfbOc/YXocwm4h+oHiP6q+j

7in6H8kL7I9bfxH129ptROt9JjIfNuNJHVwdOL08aAfX6BRYI2SdtxocaDBM/3wT

mwhZRfNpjGeoItx3WnQn7c7gWzzUPnLIewIBAw==

-----END RSA PUBLIC KEY-----