🔒 보안

AES

Advanced Encryption Standard

대칭키 암호화 표준. 128/192/256비트 키를 지원하며, 전 세계적으로 가장 널리 사용되는 블록 암호 알고리즘입니다. 데이터 암호화의 사실상 표준입니다.

📖 상세 설명

AES(Advanced Encryption Standard)는 2001년 NIST가 DES를 대체하기 위해 선정한 대칭키 블록 암호 알고리즘입니다. 벨기에 암호학자 Joan Daemen과 Vincent Rijmen이 개발한 Rijndael 알고리즘이 공개 경쟁을 통해 선정되었습니다. AES는 128비트 고정 블록 크기를 사용하며, 키 길이에 따라 AES-128(10라운드), AES-192(12라운드), AES-256(14라운드)로 구분됩니다. 현재까지 알려진 실용적 공격이 없어 가장 안전한 대칭키 암호로 인정받습니다.

AES의 내부 구조는 SubBytes(바이트 치환), ShiftRows(행 이동), MixColumns(열 혼합), AddRoundKey(라운드 키 덧셈) 4가지 변환으로 구성됩니다. 각 라운드에서 이 변환들을 순차적으로 적용하여 평문을 암호문으로 변환합니다. 하드웨어 가속(AES-NI)을 지원하는 CPU에서는 초당 수 기가바이트의 암호화 성능을 달성할 수 있습니다. 이러한 효율성 덕분에 TLS, IPsec, 디스크 암호화 등 거의 모든 보안 프로토콜에서 AES를 사용합니다.

AES는 운영 모드(Mode of Operation)와 함께 사용해야 합니다. ECB(Electronic Codebook)는 동일 평문이 동일 암호문을 생성하므로 보안에 취약합니다. CBC(Cipher Block Chaining)는 IV(초기화 벡터)를 사용하여 패턴을 숨기지만 병렬화가 어렵습니다. 현대적 용도에서는 GCM(Galois/Counter Mode)이 권장되며, 암호화와 인증(AEAD)을 동시에 제공합니다. CTR 모드는 병렬 처리가 가능하여 고성능 환경에서 선호됩니다.

AI/ML 시스템에서 AES는 모델 가중치, 학습 데이터, 추론 결과의 암호화에 필수적입니다. 클라우드 ML 플랫폼은 저장 데이터(at-rest)와 전송 데이터(in-transit) 모두 AES-256-GCM으로 보호합니다. 연합학습에서 클라이언트-서버 간 그래디언트 교환도 AES로 암호화됩니다. 양자 컴퓨터 시대에 대비하여 AES-256은 Grover 알고리즘에 대해서도 128비트 보안 강도를 유지하므로 장기 보안에 적합합니다.

💻 코드 예제

# AES-256-GCM 암호화/복호화 - Python cryptography 라이브러리
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os
import base64

class AESEncryptor:
    """AES-256-GCM 암호화 클래스"""

    def __init__(self, key: bytes = None):
        """
        Args:
            key: 32바이트(256비트) 키. None이면 랜덤 생성
        """
        self.key = key or AESGCM.generate_key(bit_length=256)
        self.aesgcm = AESGCM(self.key)

    def encrypt(self, plaintext: bytes, associated_data: bytes = None) -> dict:
        """
        데이터 암호화

        Args:
            plaintext: 암호화할 데이터
            associated_data: 인증할 추가 데이터 (암호화되지 않음)

        Returns:
            dict: nonce, ciphertext, tag 포함
        """
        # 96비트(12바이트) nonce - GCM 권장 크기
        nonce = os.urandom(12)

        # 암호화 (GCM은 ciphertext에 tag 포함)
        ciphertext = self.aesgcm.encrypt(nonce, plaintext, associated_data)

        return {
            'nonce': base64.b64encode(nonce).decode(),
            'ciphertext': base64.b64encode(ciphertext).decode(),
            'aad': base64.b64encode(associated_data).decode() if associated_data else None
        }

    def decrypt(self, encrypted_data: dict) -> bytes:
        """
        데이터 복호화

        Args:
            encrypted_data: encrypt()의 반환값

        Returns:
            bytes: 복호화된 원본 데이터
        """
        nonce = base64.b64decode(encrypted_data['nonce'])
        ciphertext = base64.b64decode(encrypted_data['ciphertext'])
        aad = base64.b64decode(encrypted_data['aad']) if encrypted_data.get('aad') else None

        return self.aesgcm.decrypt(nonce, ciphertext, aad)

