Skip to content

drsungwon/hybrid_encryption

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Python 하이브리드 암호화 예제 (RSA + AES)

alt text alt text alt text

이 프로젝트는 RSA(비대칭키)와 AES(대칭키)를 결합한 하이브리드 암호화(Hybrid Encryption) 방식을 사용하여 데이터를 안전하게 전송하는 방법을 보여주는 Python 예제입니다.

'학생'(송신자)이 '교수'(수신자)의 공개키를 사용하여 메시지를 암호화하고, '교수'는 자신의 개인키로만 이 메시지를 복호화할 수 있는 시나리오를 기반으로 합니다.

하이브리드 암호화의 작동 원리

이 시스템은 RSA의 안전성과 AES의 효율성을 모두 활용합니다.

  • AES (대칭키 암호화): 매우 빠른 속도로 대용량 데이터를 암호화하는 데 사용됩니다. 하지만 암/복호화에 동일한 키를 사용하므로, 이 키를 상대방에게 안전하게 전달하는 것이 중요합니다.
  • RSA (비대칭키 암호화): 공개키와 개인키 쌍으로 작동합니다. 속도는 느리지만, 공개키로 암호화된 내용은 해당 개인키를 가진 사람만 열어볼 수 있어 키를 안전하게 교환하는 데 적합합니다.

암호화 과정 (학생 측)

  1. 데이터를 암호화할 **임시 대칭키(AES 세션키)**를 무작위로 생성합니다.
  2. AES 세션키를 사용해 실제 데이터를 빠르고 효율적으로 암호화합니다.
  3. 데이터 암호화에 사용된 AES 세션키를 교수의 RSA 공개키로 암호화합니다.
  4. [RSA로 암호화된 세션키] + [암호화된 데이터의 길이] + [AES로 암호화된 데이터]를 하나로 합쳐서 교수에게 전송합니다.

복호화 과정 (교수 측)

  1. 수신한 데이터에서 [RSA로 암호화된 세션키] 부분을 분리합니다.
  2. 자신만 가진 RSA 개인키로 이것을 복호화하여 원본 AES 세션키를 얻습니다.
  3. 복원된 AES 세션키를 사용하여 [AES로 암호화된 데이터] 부분을 복호화하여 원본 데이터를 확인합니다.

프로젝트 구조

.
├── generate_keys.py    # RSA 공개키/개인키 쌍을 생성하는 유틸리티
├── crypto.py           # 실제 암호화 및 복호화 로직을 담은 라이브러리
├── private_key.pem     # 생성된 RSA 개인키 (외부 유출 금지!)
└── public_key.pem      # 생성된 RSA 공개키 (데이터 암호화 시 사용)

설치 방법

  1. 프로젝트 클론

    git clone https://github.com/your-username/your-repository-name.git
    cd your-repository-name
  2. 가상 환경 생성 및 활성화 (권장)

    python -m venv venv
    source venv/bin/activate  # macOS/Linux
    # venv\Scripts\activate   # Windows
  3. 필요한 라이브러리 설치 프로젝트는 cryptography 라이브러리를 사용합니다.

    pip install cryptography

사용 방법

1단계: RSA 키 쌍 생성 (수신자/교수 측)

먼저, 암/복호화에 사용할 RSA 키 쌍을 생성해야 합니다. 이 작업은 최초 1회만 수행하면 됩니다.

python generate_keys.py

실행 후, 프로젝트 폴더에 private_key.pem(개인키)과 public_key.pem(공개키) 파일이 생성됩니다.

⚠️ 중요: private_key.pem 파일은 절대 외부에 공유하거나 유출해서는 안 됩니다. 이 키는 데이터를 복호화할 수 있는 유일한 열쇠입니다.

2단계: 공개키 설정 (송신자/학생 측)

