Alert

์ด ๊ธ€์€ Claude Code์˜ ๋„์›€์„ ๋ฐ›์•„ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค

TL;DR

  • AES-GCM์€ Fernet๋ณด๋‹ค ์œ ์—ฐํ•œ ๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™” ๋ฐฉ์‹
  • RSA๋Š” ๊ณต๊ฐœ ํ‚ค/๊ฐœ์ธ ํ‚ค ์Œ์„ ์‚ฌ์šฉํ•˜๋Š” ๋น„๋Œ€์นญ ์•”ํ˜ธํ™”
  • ํ•ด์‹ฑ์€ ๋‹จ๋ฐฉํ–ฅ ๋ณ€ํ™˜์œผ๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅ ๋“ฑ์— ์‚ฌ์šฉ
  • ์ƒํ™ฉ๋ณ„๋กœ ์ ์ ˆํ•œ ์•”ํ˜ธํ™” ๋ฐฉ์‹์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”

์ด์ „ ๊ธ€

Python cryptography 1 - Fernet์—์„œ Fernet ๊ธฐ๋ฐ˜ ๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™”๋ฅผ ๋‹ค๋ค˜๋‹ค. ์ด ๊ธ€์—์„œ๋Š” Fernet์œผ๋กœ ํ•ด๊ฒฐํ•˜๊ธฐ ์–ด๋ ค์šด ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ €์ˆ˜์ค€ API๋ฅผ ๋‹ค๋ฃฌ๋‹ค.


1. AES ์ง์ ‘ ์‚ฌ์šฉํ•˜๊ธฐ

Fernet์€ ๋‚ด๋ถ€์ ์œผ๋กœ AES-128-CBC๋ฅผ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ํ‚ค ๊ธธ์ด๋‚˜ ๋ชจ๋“œ๋ฅผ ๋ฐ”๊ฟ€ ์ˆ˜ ์—†๋‹ค. cryptography์˜ hazmat ๋ ˆ์ด์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด AES๋ฅผ ์ง์ ‘ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค.

AES-GCM์ด๋ž€

AES-GCM(Galois/Counter Mode)์€ ํ˜„์žฌ ๊ฐ€์žฅ ๋„๋ฆฌ ๊ถŒ์žฅ๋˜๋Š” ๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™” ๋ชจ๋“œ๋‹ค.

  • ์•”ํ˜ธํ™” + ์ธ์ฆ์„ ํ•œ๋ฒˆ์— ์ฒ˜๋ฆฌํ•œ๋‹ค (Authenticated Encryption)
  • ๋ณ„๋„์˜ HMAC ๊ณ„์‚ฐ์ด ํ•„์š” ์—†๋‹ค
  • AES-256 ๋“ฑ ๋” ๊ธด ํ‚ค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค
  • ์ŠคํŠธ๋ฆฌ๋ฐ/์ฒญํฌ ๋‹จ์œ„ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค
๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•
import os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
 
# 1. ํ‚ค ์ƒ์„ฑ (256๋น„ํŠธ = 32๋ฐ”์ดํŠธ)
key = AESGCM.generate_key(bit_length=256)
 
# 2. nonce ์ƒ์„ฑ (12๋ฐ”์ดํŠธ ๊ถŒ์žฅ)
nonce = os.urandom(12)
 
# 3. ์•”ํ˜ธํ™”
aesgcm = AESGCM(key)
ciphertext = aesgcm.encrypt(nonce, b"secret data", None)
 
# 4. ๋ณตํ˜ธํ™”
plaintext = aesgcm.decrypt(nonce, ciphertext, None)
print(plaintext)  # b'secret data'

nonce๋Š” ์ ˆ๋Œ€ ์žฌ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋œ๋‹ค

