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

아…마이크로소프트웨어…

 요즘 심심해서 하고 있는 마으크로 소프트웨어 예제 프로그램 따라 해보기…

  SSL 프로그래밍에 관련된 강의를 보고 예제 프로그램을 따라 해보던 중… 도저히 풀리지 않는 버그가 하나 있었다.

 난 단순히 예제 프로그램만 따라 쳤을 뿐인데…왜 안되는 것인지..

 그것이 문제였다.

 아무 생각없이 예제만 보고 그대로 따라 쳤던 것.

 처음보는 함수의 등장에도 그냥 아무런 의심없이 따라 쳤기에 그 함수가 무슨 일을 하는 것이고, 무슨 인자 값을 받아들이는지에 대한 프로토 타입도 읽어보지도 않은채…여과없이 받아 들여서 그랬던 것이다.

 몇 시간의 방황끝에 겨우 답을 찾았는데 함수 사용 설명서만 읽어도 충분했던 내용이었다.

 하하…. 🙂

문제가 되었던 함수 설명..

BIO_seek() sets the file position pointer to ofs bytes from start of file.

OpenlSSL – 데이터 복호화

//      dec_evp.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/err.h>
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/x509.h>
#include <openssl/rand.h>
#include <openssl/pem.h>

#define IN_FILE “encrypt.txt”
#define OUT_FILE “decrypt.txt”

unsigned char* readFile(char *file, int *readLen);
unsigned char* readFileBio(BIO *fileBIO, int *readLen);
unsigned char* addString(unsigned char *destString, int destLen, const unsigned char *addString, int addLen);