데이터를 암호화하는 측(학생)은 수신자(교수)의 공개키를 알아야 합니다.

  1. public_key.pem 파일을 엽니다.
  2. -----BEGIN PUBLIC KEY----- 부터 -----END PUBLIC KEY----- 까지의 모든 내용을 복사합니다.
  3. crypto.py 파일을 열고, PROFESSOR_PUBLIC_KEY 상수의 따옴표 안에 복사한 내용을 붙여넣습니다.
# crypto.py
# ...
PROFESSOR_PUBLIC_KEY = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApLrm3+PqnidkFIh8BGpY
r1MhGF7MTwzrE5h3wQfx37/X65Tw7qh62D9E3kn7WdW7ETVaKb0nRTv0Ym265Fdv
... (여기에 public_key.pem 내용을 붙여넣으세요) ...
HwIDAQAB
-----END PUBLIC KEY-----
"""
# ...

3단계: 암호화 및 복호화 예제 실행

아래 예제 코드를 example.py 와 같이 새로운 파일로 만들어 실행하면 전체 암/복호화 과정을 테스트할 수 있습니다.

example.py

import struct
from cryptography.hazmat.primitives import serialization
from crypto import encrypt_data, decrypt_data, RSA_ENCRYPTED_KEY_SIZE

def load_private_key(filepath: str = "private_key.pem"):
    """PEM 파일에서 개인키를 로드합니다."""
    try:
        with open(filepath, "rb") as key_file:
            private_key = serialization.load_pem_private_key(
                key_file.read(),
                password=None,
            )
        return private_key
    except FileNotFoundError:
        print(f"🚫 '{filepath}'를 찾을 수 없습니다. 먼저 generate_keys.py를 실행하세요.")
        return None

def main():
    # 1. 암호화할 원본 데이터
    original_data = "이것은 교수님께 보내는 비밀 메시지입니다. This is a secret message for the professor.".encode('utf-8')
    print(f"🔒 원본 데이터: {original_data.decode('utf-8')}\n")

    # 2. 데이터 암호화 (학생 측)
    encrypted_blob = encrypt_data(original_data)
    if not encrypted_blob:
        print("암호화에 실패했습니다.")
        return

    print(f"📦 암호화된 전체 데이터 (Hex): {encrypted_blob.hex()}")
    print(f"   - 전체 길이: {len(encrypted_blob)} 바이트\n")

    # --- 데이터 전송 ---
    
    # 3. 데이터 복호화 (교수 측)
    print("--- 수신자 측에서 복호화 시작 ---\n")

    # 3-1. 개인키 로드
    professor_private_key = load_private_key()
    if not professor_private_key:
        return

    # 3-2. 수신된 데이터 분리
    # [RSA암호화된 키][데이터길이][AES암호화된 데이터] 형식으로 구성됨
    rsa_key = encrypted_blob[:RSA_ENCRYPTED_KEY_SIZE]
    
    # 데이터 길이를 읽어 AES 데이터 부분을 정확히 분리
    aes_data_len_bytes = encrypted_blob[RSA_ENCRYPTED_KEY_SIZE : RSA_ENCRYPTED_KEY_SIZE + 4]
    aes_data_len = struct.unpack('>I', aes_data_len_bytes)[0]
    aes_data_start = RSA_ENCRYPTED_KEY_SIZE + 4
    aes_data = encrypted_blob[aes_data_start : aes_data_start + aes_data_len]

    print(f"分解된 정보:")
    print(f"  - RSA 암호화 키 길이: {len(rsa_key)}")
    print(f"  - AES 암호화 데이터 길이: {len(aes_data)} (헤더값: {aes_data_len})\n")

    # 3-3. 데이터 복호화
    decrypted_data = decrypt_data(rsa_key, aes_data, professor_private_key)

    if decrypted_data:
        print(f"🗝️  복호화된 데이터: {decrypted_data.decode('utf-8')}\n")
        # 3-4. 원본과 비교
        assert original_data == decrypted_data
        print("✅ 데이터 무결성 확인 완료: 원본과 복호화된 데이터가 일치합니다.")
    else:
        print("❌ 복호화에 실패했습니다.")


if __name__ == '__main__':
    main()

예제 실행

python example.py

예상 출력 결과

🔒 원본 데이터: 이것은 교수님께 보내는 비밀 메시지입니다. This is a secret message for the professor.

📦 암호화된 전체 데이터 (Hex): ... (긴 16진수 문자열) ...
   - 전체 길이: 364 바이트

--- 수신자 측에서 복호화 시작 ---

分解된 정보:
  - RSA 암호화 키 길이: 256
  - AES 암호화 데이터 길이: 104 (헤더값: 104)

🗝️  복호화된 데이터: 이것은 교수님께 보내는 비밀 메시지입니다. This is a secret message for the professor.

✅ 데이터 무결성 확인 완료: 원본과 복호화된 데이터가 일치합니다.

추가 정보: 키(Key) 관리 방식

이 프로젝트에서 사용되는 두 종류의 키(RSA, AES)는 생성 시점과 생명 주기가 완전히 다릅니다. 이 차이를 이해하는 것은 하이브리드 암호화 시스템의 보안을 이해하는 데 매우 중요합니다.

1. RSA 키 (private_key.pem / public_key.pem) - "영구 마스터키"

  • 언제 생성되나요?

    • 사용자가 generate_keys.py수동으로 실행할 때 단 한 번 생성됩니다.
  • 매번 같은 값인가요?

    • 아니요. generate_keys.py를 실행할 때마다 암호학적으로 안전한 난수를 기반으로 항상 새롭고 예측 불가능한 키 쌍이 만들어집니다.
  • 어떻게 관리해야 하나요?

    • 이 키 쌍은 장기적으로 사용하는 것을 전제로 합니다. 수신자(교수)의 '신원'과 같아서, 한번 생성하면 키가 유출되지 않는 한 계속 사용합니다.
    • 만약 키를 변경하고 싶다면, generate_keys.py를 다시 실행하고, 생성된 새로운 public_key.pem의 내용을 반드시 crypto.py에 업데이트해야 합니다. 그렇지 않으면 복호화가 불가능합니다.

비유: generate_keys.py은행 금고와 그 금고의 마스터키를 만드는 과정과 같습니다. 한번 만들면 그 금고와 열쇠는 계속 사용합니다. 보안 문제(키 유출 등)가 생기면 아예 새로운 금고와 열쇠 세트로 교체해야 합니다.

2. AES 키 (세션 키) - "일회용 임시 키"

  • 언제 생성되나요?

    • crypto.pyencrypt_data() 함수가 호출될 때마다 매번 자동으로 생성됩니다.
  • 사용자가 설정할 필요가 있나요?

    • 아니요, 전혀 없습니다. 프로그램이 암호화할 때마다 내부적으로 항상 다른, 새로운 키를 만들도록 완벽하게 자동화되어 있습니다.
    • os.urandom() 함수가 매번 예측 불가능한 난수를 생성하여 키를 만들기 때문입니다.
  • 왜 이렇게 하나요? (전방향 안전성, Forward Secrecy)

    • 이 방식은 보안을 극대화합니다. 각 메시지가 고유한 일회용 키로 암호화되므로, 만약 공격자가 과거에 전송된 메시지 하나를 해독하는 데 성공하더라도, 그 정보는 오직 그 메시지 하나에만 유효합니다. 다른 메시지들(과거 또는 미래의)은 전혀 다른 키로 암호화되었기 때문에 안전하게 유지됩니다.

비유: 데이터를 보낼 때마다 매번 새로운 택배 상자와 새로운 일회용 자물쇠를 사용하는 것과 같습니다. 내용물을 상자에 넣고 자물쇠로 잠근 뒤, 그 자물쇠 열쇠를 받는 사람의 개인 금고(RSA 공개키)에만 넣을 수 있는 안전한 캡슐에 담아 함께 보냅니다. 다음 데이터를 보낼 땐 또 다른 상자와 자물쇠를 사용합니다.

About

Hybrid RSA+AES Enctyption

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages