암호화

누피밥·2025년 2월 8일
0

보안

목록 보기
2/2

암호화란?

데이터(문자, 파일 등)를 특정한 알고리즘을 사용하여 변환하여 데이터 보호하는 위한 보안 기술입니다.

암호화 종류

암호화는 크게 대칭키(Symmetric Key) 암호화와 비대칭키(Asymmetric Key) 암호화 두 가지가 있습니다.

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

하나의 키(Key)로 암호화와 복호화를 모두 수행하는 방식입니다.

  • 🔑 동일한 키를 사용하여 데이터를 암호화하고 복호화함
  • ⚡ 속도가 빠름 (대량의 데이터 암호화에 적합)
  • ❌ 키를 안전하게 공유하는 것이 어려움 → 네트워크를 통해 키를 주고받을 경우 보안 취약

동작 방식

1️⃣ A(보내는 사람)가 **비밀 키(Secret Key)** 를 사용해 데이터를 암호화.
2️⃣ B(받는 사람)는 **같은 비밀 키**를 사용해 데이터를 복호화.
3️⃣ **문제점**: 키가 노출되면 누구나 데이터를 복호화할 수 있음.

대칭키 암호화 알고리즘 종류

알고리즘키 길이설명
**AES**128/192/256비트가장 많이 사용되는 강력한 암호화 알고리즘
**DES**56비트더 이상 안전하지 않음 (취약)
**3DES**168비트DES보다 보안이 강하지만 속도가 느림
**RC4**가변 길이빠르지만 보안 문제로 사용 지양

대칭키 암호화 예제 (AES)

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

public class AESExample {
    private static final String SECRET_KEY = "12345678901234567890123456789012"; // 32바이트 키

    public static String encrypt(String data) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, secretKey);
        byte[] encrypted = cipher.doFinal(data.getBytes());
        return Base64.getEncoder().encodeToString(encrypted);
    }

    public static String decrypt(String encryptedData) throws Exception {
        SecretKeySpec secretKey = new SecretKeySpec(SECRET_KEY.getBytes(), "AES");
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, secretKey);
        byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(encryptedData));
        return new String(decrypted);
    }
}

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

공개키(Public Key)와 비공개키(Private Key) 두 개의 키를 사용하는 방식입니다.

  • 🔑 두 개의 키를 사용 → 공개키(Public Key)로 암호화, 비공개키(Private Key)로 복호화.
  • 🔐 보안성이 높음 (대칭키보다 안전함).
  • ⚡ 속도가 느림 (큰 데이터를 암호화하기에는 부적합).

동작 방식

1️⃣ **공개키(Public Key)는 누구나 가질 수 있음**.
2️⃣ **비공개키(Private Key)는 소유자만 알고 있어야 함**.
3️⃣ A(보내는 사람)가 **B의 공개키로 데이터를 암호화**.
4️⃣ B(받는 사람)는 **자신의 비공개키로 복호화**.
5️⃣ **공개키로는 복호화할 수 없고, 반드시 비공개키가 필요**.

비대칭키 암호화 알고리즘 예시

알고리즘키 길이설명
**RSA**1024/2048/4096비트가장 많이 사용되는 공개키 암호화
**ECC**256/384비트RSA보다 짧은 키 길이로 높은 보안 제공
**Diffie-Hellman**1024/2048비트키 교환 프로토콜

비대칭키 암호화 예제 (RSA)

import java.security.*;
import javax.crypto.Cipher;
import java.util.Base64;

public class RSAExample {
    private static KeyPair generateKeyPair() throws Exception {
        KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
        keyGen.initialize(2048);
        return keyGen.generateKeyPair();
    }

    public static String encrypt(String data, PublicKey publicKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        return Base64.getEncoder().encodeToString(cipher.doFinal(data.getBytes()));
    }

    public static String decrypt(String encryptedData, PrivateKey privateKey) throws Exception {
        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedData)));
    }

    public static void main(String[] args) throws Exception {
        KeyPair keyPair = generateKeyPair();
        String encrypted = encrypt("Hello, World!", keyPair.getPublic());
        String decrypted = decrypt(encrypted, keyPair.getPrivate());

        System.out.println("🔐 암호화된 데이터: " + encrypted);
        System.out.println("🔑 복호화된 데이터: " + decrypted);
    }
}

3. 하이브리드 암호화(대칭키 + 비대칭키 조합)

대칭키(AES)로 데이터를 암호화하고, 대칭키는 비대칭키(RSA)로 암호화하는 방식입니다.
이 방식이 HTTPS(SSL/TLS)에서도 사용됩니다.

대칭키의 속도와 비대칭키의 보안성을 모두 확보할 수 있는 방법입니다.

동작 방식

1️⃣ 서버는 **AES-256 대칭키를 생성**.
2️⃣ 서버는 **클라이언트의 공개키로 AES 키를 암호화**.
3️⃣ 클라이언트는 **RSA 비공개키로 AES 키를 복호화**.
4️⃣ 이후 데이터는 **AES-256을 사용하여 빠르게 암호화/복호화**.

하이브리드 암호화 방식 사용 예시

1. 클라이언트 - 공개키, 비공개키 생성

클라이언트는 Web Crypto API를 사용하여 공개키, 비공개키를 생성합니다. 비공개키는 브라우저 내부 Web Crypto API에서만 접근 가능하며, 직접 유출될 위험이 줄어듭니다.

async function generateRSAKeyPair() {
    const keyPair = await window.crypto.subtle.generateKey(
        {
            name: "RSA-OAEP",
            modulusLength: 2048,
            publicExponent: new Uint8Array([1, 0, 1]),
            hash: "SHA-256",
        },
        true,  // 내보내기(export) 가능 여부
        ["encrypt", "decrypt"]  // 공개키(암호화), 비공개키(복호화) 사용
    );

    return keyPair;
}
2. 클라이언트 - 공개키 서버로 전송

브라우저에서 생성된 공개키(Public Key)는 서버에 보내서 데이터 암・복호화에 사용될 비밀키를 암호화하는데 사용합니다.

async function sendPublicKeyToServer(publicKey) {
    const exportedKey = await window.crypto.subtle.exportKey("spki", publicKey);
    const publicKeyBase64 = btoa(String.fromCharCode(...new Uint8Array(exportedKey)));

    await fetch("/api/storePublicKey", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ publicKey: publicKeyBase64 }),
    });
}
3. 서버 - 클라이언트의 공개키를 사용하여 데이터 암・복호화에 필요한 비밀키 암호화

데이터 암・복호화에 필요한 비밀키를 안전하게 전송하기 위해 클라이언트에서 받은 공개키로 비밀키를 암호화 합니다.

import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.Cipher;
import java.util.Base64;

public class RSAEncryptor {
    //data가 AES 암호화에 사용되는 비밀키가 됨
    public static String encryptData(String data, String publicKeyBase64) throws Exception {
        byte[] decodedKey = Base64.getDecoder().decode(publicKeyBase64);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));

        Cipher cipher = Cipher.getInstance("RSA");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptedBytes = cipher.doFinal(data.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }
}
4. 클라이언트 - 암호화된 비밀키 복호화

서버에서 전달받은 암호화된 비밀키를 비공개키로 복화하여 데이터를 암호화하여 서버로 전달합니다.

async function decryptData(encryptedData, privateKey) {
    const encryptedBytes = Uint8Array.from(atob(encryptedData), c => c.charCodeAt(0));

    const decryptedData = await window.crypto.subtle.decrypt(
        { name: "RSA-OAEP" },
        privateKey,
        encryptedBytes
    );

    return new TextDecoder().decode(decryptedData);
}

0개의 댓글