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

Tags: ,

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.