int main(int argc, char** argv)
{
    
    // 키와 IV 값은 직접 만든
    unsigned char key[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
    unsigned char iv[] = {1, 2, 3, 4, 5, 6, 7, 8};
    
    unsigned char* outbuf;    // 복호문이 저장될 버퍼
    int outlen, tmplen;
    
    BIO *errBIO = NULL;
    BIO *outBIO = NULL;
    
    // 에러 발생의 경우 해당 에러 스트링 출력을 위해 미리 에러 스트링들을 로딩.
    ERR_load_crypto_strings();
    
    // 표둔 화면 출력 BIO 생성
    if((errBIO = BIO_new(BIO_s_file())) != NULL)
        BIO_set_fp(errBIO, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
    
    // 파일 출력 BIO 생성
    outBIO = BIO_new_file(OUT_FILE, “wb”);
    
    if(!outBIO) {    // 에러가 발생한 경우
        BIO_printf(errBIO, “파일 [%s]을 생성하는데 에러가 발생 했습니다.”, OUT_FILE);
        ERR_print_errors(errBIO);
        exit(1);
    }
    
    // 파일에서 읽어오기
    int len;
    unsigned char* readBuffer = readFile(IN_FILE, &len);
    
    // 암호화 컨텍스트 EVP_CIPHER_CTX 생성, 초기화
    EVP_CIPHER_CTX ctx;
    EVP_CIPHER_CTX_init(&ctx);
    
    // 초기화
    EVP_DecryptInit_ex(&ctx, EVP_bf_cbc(), NULL, key, iv);
    
    // 초기화가 끝난후에 해야 한다. 복호문 저장할 버퍼 생성
    outbuf = (unsigned char*)malloc(sizeof(unsigned char) * len);
    
    // 업데이트, 마지막 블록을 제외하고 모두 복호화
    if(!EVP_DecryptUpdate(&ctx, outbuf, &outlen, readBuffer, len)) {
        return 0;
    }
    
    // 종료. 마지막 블록을 복호화
    if(!EVP_DecryptFinal_ex(&ctx, outbuf + outlen, &tmplen)) {
        return 0;
    }
    
    // 복호문 길이는 업데이트, 종료 과정에서 나온 결과의 합
    outlen += tmplen;
    EVP_CIPHER_CTX_cleanup(&ctx);
    
    BIO_printf(errBIO, “복호화가 완료되었습니다. 복호문은 다음과 같습니다.nn”);
    outbuf[outlen] = 0;
    printf(“%s”, outbuf);
    
    // 파일에 같은 내용을 출력한다.
    BIO_write(outBIO, outbuf, outlen);

    // 객체 제거
    BIO_free(outBIO);
    
    return 0;
}

unsigned char* readFile(char *file, int *readLen)
{
    unsigned char *retBuffer = NULL;
    unsigned char *buffer = NULL;
    int length = 0;
    
    // 파일 BIO 정의
    BIO *fileBIO = NULL;
    
    // 인자로 넘어온 파일을 열고, 파일 BIO 생성
    fileBIO = BIO_new_file(file, “rb”);
    
    if(!fileBIO) {    // 파일을 여는데 에러가 발생한 경우
        printf(“입력 파일 [%s] 을 여는데 에러가 발생 했습니다.n”, file);
        exit(1);
    }
    
    // 임시로 1000 바이트 만큼의 읽은 데이터를 저장할 버퍼 생성
    buffer = (unsigned char*)malloc(1001);
    *readLen = 0;
    
    while(1) {
        // 파일 BIO에서 1000 바이트 만큼 읽어서 buffer에 저장한다.
        length = BIO_read(fileBIO, buffer, 1000);
        
        // 안전을 위해 버퍼의 끝은 NULL로 채운다.
        buffer[length] = 0;
        
        // 임시로 읽은 1000바이트의 데이터를 리턴 버퍼에 더한다.
        retBuffer = addString(retBuffer, *readLen, buffer, length);
        
        // 지금까지 읽은 데이터의 길이를 더한다.
        *readLen = *readLen + length;
        
        // 만약 지금 파일에서 읽은 데이터의 길이가 꼭 1000 바이트라면 앞으로 더 읽을
        // 데이터가 없을 것이다. 하지만 1000 바이트보다 작다면 더 이상 읽을 데이터가
        // 없을 것이므로 종료한다.
        if(length == 1000)
            // 파일 포인터를 1000 바이트 뒤로 옮긴다.
            BIO_seek(fileBIO, 1000);
        else
            break;
    }
    
    // 객체 삭제
    BIO_free(fileBIO);
    free(buffer);
    
    return retBuffer;
    
}

unsigned char* readFileBio(BIO *fileBIO, int *readLen)
{
    unsigned char* retBuffer = NULL;
    // 임시로 1000바이트 만큼의 읽은 데이터를 저장할 버퍼 생성
    unsigned char* buffer = (unsigned char*)malloc(1001);
    int length = 0;
    
    *readLen = 0;
    
    while(1) {
        // 파일 BIO에서 1000바이트 만큼 읽어서 buffer에 저장한다.
        length = BIO_read(fileBIO, buffer, 1000);
        
        // 안전을 위해 버퍼의 끝은 NULL로 채운다
        buffer[length] = 0;
        
        // 임시로 읽은 1000바이트의 데이터 리턴 버퍼에 더한다.
        retBuffer = addString(retBuffer, *readLen, buffer, length);
        
        // 지금까지 읽은 데이터의 길이를 더한다.
        *readLen = *readLen + length;
        
        // 만약 지금 파일에서 읽은 데이터의 길이가 꼭 1000 바이트라면 앞으로 더 읽을
        // 데이터가 있을 것이다. 하지만 1000 바이트보다 작다면 더 이상 읽을 데이터가
        // 없을 것이므로 종료 한다.
        if(length == 1000)
            // 파일 포인터를 1000바이트 뒤로 옮긴다.
            BIO_seek(fileBIO, 1000);
        else
            break;
    }
    
    return retBuffer;
}

unsigned char* addString(unsigned char *destString, int destLen, const unsigned char *addString, int addLen)
{
    // 리턴 할 버퍼 정의
    unsigned char *retString;
    
    int i;
    
    // 만약 덧붙일 대상 버퍼가 NULL, 이거나 길이가 0이면 덧붙일 대상버퍼가 없는 경우
    // 이므로 새로 생성하고, 덧붙일 버퍼의 내용을 복사한다.
    if((destString == NULL) || (destLen == 0)) {
        // 덧붙일 버퍼의 길이 만큼의 버퍼 생성
        retString = (unsigned char*)malloc(sizeof(unsigned char) * (addLen + 1));
        // 덧붙일 버퍼의 내용을 새로운 버퍼에 복사
        for(i = 0; i < addLen; i++) {
            retString[i] = addString[i];
        }
        
        // 안전을 위해 버퍼의 마지막에 NULL 바이트를 붙인다.
        retString[i] = NULL;
    }
    else {    // 덧붙일 대상 버퍼가 있는 경우 이므로 대상 버퍼의 길이와 덧붙일 버퍼의 길이를
            // 더한 만큼의 버퍼를 새로 생성하고, 두 버퍼의 내용을 새로운 버터에 복사한다.
        retString = (unsigned char*)malloc(sizeof(unsigned char) * (destLen + addLen + 1));
        
        // 덧붙일 대상 버퍼 내용을 새로운 버퍼에 복사
        for(i = 0; i < destLen; i++) {
            retString[i] = destString[i];
        }
        
        // 덧붙일 버퍼의 내용을 새로운 버퍼에 복사
        for(i = 0; i < addLen; i++) {
            retString[i + destLen] = addString[i];
        }
        
        // 안전을 위해 버퍼의 마지막에 NULL 바이트를 붙인다.
        retString[i + destLen] = NULL;
    }
    
    // 메모리에서 삭제
    free(destString);
    
    return retString;
}