# 사용 예시
if __name__ == "__main__":
    # 암호화 객체 생성
    encryptor = AESEncryptor()

    # ML 모델 가중치 암호화 예시
    model_weights = b"tensor([[0.1, 0.2], [0.3, 0.4]])"
    model_metadata = b"model_v1.0"  # 인증할 메타데이터

    # 암호화
    encrypted = encryptor.encrypt(model_weights, model_metadata)
    print(f"Encrypted: {encrypted['ciphertext'][:50]}...")

    # 복호화
    decrypted = encryptor.decrypt(encrypted)
    print(f"Decrypted: {decrypted.decode()}")

    # 키 저장 (안전하게 보관 필요!)
    print(f"Key (base64): {base64.b64encode(encryptor.key).decode()}")
// AES-256-GCM 암호화/복호화 - Node.js crypto 모듈
const crypto = require('crypto');

class AESEncryptor {
    constructor(key = null) {
        // 32바이트(256비트) 키
        this.key = key || crypto.randomBytes(32);
        this.algorithm = 'aes-256-gcm';
    }

    /**
     * 데이터 암호화
     * @param {Buffer|string} plaintext - 암호화할 데이터
     * @param {Buffer|string} aad - 추가 인증 데이터 (선택)
     * @returns {Object} - iv, ciphertext, authTag, aad
     */
    encrypt(plaintext, aad = null) {
        // 12바이트 IV (GCM 권장)
        const iv = crypto.randomBytes(12);
        const cipher = crypto.createCipheriv(this.algorithm, this.key, iv);

        // AAD 설정 (있는 경우)
        if (aad) {
            cipher.setAAD(Buffer.from(aad));
        }

        // 암호화
        const plaintextBuffer = Buffer.from(plaintext);
        const encrypted = Buffer.concat([
            cipher.update(plaintextBuffer),
            cipher.final()
        ]);

        // 인증 태그 (16바이트)
        const authTag = cipher.getAuthTag();

        return {
            iv: iv.toString('base64'),
            ciphertext: encrypted.toString('base64'),
            authTag: authTag.toString('base64'),
            aad: aad ? Buffer.from(aad).toString('base64') : null
        };
    }

    /**
     * 데이터 복호화
     * @param {Object} encryptedData - encrypt()의 반환값
     * @returns {Buffer} - 복호화된 데이터
     */
    decrypt(encryptedData) {
        const iv = Buffer.from(encryptedData.iv, 'base64');
        const ciphertext = Buffer.from(encryptedData.ciphertext, 'base64');
        const authTag = Buffer.from(encryptedData.authTag, 'base64');

        const decipher = crypto.createDecipheriv(this.algorithm, this.key, iv);
        decipher.setAuthTag(authTag);

        // AAD 설정 (있는 경우)
        if (encryptedData.aad) {
            const aad = Buffer.from(encryptedData.aad, 'base64');
            decipher.setAAD(aad);
        }

        // 복호화
        return Buffer.concat([
            decipher.update(ciphertext),
            decipher.final()
        ]);
    }

    // 키를 Base64로 내보내기
    exportKey() {
        return this.key.toString('base64');
    }
}

// 사용 예시
const encryptor = new AESEncryptor();

// API 응답 데이터 암호화
const sensitiveData = JSON.stringify({
    userId: "user123",
    predictions: [0.85, 0.12, 0.03]
});

// 암호화
const encrypted = encryptor.encrypt(sensitiveData, "api-response-v1");
console.log("Encrypted:", encrypted);

// 복호화
const decrypted = encryptor.decrypt(encrypted);
console.log("Decrypted:", decrypted.toString());

// 키 내보내기
console.log("Key:", encryptor.exportKey());
# AES-256 암호화/복호화 - OpenSSL CLI

# 1. 랜덤 키 생성 (32바이트 = 256비트)
openssl rand -base64 32 > aes_key.txt