๊ฐ™์€ ํ‚ค๋กœ ๊ฐ™์€ nonce๋ฅผ ๋‘ ๋ฒˆ ์‚ฌ์šฉํ•˜๋ฉด ์•”ํ˜ธํ™”๊ฐ€ ๊นจ์ง„๋‹ค. ๋งค ์•”ํ˜ธํ™”๋งˆ๋‹ค os.urandom(12)๋กœ ์ƒˆ๋กœ ์ƒ์„ฑํ•˜๊ณ , ciphertext์™€ ํ•จ๊ป˜ ์ €์žฅํ•ด์•ผ ํ•œ๋‹ค.

AAD (Associated Authenticated Data)

encrypt์˜ ์„ธ ๋ฒˆ์งธ ์ธ์ž๋Š” AAD๋‹ค. ์•”ํ˜ธํ™”ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ๋ฌด๊ฒฐ์„ฑ์„ ๊ฒ€์ฆํ•˜๊ณ  ์‹ถ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ๋Š”๋‹ค.

# ํ—ค๋” ์ •๋ณด๋Š” ์•”ํ˜ธํ™”ํ•˜์ง€ ์•Š๋˜, ๋ณ€์กฐ ์—ฌ๋ถ€๋Š” ๊ฒ€์ฆ
aad = b"user_id=42"
ciphertext = aesgcm.encrypt(nonce, b"secret data", aad)
 
# ๋ณตํ˜ธํ™” ์‹œ ๊ฐ™์€ AAD๋ฅผ ๋„˜๊ฒจ์•ผ ์„ฑ๊ณต
plaintext = aesgcm.decrypt(nonce, ciphertext, aad)
 
# AAD๊ฐ€ ๋‹ค๋ฅด๋ฉด InvalidTag ์˜ˆ์™ธ
aesgcm.decrypt(nonce, ciphertext, b"user_id=99")
# cryptography.exceptions.InvalidTag
Fernet vs AES-GCM ๋น„๊ต
ํ•ญ๋ชฉFernetAES-GCM
๋‚œ์ด๋„์‰ฌ์›€์ค‘๊ฐ„
ํ‚ค ๊ธธ์ด128๋น„ํŠธ ๊ณ ์ •128/192/256๋น„ํŠธ ์„ ํƒ
๋ชจ๋“œCBC + HMACGCM (์ธ์ฆ ๋‚ด์žฅ)
nonce/IV ๊ด€๋ฆฌ์ž๋™์ง์ ‘ ๊ด€๋ฆฌ
๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ๋ถ€์ ํ•ฉ์ ํ•ฉ
์šฉ๋„๊ฐ„๋‹จํ•œ ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™”์„ธ๋ฐ€ํ•œ ์ œ์–ด๊ฐ€ ํ•„์š”ํ•  ๋•Œ

2. ๋น„๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™” (RSA)

๋Œ€์นญ ํ‚ค๊ฐ€ ๊ฐ™์€ ์—ด์‡ ๋กœ ์ž ๊ทธ๊ณ  ์—ฌ๋Š” ๊ธˆ๊ณ ์˜€๋‹ค๋ฉด, RSA๋Š” ์šฐ์ฒดํ†ต๊ณผ ๊ฐ™๋‹ค. ๋ˆ„๊ตฌ๋‚˜ ์šฐํŽธ๋ฌผ์„ ๋„ฃ์„ ์ˆ˜ ์žˆ์ง€๋งŒ(๊ณต๊ฐœ ํ‚ค๋กœ ์•”ํ˜ธํ™”), ์—ด์–ด์„œ ๊บผ๋‚ด๋Š” ๊ฒƒ์€ ์—ด์‡ ๋ฅผ ๊ฐ€์ง„ ์ฃผ์ธ๋งŒ ๊ฐ€๋Šฅํ•˜๋‹ค(๊ฐœ์ธ ํ‚ค๋กœ ๋ณตํ˜ธํ™”).

  • ๊ณต๊ฐœ ํ‚ค : ๋ˆ„๊ตฌ์—๊ฒŒ๋‚˜ ๊ณต๊ฐœ. ์•”ํ˜ธํ™”์— ์‚ฌ์šฉ
  • ๊ฐœ์ธ ํ‚ค : ๋ณธ์ธ๋งŒ ๋ณด์œ . ๋ณตํ˜ธํ™”์— ์‚ฌ์šฉ
ํ‚ค ์Œ ์ƒ์„ฑ
from cryptography.hazmat.primitives.asymmetric import rsa, padding
from cryptography.hazmat.primitives import hashes, serialization
 
# ๊ฐœ์ธ ํ‚ค ์ƒ์„ฑ
private_key = rsa.generate_private_key(
    public_exponent=65537,
    key_size=2048,
)
 
# ๊ณต๊ฐœ ํ‚ค ์ถ”์ถœ
public_key = private_key.public_key()
ํ‚ค๋ฅผ ํŒŒ์ผ๋กœ ์ €์žฅ/๋ถˆ๋Ÿฌ์˜ค๊ธฐ
# ๊ฐœ์ธ ํ‚ค ์ €์žฅ (PEM ํ˜•์‹)
pem_private = private_key.private_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PrivateFormat.PKCS8,
    encryption_algorithm=serialization.BestAvailableEncryption(b"passphrase"),
)
Path("private.pem").write_bytes(pem_private)
 
# ๊ณต๊ฐœ ํ‚ค ์ €์žฅ
pem_public = public_key.public_bytes(
    encoding=serialization.Encoding.PEM,
    format=serialization.PublicFormat.SubjectPublicKeyInfo,
)
Path("public.pem").write_bytes(pem_public)
 
# ๊ฐœ์ธ ํ‚ค ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
loaded_private = serialization.load_pem_private_key(
    Path("private.pem").read_bytes(),
    password=b"passphrase",
)
 
# ๊ณต๊ฐœ ํ‚ค ๋ถˆ๋Ÿฌ์˜ค๊ธฐ
loaded_public = serialization.load_pem_public_key(
    Path("public.pem").read_bytes(),
)
์•”ํ˜ธํ™” / ๋ณตํ˜ธํ™”
# ๊ณต๊ฐœ ํ‚ค๋กœ ์•”ํ˜ธํ™”
ciphertext = public_key.encrypt(
    b"secret message",
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None,
    ),
)
 
# ๊ฐœ์ธ ํ‚ค๋กœ ๋ณตํ˜ธํ™”
plaintext = private_key.decrypt(
    ciphertext,
    padding.OAEP(
        mgf=padding.MGF1(algorithm=hashes.SHA256()),
        algorithm=hashes.SHA256(),
        label=None,
    ),
)
print(plaintext)  # b'secret message'

RSA๋Š” ์ž‘์€ ๋ฐ์ดํ„ฐ๋งŒ ์•”ํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ๋‹ค

RSA-2048 ๊ธฐ์ค€ ์ตœ๋Œ€ ์•ฝ 190๋ฐ”์ดํŠธ๊นŒ์ง€๋งŒ ์•”ํ˜ธํ™” ๊ฐ€๋Šฅํ•˜๋‹ค. ํฐ ๋ฐ์ดํ„ฐ๋Š” AES๋กœ ์•”ํ˜ธํ™”ํ•˜๊ณ , AES ํ‚ค๋งŒ RSA๋กœ ์•”ํ˜ธํ™”ํ•˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•œ๋‹ค.

๋””์ง€ํ„ธ ์„œ๋ช… / ๊ฒ€์ฆ

์•”ํ˜ธํ™”์™€ ๋ฐ˜๋Œ€ ๋ฐฉํ–ฅ์ด๋‹ค. ๊ฐœ์ธ ํ‚ค๋กœ ์„œ๋ช…ํ•˜๊ณ  ๊ณต๊ฐœ ํ‚ค๋กœ ๊ฒ€์ฆํ•œ๋‹ค. ๋ฐ์ดํ„ฐ๊ฐ€ ๋ณ€์กฐ๋˜์ง€ ์•Š์•˜์Œ์„ ์ฆ๋ช…ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค. ์‹ค์ œ๋กœ TLS handshake์—์„œ ์„œ๋ฒ„ ์ธ์ฆ์— ์ด ๋ฐฉ์‹์ด ์“ฐ์ธ๋‹ค.

from cryptography.hazmat.primitives.asymmetric import utils
 
message = b"this data must not be tampered"
 
# ๊ฐœ์ธ ํ‚ค๋กœ ์„œ๋ช…
signature = private_key.sign(
    message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH,
    ),
    hashes.SHA256(),
)
 
# ๊ณต๊ฐœ ํ‚ค๋กœ ๊ฒ€์ฆ (๋ณ€์กฐ๋˜์ง€ ์•Š์•˜์œผ๋ฉด ์ •์ƒ ํ†ต๊ณผ)
public_key.verify(
    signature,
    message,
    padding.PSS(
        mgf=padding.MGF1(hashes.SHA256()),
        salt_length=padding.PSS.MAX_LENGTH,
    ),
    hashes.SHA256(),
)
# ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด ๊ฒ€์ฆ ์„ฑ๊ณต
 
# ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณ€์กฐ๋œ ๊ฒฝ์šฐ
public_key.verify(signature, b"tampered data", ...)
# cryptography.exceptions.InvalidSignature

3. ํ•ด์‹ฑ

ํ•ด์‹ฑ์€ ์•”ํ˜ธํ™”์™€ ๋‹ค๋ฅด๋‹ค. ๋‹จ๋ฐฉํ–ฅ ๋ณ€ํ™˜์ด๊ธฐ ๋•Œ๋ฌธ์— ํ•ด์‹œ ๊ฐ’์—์„œ ์›๋ณธ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณต์›ํ•  ์ˆ˜ ์—†๋‹ค.

๊ตฌ๋ถ„์•”ํ˜ธํ™”ํ•ด์‹ฑ
๋ฐฉํ–ฅ์–‘๋ฐฉํ–ฅ (์•”ํ˜ธํ™” โ†” ๋ณตํ˜ธํ™”)๋‹จ๋ฐฉํ–ฅ (์›๋ณธ โ†’ ํ•ด์‹œ)
ํ‚คํ•„์š”๋ถˆํ•„์š”
์šฉ๋„๋ฐ์ดํ„ฐ ๋ณดํ˜ธ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ, ๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅ
๋ฐ์ดํ„ฐ ํ•ด์‹ฑ (SHA-256)

ํŒŒ์ผ์ด๋‚˜ ๋ฉ”์‹œ์ง€์˜ ๋ฌด๊ฒฐ์„ฑ์„ ๊ฒ€์ฆํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.

from cryptography.hazmat.primitives import hashes
 
digest = hashes.Hash(hashes.SHA256())
digest.update(b"hello ")
digest.update(b"world")
result = digest.finalize()
 
print(result.hex())
# ์ •ํ•ด์ง„ ๊ธธ์ด์˜ ํ•ด์‹œ ๊ฐ’ ์ถœ๋ ฅ (64์ž hex)
๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹ฑ๊ณผ ๋ฐ์ดํ„ฐ ํ•ด์‹ฑ์€ ๋‹ค๋ฅด๋‹ค

SHA-256์œผ๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ €์žฅํ•˜๋ฉด ์•ˆ ๋œ๋‹ค

SHA-256์€ ์†๋„๊ฐ€ ๋น ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋ฌด์ฐจ๋ณ„ ๋Œ€์ž… ๊ณต๊ฒฉ(brute-force)์— ์ทจ์•ฝํ•˜๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹ฑ์—๋Š” ์˜๋„์ ์œผ๋กœ ๋А๋ฆฐ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹ฑ์—๋Š” bcrypt๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

pip install bcrypt
import bcrypt
 
password = b"my_secure_password"
 
# ํ•ด์‹ฑ (salt ์ž๋™ ์ƒ์„ฑ)
hashed = bcrypt.hashpw(password, bcrypt.gensalt())
print(hashed)
# b'$2b$12$...'
 
# ๊ฒ€์ฆ
if bcrypt.checkpw(password, hashed):
    print("๋น„๋ฐ€๋ฒˆํ˜ธ ์ผ์น˜")
else:
    print("๋น„๋ฐ€๋ฒˆํ˜ธ ๋ถˆ์ผ์น˜")
์•Œ๊ณ ๋ฆฌ์ฆ˜์šฉ๋„์†๋„
SHA-256ํŒŒ์ผ ๋ฌด๊ฒฐ์„ฑ, ๋ฐ์ดํ„ฐ ์ง€๋ฌธ๋น ๋ฆ„
bcrypt๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅ์˜๋„์ ์œผ๋กœ ๋А๋ฆผ
scrypt๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅ (๋ฉ”๋ชจ๋ฆฌ ์ง‘์•ฝ์ )๋А๋ฆผ
argon2๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅ (์ตœ์‹  ๊ถŒ์žฅ)๋А๋ฆผ

4. ์‹ค์ „ ์„ ํƒ ๊ฐ€์ด๋“œ

์ƒํ™ฉ์— ๋”ฐ๋ผ ์–ด๋–ค ์•”ํ˜ธํ™” ๋ฐฉ์‹์„ ์„ ํƒํ•ด์•ผ ํ•˜๋Š”์ง€ ์ •๋ฆฌํ•œ๋‹ค.

์ƒํ™ฉ์ถ”์ฒœ ๋ฐฉ์‹์ด์œ 
API ํ‚ค/ํ† ํฐ ์ €์žฅFernet๊ฐ„๋‹จํ•˜๊ณ  ์ถฉ๋ถ„ํžˆ ์•ˆ์ „
์„ค์ • ํŒŒ์ผ ์•”ํ˜ธํ™”Fernet๋‹จ์ผ ํ‚ค๋กœ ๊ฐ„ํŽธํ•˜๊ฒŒ ๊ด€๋ฆฌ
๋Œ€์šฉ๋Ÿ‰ ํŒŒ์ผ ์•”ํ˜ธํ™”AES-GCM์ŠคํŠธ๋ฆฌ๋ฐ ์ฒ˜๋ฆฌ, ์„ฑ๋Šฅ ์šฐ์ˆ˜
์„œ๋ฒ„ ๊ฐ„ ๋ฐ์ดํ„ฐ ์ „์†กAES-GCM + RSA (ํ•˜์ด๋ธŒ๋ฆฌ๋“œ)ํ‚ค ๊ตํ™˜ ๋ฌธ์ œ ํ•ด๊ฒฐ
๋น„๋ฐ€๋ฒˆํ˜ธ ์ €์žฅbcrypt / argon2๋ณตํ˜ธํ™”๊ฐ€ ํ•„์š” ์—†๊ณ  ๋А๋ ค์•ผ ์•ˆ์ „
ํŒŒ์ผ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆSHA-256๋น ๋ฅด๊ณ  ์ถฉ๋Œ ์ €ํ•ญ์„ฑ ๋†’์Œ
๋ฐ์ดํ„ฐ ์„œ๋ช…/์ธ์ฆRSA ์„œ๋ช…๋ณ€์กฐ ๋ฐฉ์ง€ + ๋ฐœ์‹ ์ž ์ฆ๋ช…

ํŒ๋‹จ ๊ธฐ์ค€

  • ๋ณตํ˜ธํ™”๊ฐ€ ํ•„์š”ํ•œ๊ฐ€? โ†’ ํ•„์š” ์—†์œผ๋ฉด ํ•ด์‹ฑ
  • ํ‚ค๋ฅผ ์ƒ๋Œ€๋ฐฉ์—๊ฒŒ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€? โ†’ ์ „๋‹ฌํ•ด์•ผ ํ•˜๋ฉด RSA ๋˜๋Š” ํ•˜์ด๋ธŒ๋ฆฌ๋“œ
  • ๋ฐ์ดํ„ฐ ํฌ๊ธฐ๊ฐ€ ํฐ๊ฐ€? โ†’ ํฌ๋ฉด AES-GCM
  • ๊ฐ„๋‹จํ•˜๊ฒŒ ๋๋‚ด๊ณ  ์‹ถ์€๊ฐ€? โ†’ Fernet

