← 블로그 목록

암호화 완벽 가이드: 대칭키, 비대칭키, 해싱

암호화의 기초부터 AES, RSA, SHA까지. 데이터 보안을 완벽히 이해하세요.

암호화, 데이터 보안의 핵심

암호화

이 가이드에서는 암호화의 종류, 원리, 실제 구현을 배웁니다.

1부: 암호화의 종류

1. 대칭키 암호화 (Symmetric Encryption)

원문(Plaintext) + 키(Key) → 암호화 → 암호문(Ciphertext)
암호문 + 같은 키 → 복호화 → 원문

같은 키로 암호화와 복호화를 함

특징

  • 장점: 빠름, 효율적
  • 단점: 키 공유 문제 (둘 다 같은 키를 가져야 함)
  • 사용: 대용량 데이터, 파일 암호화

예시: AES (Advanced Encryption Standard)

const crypto = require('crypto');

// 암호화
const key = crypto.randomBytes(32); // 256비트 키
const iv = crypto.randomBytes(16);  // Initialization Vector
const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);

let encrypted = cipher.update('Hello World', 'utf8', 'hex');
encrypted += cipher.final('hex');

// 복호화
const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');

2. 비대칭키 암호화 (Asymmetric Encryption)

공개키(Public Key) + 개인키(Private Key) 쌍

공개키로 암호화 → 개인키로만 복호화 가능
개인키로 서명 → 공개키로 검증 가능

특징

  • 장점: 키 공유 문제 없음, 안전한 통신
  • 단점: 느림, 복잡함
  • 사용: HTTPS, 디지털 서명, 인증

예시: RSA

// 키 생성
const crypto = require('crypto');
const { publicKey, privateKey } = crypto.generateKeyPairSync('rsa', {
  modulusLength: 2048,
  publicKeyEncoding: { type: 'spki', format: 'pem' },
  privateKeyEncoding: { type: 'pkcs8', format: 'pem' }
});

// 공개키로 암호화
const encrypted = crypto.publicEncrypt(publicKey, Buffer.from('Hello'));

// 개인키로 복호화
const decrypted = crypto.privateDecrypt(privateKey, encrypted);

3. 해싱 (Hashing)

데이터 → 해시 함수 → 고정 길이 해시값

원본: "password123"
MD5: 0192023a7bbd73250516f069df18b500
SHA-256: ef92b778bafe771e89245d171bafecca6f1034f91b4542326d8060..."

특징

  • 한 방향: 해시값에서 원본 복원 불가
  • 고유성: 다른 입력 → 다른 해시
  • 사용: 패스워드 저장, 무결성 검사

⚠️ 주의: 암호화 아님!

해싱은 암호화가 아닙니다. 복호화 불가능합니다.

2부: 주요 암호화 알고리즘

AES (Advanced Encryption Standard)

키 길이: 128, 192, 256비트
속도: 빠름
보안: 강함
사용: 파일 암호화, 데이터베이스 암호화

AES-256이 가장 안전함

RSA

키 길이: 1024~4096비트
속도: 느림 (AES의 1000배)
보안: 강함
사용: HTTPS, 이메일 암호화, 디지털 서명

2048비트 이상 권장

해싱 알고리즘

MD5 (128비트)
❌ 약함, 충돌 가능 - 사용 금지

SHA-1 (160비트)
❌ 약함, 충돌 가능 - 사용 금지

SHA-256 (256비트)
✅ 강함, 표준

SHA-512 (512비트)
✅ 매우 강함

bcrypt
✅ 가장 권장 (패스워드 저장용)

3부: 암호화 흐름

HTTPS 통신

1. 클라이언트 → 서버: TLS 핸드셰이크 시작
2. 서버 → 클라이언트: 인증서(공개키 포함)
3. 클라이언트: 세션 키 생성
4. 클라이언트: 세션 키를 서버의 공개키로 암호화해서 전송
5. 서버: 개인키로 복호화 (세션 키 획득)
6. 이후: 대칭키(세션 키)로 빠르게 암호화/복호화

→ 비대칭키의 안전성 + 대칭키의 속도

패스워드 저장

❌ 나쁜 방법:
데이터베이스: password = "password123"

❌ 더 나쁜 방법:
해시 저장: password_hash = sha256("password123")
→ 레인보우 테이블 공격 가능

✅ 좋은 방법:
bcrypt 사용:
password_hash = bcrypt.hash("password123", saltRounds=10)
→ 느린 해싱, 솔트 자동 포함

4부: 실제 구현

파일 암호화 (Node.js)

const fs = require('fs');
const crypto = require('crypto');

function encryptFile(filename, key) {
  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);

  const input = fs.createReadStream(filename);
  const output = fs.createWriteStream(filename + '.encrypted');

  // IV를 파일 앞에 저장
  output.write(iv);

  input.pipe(cipher).pipe(output);
}

function decryptFile(filename, key) {
  const input = fs.createReadStream(filename);
  const output = fs.createWriteStream(filename.replace('.encrypted', ''));

  // IV 읽기
  input.read(16); // IV 크기 = 16바이트

  const decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
  input.pipe(decipher).pipe(output);
}

패스워드 해싱 (Node.js)

const bcrypt = require('bcrypt');

// 패스워드 해싱
async function hashPassword(password) {
  const saltRounds = 10;
  return await bcrypt.hash(password, saltRounds);
}

// 패스워드 검증
async function verifyPassword(password, hash) {
  return await bcrypt.compare(password, hash);
}

// 사용 예시
const hashedPassword = await hashPassword('mypassword');
const isCorrect = await verifyPassword('mypassword', hashedPassword);

5부: 암호화 보안 모범 사례

1. 강한 키 생성

❌ 약한 키
const key = "password";

✅ 강한 키
const key = crypto.randomBytes(32); // 256비트

2. 키 관리

❌ 소스 코드에 키 저장
const key = "my-secret-key";

✅ 환경 변수 사용
const key = Buffer.from(process.env.ENCRYPTION_KEY, 'hex');

3. 솔트(Salt) 사용

❌ 솔트 없음
hash = sha256("password")

✅ 솔트 포함
salt = randomBytes(16)
hash = sha256(password + salt)

4. IV(Initialization Vector) 사용

❌ 같은 IV 반복 사용
IV = "static value"

✅ 매번 새로운 IV
IV = randomBytes(16)

자주 하는 실수

1. MD5/SHA-1 사용

❌ MD5 또는 SHA-1로 해싱

✅ SHA-256 또는 bcrypt 사용

2. 암호화와 해싱 혼동

❌ 패스워드를 AES로 암호화 저장

✅ bcrypt로 해싱 저장

3. 키를 소스 코드에 저장

❌ const SECRET_KEY = "mysecret";

✅ 환경 변수 또는 보안 저장소 사용

4. 약한 알고리즘 사용

❌ MD5, DES, RC4

✅ AES-256, SHA-256, bcrypt

마무리

암호화는 데이터 보안의 기초입니다. 올바른 알고리즘 선택과 키 관리를 통해 안전한 시스템을 구축하세요.