본문 바로가기

勉強/C,C++

문서 중앙화 프로젝트 - Linux inotify + OpenSSL AES-128 파일 자동 암호화 구현

프로젝트 개요

기업 환경에서 중요 문서를 중앙 서버에서 관리하고, 외부 유출을 방지하는 문서 중앙화 시스템을 구현하고자 했던 프로젝트입니다. 결론적으로는 각 기능별 예제 구현까지는 성공했지만, 전체 통합에 실패하여 미완성으로 남은 프로젝트입니다.

GitHub: https://github.com/LEntropy/Document_Management-Failed-

전체 시스템 아키텍처

구성 요소 기술 역할
Linux 서버 Ubuntu / C Samba 파일 서버, inotify 감시, OpenSSL 암호화
Windows 클라이언트 C# WinForms SMB 드라이브 연결, USB 차단, 화면잠금, 소켓 통신
관리자 앱 C# WinForms 회원 관리, 클라이언트 원격 제어
DB MariaDB / MySQL 계정 관리, 암호화 키·IV 저장

Linux 서버 파트 - 구현 목표

  • Samba로 /share 폴더를 네트워크 공유
  • inotify로 공유 폴더 파일 생성/삭제 이벤트 감지
  • 새 파일이 생성되면 OpenSSL AES-128-CBC로 즉시 암호화
  • 암호화 Key·IV를 MySQL DB에 저장 (파일명과 함께)
  • 원본 파일 삭제 → 암호화 파일(.enc)만 서버에 보관

구현 1 - OpenSSL AES-128-CBC 암호화 기초 (opensslex01.c)

OpenSSL EVP 인터페이스로 AES-128-CBC 암호화/복호화를 구현한 기초 예제입니다.

#include <openssl/rand.h>
#include <openssl/evp.h>

#define NUM_BYTES_READ 32

int main() {
    EVP_CIPHER_CTX* ctx_enc = EVP_CIPHER_CTX_new();
    EVP_CipherInit_ex(ctx_enc, EVP_aes_128_cbc(), NULL, NULL, NULL, 1);

    // 랜덤 Key·IV 생성
    unsigned char* key = malloc(EVP_CIPHER_CTX_key_length(ctx_enc));  // 16 bytes
    unsigned char* iv  = malloc(EVP_CIPHER_CTX_iv_length(ctx_enc));   // 16 bytes
    RAND_bytes(key, EVP_CIPHER_CTX_key_length(ctx_enc));
    RAND_bytes(iv,  EVP_CIPHER_CTX_iv_length(ctx_enc));

    // 파일 암호화
    FILE* ifp = fopen("/share/test.txt", "r");
    FILE* ofp = fopen("/share/test.enc", "w");
    do_crypt(key, iv, ifp, ofp, 1);  // 1 = 암호화
    fclose(ifp); fclose(ofp);

    // 복호화 검증
    FILE* lis = fopen("/share/test.enc", "r");
    FILE* los = fopen("/share/result.txt", "w");
    do_crypt(key, iv, lis, los, 0);  // 0 = 복호화
    fclose(lis); fclose(los);
}

do_crypt 함수 (암호화/복호화 공통)

int do_crypt(const unsigned char* key, const unsigned char* iv,
             FILE* fip, FILE* ofp, int isEncrypt) {
    EVP_CIPHER_CTX* ctx = EVP_CIPHER_CTX_new();
    EVP_CipherInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv, isEncrypt);

    unsigned char* input_buf  = malloc(NUM_BYTES_READ);
    unsigned char* output_buf = malloc(NUM_BYTES_READ + EVP_CIPHER_CTX_block_size(ctx));

    int inlen = 0, outtxtlen = 0;

    while (1) {
        inlen = fread(input_buf, 1, NUM_BYTES_READ, fip);
        if (inlen <= 0) break;

        EVP_CipherUpdate(ctx, output_buf, &outtxtlen, input_buf, inlen);
        fwrite(output_buf, 1, outtxtlen, ofp);
    }

    EVP_CipherFinal(ctx, output_buf, &outtxtlen);  // 마지막 블록 패딩 처리
    fwrite(output_buf, 1, outtxtlen, ofp);

    EVP_CIPHER_CTX_free(ctx);
    free(input_buf); free(output_buf);
    return 0;
}

