2.6 암호연산

개요

데이터의 기밀성, 무결성, 인증 등을 보장하기 위해 암호 기술을 사용하는 것은 현대 소프트웨어 보안의 필수 요소입니다. 하지만 암호 기술을 올바르게 선택하고 적용하지 않으면 오히려 보안 취약점을 야기할 수 있습니다. 예를 들어, 이미 취약점이 발견된 오래된 암호 알고리즘(DES, MD5, SHA-1 등)을 사용하거나, 안전하지 않은 운영 모드(ECB 등)를 사용하거나, 초기화 벡터(IV) 또는 Nonce를 부적절하게 관리하는 경우 암호화된 데이터가 해독되거나 위변조될 위험이 있습니다.

이 기준은 소프트웨어 개발 시 검증된 안전한 암호 알고리즘을 선택하고, 올바른 운영 모드, 키 길이, 초기화 벡터, 패딩 방식 등을 사용하여 암호 연산을 안전하게 수행하기 위한 보안 요구사항을 정의합니다.

보안 대책

  • - 검증된 표준 암호 알고리즘 사용:
    • 대칭키 암호화: AES (128비트 이상, 권장 256비트) 등 검증된 최신 알고리즘을 사용합니다. (DES, 3DES, SEED 등 사용 지양)
    • 비대칭키 암호화: RSA (2048비트 이상, 권장 3072비트 이상), ECC (256비트 이상) 등 충분한 키 길이를 가진 알고리즘을 사용합니다.
    • 해시 함수: SHA-2 계열(SHA-256 이상) 또는 SHA-3 등 충돌 저항성이 충분히 검증된 알고리즘을 사용합니다. (MD5, SHA-1 사용 금지)
  • - 안전한 운영 모드(Mode of Operation) 사용: 블록 암호 알고리즘(AES 등) 사용 시, ECB(Electronic Codebook) 모드는 동일 평문 블록이 동일 암호문 블록으로 암호화되어 패턴 분석에 취약하므로 절대 사용해서는 안 됩니다. CBC, CFB, OFB, CTR 모드는 안전하게 사용될 수 있으나, 무결성 보장을 위해서는 GCM, CCM과 같은 인증 암호화(AEAD: Authenticated Encryption with Associated Data) 모드를 사용하는 것이 가장 권장됩니다.
  • - 초기화 벡터(IV) / Nonce의 안전한 관리: CBC, GCM 등 대부분의 안전한 운영 모드는 예측 불가능하고 재사용되지 않는 초기화 벡터(IV) 또는 Nonce를 요구합니다. 암호학적으로 안전한 난수 생성기(CSPRNG)를 사용하여 IV/Nonce를 생성하고, 암호문과 함께 안전하게 전송/저장해야 합니다. (IV/Nonce 자체는 비밀일 필요는 없으나, 예측 가능하거나 재사용되면 안 됨)
  • - 안전한 패딩(Padding) 방식 사용: 블록 암호화 시 평문 길이가 블록 크기의 배수가 아닐 때 패딩이 필요합니다. PKCS#7(PKCS#5) 등의 표준 패딩 방식을 사용하고, 복호화 시 패딩 오류를 이용한 공격(Padding Oracle Attack)에 대비합니다. (AEAD 모드는 패딩이 필요 없거나 내장된 경우가 많음)
  • - 검증된 암호 라이브러리 사용: 직접 암호 로직을 구현하는 것은 매우 위험하므로, 널리 사용되고 검증된 표준 암호 라이브러리(예: Java Cryptography Architecture - JCA/JCE, Python pycryptodome, OpenSSL 등)를 사용합니다.

코드 예시 (Java - AES 암호화)

취약한 코드 (ECB 모드 사용, IV 없음):

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

// ... 키 로드 로직 (하드코딩 금지) ...
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

// ECB 모드는 동일 평문에 대해 동일 암호문을 생성하여 매우 취약!
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding"); 
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF-8"));
// ... Base64 인코딩 등 ...
                        
안전한 코드 (GCM 모드 사용, 안전한 Nonce 생성):

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;
import java.util.Base64;

// ... 키 로드 로직 ...
SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");

// 1. 안전한 Nonce(IV) 생성 (매 암호화 시 새로 생성해야 함)
byte[] nonce = new byte[12]; // GCM 권장 Nonce 크기: 12 bytes
SecureRandom random = SecureRandom.getInstanceStrong(); // CSPRNG 사용
random.nextBytes(nonce);

// 2. GCM 모드 사용 (인증 암호화)
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding"); 
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, nonce); // 128 비트 인증 태그 크기
cipher.init(Cipher.ENCRYPT_MODE, secretKey, parameterSpec);

// 추가 인증 데이터(AAD) 설정 (선택 사항)
// byte[] aad = "Additional Authenticated Data".getBytes("UTF-8");
// cipher.updateAAD(aad);

byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF-8"));

// Nonce와 암호문을 함께 저장/전송해야 복호화 가능
// 예: byte[] encryptedPayload = new byte[nonce.length + cipherText.length];
// System.arraycopy(nonce, 0, encryptedPayload, 0, nonce.length);
// System.arraycopy(cipherText, 0, encryptedPayload, nonce.length, cipherText.length);
// String encoded = Base64.getEncoder().encodeToString(encryptedPayload);

// 복호화 시에는 저장된 Nonce를 사용하여 GCMParameterSpec을 만들고 Cipher를 초기화
                        

Python(pycryptodome), C#(System.Security.Cryptography), JavaScript(Web Crypto API, Node.js crypto 모듈), C/C++(OpenSSL) 등에서도 GCM, CCM과 같은 AEAD 모드 사용을 권장하며, 각 라이브러리의 IV/Nonce 생성 및 관리 방법을 정확히 따라야 합니다.