US0
[OpenSSL/RSA] RSA Private key와 Public key 나누기!!(Serialization) 본문
[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의 데이터를 저장할수 있는 공간을 만들어주기 위해
#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-----
'Security > Cryptography' 카테고리의 다른 글
(미완) [OpenSSL/ECDH] ECDH Cryptography Part1. (Serialization /Deserialization) (0) | 2018.11.29 |
---|---|
[OpenSSL/RSA] 나눴던 Private Key로 다시 RSA구조체 만들고 암/복호화 하기!!(Deserialization) (0) | 2018.11.24 |
[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 |