OpenlSSL – SSL 통신 클라이언트

//      SSL_Client.c
//      
//      Copyright 2009 Kim Sung-tae <pchero21@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <netdb.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/ssl.h>

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <arpa/inet.h>

#define PORT 7921
#define SERVER_ADDRESS “127.0.0.1”

int main(int argc, char** argv)
{
    char *server_name = SERVER_ADDRESS;
    unsigned short port = PORT;
    
    unsigned int addr;
    struct sockaddr_in server_add;
    struct hostent *host;
    
    int conn_socket;
    int socket_type = SOCK_STREAM;
    int retval;
    
    char *retString = NULL;
    
    const char *currentCipher;
    char buffer[1000];
    char message[100] = “이것은 클라이언트가 보내는 메시지입니다.”;
    
    // SSL 구조체 생성
    SSL_METHOD *meth;
    SSL_CTX *ctx;
    SSL *ssl;
    X509 *server_cert;
    
    BIO *errBIO;
    
    if((errBIO = BIO_new(BIO_s_file())) != NULL)
        BIO_set_fp(errBIO, stderr, BIO_NOCLOSE|BIO_FP_TEXT);
        
    SSL_load_error_strings();
    SSLeay_add_ssl_algorithms();
    meth = SSLv3_method();
    ctx = SSL_CTX_new(meth);
    
    if(ctx == NULL) {
        BIO_printf(errBIO, “SSL_CTX 생성 에러”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 서버 이름이 알파벳인 DNS로 되어 있을 경우
    if(isalpha(server_name[0])) {
        host = gethostbyname(server_name);
    }
    // 서버 이름이 IP 로 되어 있을 경우
    else {
        addr = inet_addr(server_name);
        host = gethostbyaddr((char *)&addr, 4, AF_INET);
    }
    
    if(host == NULL) {
        fprintf(stderr, “알 수 없는 주소[%s] 입니다!n”, server_name);
        exit(1);
    }
    
    memset(&server_add, 0, sizeof(server_add));
    memcpy(&(server_add.sin_addr), host->h_addr, host->h_length);
    server_add.sin_family = host->h_addrtype;
    server_add.sin_port = htons(port);
    
    conn_socket = socket(AF_INET, socket_type, 0);
    if(conn_socket < 0) {
        fprintf(stderr, “소켓 생성 에러!n”);
        exit(1);
    }
    
    printf(“[%s] 서버에 연결중…n”, server_name);
    if(connect(conn_socket, (struct sockaddr*)&server_add, sizeof(server_add)) == -1) {
        fprintf(stderr, “connect 에러!n”);
        exit(1);
    }
    
    // 세션 키를 만들기 위한 랜덤 수를 위한 Seed 공급
    printf(“랜덤 수 생성중…n”);
    RAND_status();
    printf(“랜덤 수 생성 완료!b”);
    
    ssl = SSL_new(ctx);
    if(ssl == NULL) {
        BIO_printf(errBIO, “SSL 생성 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    SSL_set_fd(ssl, conn_socket);
    retval = SSL_connect(ssl);
    if(retval == -1) {
        BIO_printf(errBIO, “SSL connect 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    currentCipher = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
    printf(“SSL 연결, 사용 알고리즘 파라메터: [%s]n”, currentCipher);
    
    server_cert = SSL_get_peer_certificate(ssl);
    if(server_cert == NULL) {
        BIO_printf(errBIO, “서버 인증서를 받을 수 없음.”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    printf(“Server certificate:n”);
    
    retString = NULL;
    
    // 주체의 DN을 문자열로 얻음
    retString = X509_NAME_oneline(X509_get_subject_name(server_cert), 0, 0);
    if(retString == NULL) {
        BIO_printf(errBIO, “서버 인증서에서 주체의 DN을 읽을 수 없음.”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    printf(“t subject: %sn”, retString);
    free(retString);
    
    // 발급자의 DN을 문자열로 얻음
    retString = X509_NAME_oneline(X509_get_issuer_name(server_cert), 0, 0);
    if(retString == NULL) {
        BIO_printf(errBIO, “서버 인증서에서 발급자의 DN을 읽을 수 없음.”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    printf(“t issuer: %sn”, retString);
    free(retString);
    
    X509_free(server_cert);
    
    retval = SSL_write(ssl, “hi!!_from client”, strlen(“hi!!_from client”));
    if(retval == -1) {
        BIO_printf(errBIO, “SSL write 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    retval = SSL_read(ssl, buffer, sizeof(buffer) – 1);
    if(retval == -1) {
        BIO_printf(errBIO, “SSL read 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    buffer[retval] = ‘’;
    printf(“서버로부터 데이터 전송: [%s], 길이:%dn”, buffer, retval);
    
    SSL_shutdown(ssl);
    
    close(conn_socket);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    
    return 0;
}
XUA8jQk84Z.c

OpenlSSL – SSL 통신 서버

//      SSL_Server.c
//      
//      Copyright 2009 Kim Sung-tae <pchero21@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/evp.h>
#include <openssl/crypto.h>
#include <openssl/ssl.h>

#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/types.h>

// 서버 포트와 IP 주소 정의
#define PORT 7921
#define SERVER_ADDRESS “127.0.0.1”

// 서버 인증서와 개인키 파일 정의
#define CERT_FILE    “rootcert.pem”
#define PRIVKEY_FILE    “rootkey.pem”

// SSL 핸드쉐이크 메시지 교환 과정을 알려주는 콜백함수
void ssl_info_callback(const SSL *s, int where, int ret);

// 화면에 표시하기 위한 파일 BIO 생성
BIO *errBIO;

int main(int argc, char** argv)
{
    unsigned short port = PORT;
    char *serverAddress = SERVER_ADDRESS;
    
    // 서버의 소켓 타입은 TCP 같은 연결형이다.
    int socket_type = SOCK_STREAM;
    struct sockaddr_in server_add, client_add;
    int server_socket, client_socket;
    
    socket_type = SOCK_STREAM;
    
    // SSL 구조체 생성
    SSL_METHOD *meth;
    SSL_CTX *ctx;
    SSL* ssl;
    
    int retval, client_addlen;
    const char *currentCipher;
    char inbuffer[1000];
    char message[100] = “이것은 서버로부터의 응답 메시지입니다.”;
    
    // 화면 출력 BIO 생성
    if((errBIO = BIO_new(BIO_s_file())) != NULL)
        BIO_set_fp(errBIO, stderr, BIO_NOCLOSE|BIO_FP_TEXT);
        
    // 모든 에러 스트링 로드
    SSL_load_error_strings();
    
    // 모든 알고리즘 로드
    SSLeay_add_ssl_algorithms();
    
    // SSL 버전3 프로토콜 사용
    meth = SSLv3_method();
    
    // SSL 컨텍스트 생성
    ctx = SSL_CTX_new(meth);
    if(ctx == NULL) {
        BIO_printf(errBIO, “SSL_CTX 생성 에러”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // SSL 핸드쉐이크 메시지교환 과정을 알려주는 콜백함수를 셋팅
    SSL_CTX_set_info_callback(ctx, ssl_info_callback);
    
    // 자신의 인증서를 파일에서 로딩한다.
    if(SSL_CTX_use_certificate_file(ctx, CERT_FILE, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 자신의 개인키를 파일에서 로딩한다.
    if(SSL_CTX_use_PrivateKey_file(ctx, PRIVKEY_FILE, SSL_FILETYPE_PEM) <= 0) {
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 읽은 인증서와 개인키가 맞는지 확인한다.
    if(!SSL_CTX_check_private_key(ctx)) {
        BIO_printf(errBIO, “인증서와 개인키가 맞지 않습니다.n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // sockaddr_in 구조체의 주소체계를 인터넷 주소체계로 한다.
    server_add.sin_family = AF_INET;
    
    // 서버의 주소를 인터넷 32비트 주소로 변환하여 sockaddr_in 에 넣는다.
    server_add.sin_addr.s_addr = inet_addr(serverAddress);
    
    // 네트워크 형식으로 포트번호를 변환하여 sockaddr_in에 넣는다.
    server_add.sin_port = htons(port);
    
    // 서버의 소켓을 생성한다.
    server_socket = socket(AF_INET, socket_type, 0);    // TCP socket
    if(server_socket == -1) {
        fprintf(stderr, “소켓 생성 에러 n”);
        exit(1);
    }
    
    // bind를 실행하여 서버 소켓과 서버 주소를 연결한다.
    retval = bind(server_socket, (struct sockaddr*)&server_add, sizeof(server_add));
    if(retval == -1) {
        fprintf(stderr, “bind 에러!n”);
        exit(1);
    }
    
    // listen 함수를 실행하여 클라이언트가 접속할 수 있는 최대 버퍼수를 5로 정한다
    retval = listen(server_socket, 5);
    if(retval == -1) {
        fprintf(stderr, “listen 에러!n”);
        exit(1);
    }
    
    printf(“주소 %s, 포트 %d 에서 클라이언트의 연결 기다림…n”, serverAddress, port);
    
    
    client_addlen = sizeof(client_add);
    
    // accept 함수를 실행 하여 클라이언트로부터의 접속을 기다린다.
    client_socket = accept(server_socket, (struct sockaddr*)&client_add, &client_addlen);
    if(client_socket == -1) {
        fprintf(stderr, “accept 에러!n”);
        exit(1);
    }
    
    // 클라이언트로부터의 접속, 연결
    printf(“클라이언트 연결, 주소: %s, 포트 %dn”, inet_ntoa(client_add.sin_addr), htons(client_add.sin_port));
    
    // SSL 구조체 생성
    ssl = SSL_new(ctx);
    if(ssl == NULL) {
        BIO_printf(errBIO, “SSL 생성 에러”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 연결된 소켓과 SSL과의 연결
    SSL_set_fd(ssl, client_socket);
    
    // 가장 중요한 함수, 클라이언트와의 초기 협상과정, 즉 핸드쉐이크 과정을 수행
    retval = SSL_accept(ssl);
    if(retval == -1) {
        BIO_printf(errBIO, “SSL accept 에러”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 현재 클라이언트와 정의된 암호화 파라메터정보를 얻음
    currentCipher = SSL_CIPHER_get_name(SSL_get_current_cipher(ssl));
    printf(“SSL 연결, 사용 알고리즘 파라메터 : [%s]n”, currentCipher);

 
    // 클라이언트로부터 SSL 통신을 통해 메시지 받음
    retval = SSL_read(ssl, inbuffer, sizeof(inbuffer) – 1);
    if(retval == -1) {
        BIO_printf(errBIO, “SSL read 에러”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 받은 데이터를 화면에 표시
    inbuffer[retval] = ‘’;
    printf(“클라이언트로부터 데이터 전송: [%s], 길이:[%d]n”, inbuffer, retval);

    // 클라이언트에게 SSL 통신을 통해 메시지 보냄
    retval = SSL_write(ssl, message, strlen(message));
    if(retval == -1) {
        BIO_printf(errBIO, “SSL write 에러!n”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 연결 해제 및 객체 제거
    printf(“연결 해제n”);
    close(client_socket);
    SSL_free(ssl);
    SSL_CTX_free(ctx);
    
    sleep(20000);

    
    return 0;
}

// SSL 핸드쉐이크 메시지 교환 과정을 알려주는 콜백함수
void ssl_info_callback(const SSL *s, int where, int ret)
{
    char *writeString;
    int w;
    
    // 현재 어떤 메시지 교환 과정인지를 나타냄
    w = where & ~SSL_ST_MASK;
    
    // 클라이언트가 연결 했을 때
    if(w & SSL_ST_CONNECT)
        writeString = “SSL_connect”;
    // 서버가 연결을 받았을 때
    else if (w & SSL_ST_ACCEPT)
        writeString = “SSL_accept”;
    // 알 수 없는 경우
    else
        writeString = “undefined”;
    
    // 일반적인 핸드쉐이크 프로토콜 메시지일 경우
    if(where & SSL_CB_LOOP) {
        // SSL_state_string_long(s) 함수로부터 현재 진행되는 메시지가 무엇인지 표시
        BIO_printf(errBIO, “%s:%sn”, writeString, SSL_state_string_long(s));
    }
    // alert 프로토콜일 경우
    else if(where & SSL_CB_ALERT) {
        writeString = (where & SSL_CB_READ)? “read”:”write”;
        BIO_printf(errBIO, “SSL3 alert %s:%s:%sn”, writeString, SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret));
    }
    else if(where & SSL_CB_EXIT) {
        // 종료 과정일 경우
        if(ret == 0)
            BIO_printf(errBIO, “%s:failed in %sn”, writeString, SSL_state_string_long(s));
        else if(ret < 0)
            BIO_printf(errBIO, “%s:error in %sn”, writeString, SSL_state_string_long(s));
    }
}

XUI3H1XICP.pemXQCYwl3nVb.pemXGXvAcHioM.c

OpenlSSL – 인증서 인증하기

//      Verify_Cert.c
//      
//      Copyright 2009 Kim Sung-tae <pchero21@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include <stdio.h>

#include <openssl/bio.h>
#include <openssl/conf.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/rand.h>
#include <openssl/pem.h>

#define CA_CERT_FILE    “rootcert.pem”
#define CRL_FILE        “testcrl.pem”
#define CERT_FILE        “newcert.pem”

int verifyCallbackfunc(int ok, X509_STORE_CTX *store)
{
    X509 *cert;
    
    if(!ok) {
        cert = X509_STORE_CTX_get_current_cert(store);
        printf(“error:%sn”, X509_verify_cert_error_string(store->error));
    }
    
    return ok;
}

int main(int argc, char** argv)
{
    BIO *bio_err;
    int retVal;
    char *retString;
    
    X509 *cert;
    X509_STORE *store;
    X509_LOOKUP *lookup;
    X509_STORE_CTX *storeCtx;
    
    BIO *certBIO = NULL;
    
    OpenSSL_add_all_algorithms();
    
    // 화면 출력용 BIO 생성
    if((bio_err = BIO_new(BIO_s_file())) != NULL)
        BIO_set_fp(bio_err, stderr, BIO_NOCLOSE|BIO_FP_TEXT);
    
    // 인증할 인증서를 읽기 위한 BIO 생성
    certBIO = BIO_new(BIO_s_file());
    if(BIO_read_filename(certBIO, CERT_FILE) <= 0) {
        BIO_printf(bio_err, “인증서 파일 [%s]을 여는데 에러가 발생 했습니다.”, CERT_FILE);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    // 인증할 인증서를 파일로부터 읽어 X509 구조체로 변환
    cert = PEM_read_bio_X509(certBIO, NULL, NULL, NULL);
    
    if(cert == NULL) {
        BIO_printf(bio_err, “CA 인증서를 로드할 수 없습니다.”);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    // 인증서를 저장할 STORE 구조체 생성
    store = X509_STORE_new();
    if(store == NULL) {
        BIO_printf(bio_err, “X509_STORE 를 생성할 수 없습니다.”);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    // 콜백 함수 설정
    X509_STORE_set_verify_cb_func(store, verifyCallbackfunc);
    
    // 파일로부터 CA 인증서 읽음
    if(!X509_STORE_load_locations(store, CA_CERT_FILE, NULL)) {
        BIO_printf(bio_err, “CA 인증서를 로드할 수 없습니다.”);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    // STORE에 CA 인증서 추가
    lookup = X509_STORE_add_lookup(store, X509_LOOKUP_file());
    if(lookup == NULL) {
        BIO_printf(bio_err, “X509_LOOKUP 를 생성할 수 없습니다.”);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    // CRL 읽음
    if(!X509_load_crl_file(lookup, CRL_FILE, X509_FILETYPE_PEM)) {
        BIO_printf(bio_err, “CRL을 로드 할 수 없습니다.”);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    // CA 인증서, CRL 인증 모두 지원
    X509_STORE_set_flags(store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
    
    // STORE 컨텍스트 생성
    storeCtx = X509_STORE_CTX_new();
    if(storeCtx == NULL) {
        BIO_printf(bio_err, “X509_STORE_CTX를 생성 할 수 없습니다.”);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    if(!X509_STORE_CTX_init(storeCtx, store, cert, NULL)) {
        BIO_printf(bio_err, “X509_STORE_CTX를 초기화 할 수 없습니다.”);
        ERR_print_errors(bio_err);
        exit(1);
    }
    
    // 인증서 인증
    retVal = X509_verify_cert(storeCtx);
    
    if(retVal == 1) {
        BIO_printf(bio_err, “인증 되었습니다.”);
    }
    else {
        BIO_printf(bio_err, “인증을 할 수 없습니다.”);
        ERR_print_errors(bio_err);
    }
    
    return 0;
}

XcClgYwHih.cXObk62k8pF.pemXKaRlaHhnu.pemXD8GYZUkIz.pem

OpenlSSL – RSA 패키지를 이용한 암호화 & 복호화

//      use_rsa.c
//      
//      Copyright 2009 Kim Sung-tae <pchero21@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include <stdio.h>
#include <string.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/pem.h>

int main(int argc, char** argv)
{
    // 변수 정의
    BIO *keyBIO = NULL;
    BIO *errBIO = NULL;
    BIO *rsa = NULL;
    
    char keyFile[100];
    char KeyFormat[10];
    char encType[10];
    char keyType[10];
    
    char inFile[100];
    char outFile[100];
    
    BIO *inBIO = NULL;
    BIO *outBIO = NULL;
    
    // 표준 화면 출력 BIO 생성
    if((errBIO = BIO_new(BIO_s_file())) != NULL)
        BIO_set_fp(errBIO, stderr, BIO_NOCLOSE|BIO_FP_TEXT);
        
    // 암호화를 한건지 복호화를 한 건지 선택
    printf(“암호화, 복호화 선택 (e,d): “);
    scanf(“%s”, encType);
    
    // 키를 공개키를 사용 할 건지, 개인키를 사용 할 건지 선택
    printf(“공개키, 개인키 선택(pri,pub): “);
    scanf(“%s”, keyType);
    
    // 키 파일명 입력
    printf(“키 파일을 입력 하세요: “);
    scanf(“%s”, keyFile);
    
    // 키 파일 형식 입력
    printf(“키 파일의 형식을 입력 하세요. (PEM,DER): “);
    scanf(“%s”, KeyFormat);
    
    // 입력 파일명 입력
    printf(“입력 파일명을 입력 하세요: “);
    scanf(“%s”, inFile);
    
    // 출력 파일명 입력
    printf(“출력 파일명을 입력 하세요: “);
    scanf(“%s”, outFile);
    
    // 키 파일 BIO 생성
    keyBIO = BIO_new(BIO_s_file());
    if(keyBIO == NULL) {
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 키 파일 읽음
    if(BIO_read_filename(keyBIO, keyFile) <= 0) {
        BIO_printf(errBIO, “키 파일 [%s]을 여는데 에러가 발생 했습니다.”, keyFile);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // DER 형식이면, 키 파일 BIO에서 키 내용을 읽어서 rsa 구조체 형식으로 변환
    if(strcmp(KeyFormat, “DER”) == 0) {
        // 개인키와 공개키에 따라서 다른 함수 사용
        if(strcmp(keyType, “pub”) == 0)
            rsa = d2i_RSAPublicKey_bio(keyBIO, NULL);
        else
            rsa = d2i_RSAPrivateKey_bio(keyBIO, NULL);
    }
    
    // PEM 형식이면, 키 파일 BIO에서 키 내용을 읽어서 rsa 구조체 형식으로 변환
    else if(strcmp(KeyFormat, “PEM”) == 0) {
        // 개인키와 공개키에 따라서 다른 함수 사용
        if(strcmp(keyType, “pub”) == 0)
            rsa = PEM_read_bio_RSA_PUBKEY(keyBIO, NULL, NULL, NULL);
        else
            rsa = PEM_read_bio_RSAPrivateKey(keyBIO, NULL, NULL, NULL);
    }
    else {
            BIO_printf(errBIO, “알 수 없는 포멧[%s] 입니다.”, KeyFormat);
    }
    
    // 키를 로드 하는데 에러 발생
    if(rsa == NULL) {
        BIO_printf(errBIO, “키를 로드 할 수 없습니다.”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 입력 파일에서 BIO 생성
    inBIO = BIO_new_file(inFile, “rb”);
    if(!inBIO) {
        BIO_printf(errBIO, “입력 파일 [%s]을 여는데 에러가 발생 했습니다.”, inFile);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 출력 파일에서 BIO 생성
    outBIO = BIO_new_file(outFile, “wb”);
    if(!outBIO) {
        BIO_printf(errBIO, “출력 파일 [%s]을 생성하는데 에러가 발생 했습니다.”, outFile);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 읽은 키의 길이를 얻음
    int keySize = RSA_size(rsa);
    
    // 입력문 내용이 들어갈 버퍼와, 출력문 내용이 들어갈 버퍼 생성
    // 입력 버퍼의 길이는 키 길이의 두배, 출력 버퍼는 키 길이와 동일
    unsigned char *inBuffer = (unsigned char *)malloc(keySize * 2);
    unsigned char *outBuffer = (unsigned char *)malloc(keySize);
    
    // 패딩 정의, 일반적인 패딩으로 사용
    unsigned char pad = RSA_PKCS1_PADDING;
    
    // 입력문 파일에서 내용 읽어 버퍼에 저장
    int inLength = BIO_read(inBIO, inBuffer, keySize * 2);
    
    int outLength = 0;
    
    // 공개키로 암호화 할때, 입력 버퍼의 내용을 암호화해서 출력 버퍼에 넣음
    if((strcmp(encType, “e”) == 0) && (strcmp(keyType, “pub”) == 0))
        outLength = RSA_public_encrypt(inLength, inBuffer, outBuffer, rsa, pad);
        
    // 개인키로 암호화 할때, 입력 버퍼의 내용을 암호화해서 출력 버퍼에 넣음
    else if((strcmp(encType, “e”) == 0) && (strcmp(keyType, “pri”) == 0))
        outLength = RSA_private_encrypt(inLength, inBuffer, outBuffer, rsa, pad);
        
    // 공캐키로 복호화 할때, 입력 버퍼의 내용을 복호화해서 출력 버퍼에 넣음
    else if((strcmp(encType, “d”) == 0) && (strcmp(keyType, “pub”) == 0))
        outLength = RSA_public_decrypt(inLength, inBuffer, outBuffer, rsa, pad);
        
    else if((strcmp(encType, “d”) == 0) && (strcmp(keyType, “pri”) == 0))
        outLength = RSA_private_decrypt(inLength, inBuffer, outBuffer, rsa, pad);
        
    // 암호화 혹은 복호화시 에러 발생 체크
    if(outLength <= 0) {
        BIO_printf(errBIO, “RSA 암호화시 에러 발생”);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 출력 파일에 출력 버퍼의 내용 저장
    BIO_write(outBIO, outBuffer, outLength);
    
    BIO_printf(errBIO, “완료 되었습니다.”);
    
    // 객체 제거
    if(keyBIO != NULL)
        BIO_free(keyBIO);
    if(rsa != NULL)
        RSA_free(rsa);
    
    free(inBuffer);
    free(outBuffer);
        
    
    return 0;
}

OpenlSSL – RSA 패키지를 이용한 공개키 & 개인키 만들기

//      enc_rsa.c
//      
//      Copyright 2009 Kim Sung-tae <pchero21@gmail.com>
//      
//      This program is free software; you can redistribute it and/or modify
//      it under the terms of the GNU General Public License as published by
//      the Free Software Foundation; either version 2 of the License, or
//      (at your option) any later version.
//      
//      This program is distributed in the hope that it will be useful,
//      but WITHOUT ANY WARRANTY; without even the implied warranty of
//      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//      GNU General Public License for more details.
//      
//      You should have received a copy of the GNU General Public License
//      along with this program; if not, write to the Free Software
//      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
//      MA 02110-1301, USA.

#include <stdio.h>
#include <string.h>

#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/rand.h>

#define true 1
#define false 0

// 콜백 함수 정의
static void genrsa_cb(int p, int n, void *arb);

int main(int argc, char** argv)
{
    
    int keyLenInput = 512;    // 키 길이
    char outPublicKeyFile[50];    // 공개키를 저장
    char outPrivateKeyFile[50];    // 개인키를 저장
    
    int isPem = true;    // PEM 형식으로…
    
    BIO *publicOut = NULL;    // 공개키가 저장되는 파일 BIO
    BIO *privateOut = NULL;    // 개인키가 저장되는 파일 BIO
    BIO *bio_stdout = NULL;    // 화면에 출력할 stdout BIO
    
    RSA *rsa = NULL;    // RSA 구조체
    
    printf(“키 길이 입력 :”);    // 키 길이 입력
    scanf(“%d”, &keyLenInput);
    
    printf(“저장할 공개키 파일 이름 입력: “);    // 공개키를 저장할 파일명 입력
    scanf(“%s”, outPublicKeyFile);
    
    printf(“저장할 개인키 파일 이름 입력: “);    // 개인키를 저장할 파일명 입력
    scanf(“%s”, outPrivateKeyFile);
    
    // 표준 화면 출력 BIO 생성
    if((bio_stdout = BIO_new(BIO_s_file())) != NULL) {
        BIO_set_fp(bio_stdout, stdout, BIO_NOCLOSE | BIO_FP_TEXT);
    }
    
     //공개키를 저장할 파일 BIO 생성
     if((publicOut = BIO_new(BIO_s_file())) == NULL) {
         printf(“BIO 생성 에러. %s”, outPublicKeyFile);
         exit(1);
     }
    
     // 개인키를 저장할 파일 BIO 생성
     if((privateOut = BIO_new(BIO_s_file())) == NULL) {
         printf(“BIO 생성 에러. %s”, outPublicKeyFile);
         exit(1);
     }
    
     // 파일 BIO와 해당 공개키 저장할 파일 연결
     if(BIO_write_filename(publicOut, outPublicKeyFile) <= 0) {
         printf(“BIO 생성 에러. %s”, outPublicKeyFile);
         exit(1);
     }
    
     // 파일 BIO와 해당 개인키 저장할 파일 연결
     if(BIO_write_filename(privateOut, outPrivateKeyFile) <= 0) {
         printf(“BIO 생성 에러. %s”, outPrivateKeyFile);
         exit(1);
     }
    
     RAND_status();    // seed 생성, 공급
    
     // 키 생성
     rsa = RSA_generate_key(keyLenInput, RSA_F4, genrsa_cb, NULL);
    
     if(isPem) {
         // PEM 포멧으로 표준 화면 출력 BIO에 공개키 출력
         if(!PEM_write_bio_RSA_PUBKEY(bio_stdout, rsa)) {
             printf(“PEM 파일 생성 에러 %s”, outPrivateKeyFile);
             exit(1);
         }
         printf(“nn”);
        
         // PEM 포멧으로 표준 화면 출력 BIO에 개인키 출력
         if(!PEM_write_bio_RSAPrivateKey(bio_stdout, rsa, NULL, NULL, 0, NULL, NULL)) {
             printf(“PEM 파일 생성 에러 %s”, outPrivateKeyFile);
             exit(1);
         }
        
         // PEM 포멧으로 파일 BIO에 공개키 출력
         if(!PEM_write_bio_RSA_PUBKEY(publicOut, rsa)) {
             printf(“PEM 파일 생성 에러 %s”, outPrivateKeyFile);
             exit(1);
         }
        
         // PEM 포멧으로 파일 BIO에 개인키 출력
         if(!PEM_write_bio_RSAPrivateKey(privateOut, rsa, NULL, NULL, 0, NULL, NULL)) {
             printf(“PEM 파일 생성 에러 %s”, outPrivateKeyFile);
             exit(1);
         }
     }
     else {    // 만약 DEM 포멧으로 키 쌍을 출력 한다면..
        printf(“DEM PUBLIC KEYn”);
        
        // DEM 포멧으로 표준 화면 출력 BIO에 공개키 출력
        if(!i2d_RSA_PUBKEY_bio(bio_stdout, rsa)) {
            printf(“DEM 파일 생성 에러 %s”, outPrivateKeyFile);
            exit(1);
        }
        
        printf(“nn”);
        printf(“DER PRIVATE KEYn”);
        printf(“n”);
        
        // DEM 포멧으로 표준 화면 출력 BIO에 개인키 출력
        if(!i2d_RSAPrivateKey_bio(bio_stdout, rsa)) {
            printf(“DEM 파일 생성 에러 %s”, outPrivateKeyFile);
            exit(1);
        }
        
        // DEM 포멧으로 파일 BIO에 공개키 출력
        if(!i2d_RSA_PUBKEY_bio(publicOut, rsa)) {
            printf(“DEM 파일 생성 에러 %s”, outPrivateKeyFile);
            exit(1);
        }
        
        // DEM 포멧으로 파일 BIO에 개인키 출력
        if(!i2d_RSAPrivateKey_bio(privateOut, rsa)) {
            printf(“DEM 파일 생성 에러 %s”, outPrivateKeyFile);
            exit(1);
        }
    }
    
    // RSA 구조체 메모리에서 삭제
    if(rsa != NULL)
        RSA_free(rsa);
        
    // BIO를 메모리에서 삭제
    if(publicOut != NULL) BIO_free_all(publicOut);
    if(privateOut != NULL) BIO_free_all(privateOut);
    
    
    return 0;
}

// 콜백 함수
static void genrsa_cb(int p, int n, void *arg)
{
    char c = ‘*’;
    
    // prime number e 의 생성 과정을 표시
    if(p == 0) c = ‘.’;
    if(p == 1) c = ‘+’;
    if(p == 2) c = ‘*’;
    if(p == 3) c = ‘n’;
    
    printf(“%c”, c);
}