5. ํ”ํ•œ ์‹ค์ˆ˜์™€ ๋ณด์•ˆ ์ฃผ์˜์‚ฌํ•ญ

ํ‚ค๋ฅผ ์ฝ”๋“œ์— ํ•˜๋“œ์ฝ”๋”ฉ
# ์ ˆ๋Œ€ ํ•˜๋ฉด ์•ˆ ๋˜๋Š” ํŒจํ„ด
key = b"ZmDfcTF7_60GrrY4vBGJSVgmYR0yGH8rrOamiLkI6mA="

ํ‚ค๊ฐ€ git ํžˆ์Šคํ† ๋ฆฌ์— ๋‚จ์œผ๋ฉด ์‚ญ์ œํ•ด๋„ ์ด๋ฏธ ์œ ์ถœ๋œ ๊ฒƒ์ด๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜๋‚˜ ์‹œํฌ๋ฆฟ ๋งค๋‹ˆ์ €๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

ECB ๋ชจ๋“œ ์‚ฌ์šฉ

ECB(Electronic Codebook)๋Š” ๊ฐ™์€ ํ‰๋ฌธ ๋ธ”๋ก์ด ํ•ญ์ƒ ๊ฐ™์€ ์•”ํ˜ธ๋ฌธ์„ ์ƒ์„ฑํ•œ๋‹ค. ํŒจํ„ด์ด ๊ทธ๋Œ€๋กœ ๋“œ๋Ÿฌ๋‚˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. GCM์ด๋‚˜ CBC๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

nonce/IV ์žฌ์‚ฌ์šฉ

AES-GCM์—์„œ ๊ฐ™์€ ํ‚ค๋กœ ๊ฐ™์€ nonce๋ฅผ ๋‘ ๋ฒˆ ์‚ฌ์šฉํ•˜๋ฉด ์•”ํ˜ธํ™”๊ฐ€ ์™„์ „ํžˆ ๊นจ์ง„๋‹ค. ๋งค๋ฒˆ os.urandom()์œผ๋กœ ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.

์ž์ฒด ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ๊ตฌํ˜„

๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค. ์ง์ ‘ ๋งŒ๋“  ์•”ํ˜ธํ™”๋Š” ๊ฑฐ์˜ ํ™•์‹คํ•˜๊ฒŒ ์ทจ์•ฝ์ ์ด ์žˆ๋‹ค.

SHA-256์œผ๋กœ ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹ฑ

์œ„์—์„œ ๋‹ค๋ค˜๋“ฏ์ด SHA-256์€ ๋น ๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋น„๋ฐ€๋ฒˆํ˜ธ ํ•ด์‹ฑ์— ๋ถ€์ ํ•ฉํ•˜๋‹ค. bcrypt, scrypt, argon2๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

ํ•ต์‹ฌ ์›์น™

  • ์ง์ ‘ ๋งŒ๋“ค์ง€ ๋ง๊ณ  ๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค
  • ํ‚ค๋Š” ์ฝ”๋“œ์™€ ๋ถ„๋ฆฌํ•œ๋‹ค
  • nonce/IV๋Š” ๋งค๋ฒˆ ์ƒˆ๋กœ ์ƒ์„ฑํ•œ๋‹ค
  • ๋น„๋ฐ€๋ฒˆํ˜ธ๋Š” ํ•ด์‹ฑ, ๋ฐ์ดํ„ฐ๋Š” ์•”ํ˜ธํ™”๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค