Upgrade openssl-1.0.1 on Debian 6

Freeswitch 를 설치하는데 openssl-1.0 이상 버전을 요구했다.

현재 운용중인 서버 버전은 Debian-6.0
apt-get 으로 설치 가능한 openssl 버전은 0.9.x 버전이었다.

 

즉, openssl 버전 문제로 정상적인 설치가 안되는 상황.
openssl 최신버전이야 소스 설치를 하면 되겠는데.. 문제는 이미 사용중인 openssl-0.9.x 버전은 어떻게 하느냐였다.
이미 많은 수의 패키지들이 라이브러리를 참조하고 있었다.
실제로 apt-get remove 명령어로 해당 패키지를 지워볼까 생각도 했는데, 의존성 문제로 상당히 많은 수의 패키지들을 같이 지워야 해서 관두었다.

어쩔까…
Linux HanIRC 채널에 문의를 해보니 다행히 답변이 나왔다.

그냥 덮어쓰면 된다는 것.

 wget http://openssl.org/source/openssl-1.0.1.tar.gz 
 tar xfz openssl-1.0.1.tar.gz 
 cd openssl-* 
 ./config --prefix=/usr zlib-dynamic --openssldir=/etc/ssl shared 
 make 
 sudo make install

 

출처 : http://mariobrandt.de/archives/linux/upgrading-openssl-on-debian-6-squeeze-or-ubuntu-8-04-hardy-456

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;
}