프로젝트 개요
기업 환경에서 중요 문서를 중앙 서버에서 관리하고, 외부 유출을 방지하는 문서 중앙화 시스템을 구현하고자 했던 프로젝트입니다. 결론적으로는 각 기능별 예제 구현까지는 성공했지만, 전체 통합에 실패하여 미완성으로 남은 프로젝트입니다.
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 클라이언트 파트와 최종 실패 원인을 정리합니다.
'勉強 > C,C++' 카테고리의 다른 글
| 문서 중앙화 DLP - Windows Minifilter 커널 드라이버 구현 (USB 차단, 파일 I/O 필터링, CDR 정사니타이징) (0) | 2026.06.02 |
|---|---|
| 연산자와 기초예제 (1) | 2024.01.09 |
| 사칙연산과 기초예제 (2) | 2024.01.05 |