⚠️ AES-128-CBC 특성: 블록 단위(16 bytes)로 처리되므로 마지막 블록은 EVP_CipherFinal로 패딩을 처리해야 합니다.

구현 2 - inotify + OpenSSL + MySQL 통합 (inotifyex01.c)

파일 감시(inotify)와 암호화(OpenSSL), DB 저장(MySQL)을 하나로 합친 핵심 서버 코드입니다.

inotify 초기화 및 감시 등록

#include <sys/inotify.h>

#define PATH_TARGET_DIR  "/share"
#define INTY_MAX_EVENTS  1024
#define INTY_EVENT_SIZE  (sizeof(struct inotify_event))
#define INTY_BUF_SIZE    (INTY_MAX_EVENTS * (INTY_EVENT_SIZE + 16))

int inty_fd = inotify_init();                  // inotify 인스턴스 생성
int inty_wd = inotify_add_watch(
    inty_fd, PATH_TARGET_DIR,
    IN_CREATE | IN_DELETE                       // 생성·삭제 이벤트 감시
);

이벤트 처리 루프

char inty_buffer[INTY_BUF_SIZE];

while (true) {
    int inty_length = read(inty_fd, inty_buffer, INTY_BUF_SIZE);

    int inty_idx = 0;
    while (inty_idx < inty_length) {
        struct inotify_event* event =
            (struct inotify_event*)&inty_buffer[inty_idx];

        if (event->len) {
            char* enc_ext = strstr(event->name, ".enc");   // 이미 암호화된 파일
            char* swp_ext = strstr(event->name, ".swp");   // vim 임시파일

            // 새 파일 생성 + .enc/.swp 아닌 경우만 암호화
            if ((event->mask & IN_CREATE) && enc_ext == NULL && swp_ext == NULL) {

                char fn_input[50], fn_output[100];
                sprintf(fn_input,  "/share/%s",      event->name);
                sprintf(fn_output, "/share/%s.enc",  event->name);

                FILE* ifp = fopen(fn_input,  "r");
                FILE* ofp = fopen(fn_output, "w");

                do_crypt(key, iv, ifp, ofp, 1);   // AES-128-CBC 암호화

                fclose(ifp); fclose(ofp);
                remove(fn_input);                  // 원본 파일 삭제

                // DB에 key, iv, 파일명 저장
                char sql[255];
                sprintf(sql,
                    "INSERT INTO openssl (key, iv, filename) VALUES('%s','%s','%s')",
                    key, iv, fn_output);
                mysql_query(conn, sql);
            }
        }
        inty_idx += INTY_EVENT_SIZE + event->len;
    }
}

MySQL 연결

MYSQL* conn;
conn = mysql_init(NULL);
mysql_real_connect(conn, "192.168.0.24", "root", "security", NULL, 3307, NULL, 0);
mysql_select_db(conn, "my_site");

구현 결과 및 동작 확인

  • ✅ OpenSSL AES-128-CBC 암호화/복호화 정상 동작 확인
  • ✅ inotify로 /share 폴더 파일 생성 이벤트 감지 성공
  • ✅ 파일 생성 시 자동 .enc 암호화 파일 생성 및 원본 삭제 확인
  • ✅ MySQL에 key·iv·파일명 INSERT 성공
  • ⚠️ Key/IV가 메모리에만 존재 - 서버 재시작 시 기존 파일 복호화 불가 문제 존재

왜 실패했나 - Linux 파트의 한계

문제 내용
Key 관리 미흡 Key·IV가 런타임 메모리에만 존재. 서버 재시작 시 기존 .enc 파일 영구 복호화 불가
Samba 권한 설계 미완 사용자별 접근 권한 분리 없이 모든 Samba 사용자가 /share 공유 접근 가능
C# 클라이언트와 연동 미완 서버의 복호화 기능을 클라이언트 요청 시 제공하는 API 미구현
통합 빌드 환경 부재 Linux C 코드와 Windows C# 코드를 함께 빌드·테스트하는 환경 구성 실패

다음 포스팅(C# 카테고리)에서 Windows 클라이언트 파트와 최종 실패 원인을 정리합니다.


undefined