# 2. 파일 암호화 (AES-256-CBC)
# -pbkdf2: 비밀번호 기반 키 파생 (권장)
# -iter: PBKDF2 반복 횟수
openssl enc -aes-256-cbc -pbkdf2 -iter 100000 \
    -in model_weights.bin \
    -out model_weights.enc \
    -pass file:aes_key.txt

# 3. 파일 복호화
openssl enc -aes-256-cbc -pbkdf2 -iter 100000 -d \
    -in model_weights.enc \
    -out model_weights_decrypted.bin \
    -pass file:aes_key.txt

# 4. AES-256-GCM으로 암호화 (인증 암호화)
# GCM은 enc 명령어로 직접 지원하지 않으므로 openssl 명령어 사용
# 또는 프로그래밍 방식 권장

# 5. 대용량 파일 스트리밍 암호화 (파이프라인)
cat large_dataset.csv | \
    openssl enc -aes-256-cbc -pbkdf2 -iter 100000 -pass file:aes_key.txt | \
    gzip > large_dataset.csv.enc.gz

# 6. 스트리밍 복호화
gunzip -c large_dataset.csv.enc.gz | \
    openssl enc -aes-256-cbc -pbkdf2 -iter 100000 -d -pass file:aes_key.txt \
    > large_dataset_restored.csv

# 7. 키 정보 확인
# AES-256 키는 32바이트(256비트)
echo "Key length: $(cat aes_key.txt | base64 -d | wc -c) bytes"

# 8. 암호화 알고리즘 목록 확인
openssl enc -list | grep aes

# 9. 벤치마크 (AES 성능 테스트)
openssl speed aes-256-cbc aes-256-gcm

# 10. 실무 팁: 환경변수로 키 전달 (파일 노출 방지)
export AES_KEY=$(openssl rand -base64 32)
echo "secret data" | openssl enc -aes-256-cbc -pbkdf2 -pass env:AES_KEY

🗣️ 실무에서 이렇게 말하세요

💬 보안 아키텍처 설계 회의에서
"저장 데이터는 AES-256-GCM으로 암호화하고, 키는 AWS KMS에서 관리합시다. GCM 모드는 암호화와 무결성 검증을 동시에 제공해서 별도 HMAC이 필요 없습니다. ECB 모드는 절대 사용하지 마세요."
💬 ML 모델 보안 검토에서
"학습된 모델 가중치를 S3에 저장할 때 서버 측 암호화(SSE-S3)가 기본이지만, 더 강력한 통제가 필요하면 고객 관리 키(SSE-KMS)로 AES-256 암호화하세요. 키 접근 로그도 CloudTrail에 남습니다."
💬 성능 최적화 논의에서
"AES-NI 지원 CPU에서는 GCM 모드가 CBC보다 빠릅니다. 우리 API 서버 벤치마크 결과 AES-256-GCM이 10GB/s 이상 나와요. 암호화 오버헤드 걱정 없이 모든 응답을 암호화해도 됩니다."

⚠️ 주의사항 & 베스트 프랙티스

ECB 모드 사용 금지

ECB(Electronic Codebook) 모드는 동일한 평문 블록이 동일한 암호문을 생성합니다. 이미지 암호화 시 원본 패턴이 드러나는 "펭귄 문제"가 대표적입니다. 항상 CBC, CTR, GCM 모드를 사용하세요.

IV/Nonce 재사용 금지

같은 키로 같은 IV/Nonce를 재사용하면 암호화가 완전히 무력화됩니다. 특히 GCM 모드에서 nonce 재사용은 인증 키까지 노출시킵니다. 매 암호화마다 암호학적으로 안전한 랜덤 값을 생성하세요.

키를 코드에 하드코딩

암호화 키를 소스 코드에 직접 작성하면 Git 히스토리, 로그, 메모리 덤프 등에서 노출됩니다. AWS KMS, HashiCorp Vault, 환경변수 등 안전한 키 관리 시스템을 사용하세요.

AES 베스트 프랙티스

AES-256-GCM을 기본으로 사용하세요. 키는 HSM 또는 KMS에서 관리하고, 키 로테이션 정책을 수립하세요. 암호화된 데이터와 키를 절대 같은 위치에 저장하지 마세요. 정기적으로 암호화 라이브러리를 업데이트하세요.

🔗 관련 용어

📚 더 배우기