AES cryptosystem ์ ์šฉ

GEONNYยท2024๋…„ 9์›” 10์ผ
0

Building-API

๋ชฉ๋ก ๋ณด๊ธฐ
26/28
post-thumbnail

๐Ÿ“ŒAES

AES(Advanced Encryption Standard) ๋Š” ๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”ํ•˜๊ณ  ๋ณตํ˜ธํ™”ํ•  ๋•Œ ๋™์ผํ•œ ๋น„๋ฐ€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. AES๋Š” 1997๋…„ ๋ฏธ๊ตญ ๊ตญ๊ฐ€ํ‘œ์ค€๊ธฐ์ˆ ์—ฐ๊ตฌ์†Œ(NIST)์— ์˜ํ•ด ๋Œ€์ค‘์— ๊ณต๊ฐœ๋˜์—ˆ๊ณ , 2001๋…„์— DES(Data Encryption Standard)๋ฅผ ๋Œ€์ฒดํ•˜์—ฌ ํ‘œ์ค€ ๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ์ฑ„ํƒ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

AES๋Š” ๋ธ”๋ก ์•”ํ˜ธํ™” ๋ฐฉ์‹์„ ๋”ฐ๋ฅด๋ฉฐ, ๊ณ ์ •๋œ ํฌ๊ธฐ์˜ ๋ธ”๋ก(128๋น„ํŠธ)์„ ์•”ํ˜ธํ™”ํ•ฉ๋‹ˆ๋‹ค. ์ด๋•Œ, ์•”ํ˜ธํ™”์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ‚ค ๊ธธ์ด๋Š” 128๋น„ํŠธ, 192๋น„ํŠธ, 256๋น„ํŠธ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด, ๋ณด์•ˆ ์š”๊ตฌ์— ๋”ฐ๋ผ ์„ ํƒ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ AES๋Š” ์†๋„์™€ ๋ณด์•ˆ์„ฑ ๋ฉด์—์„œ ๋งค์šฐ ํšจ์œจ์ ์ด๋ฉฐ, ๊ธˆ์œต ์‹œ์Šคํ…œ, ์ „์ž ์ƒ๊ฑฐ๋ž˜, ๋ฌด์„  ๋„คํŠธ์›Œํฌ ๋“ฑ์—์„œ ๋„๋ฆฌ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ๋Œ€์นญ ์•”ํ˜ธํ™”

๋Œ€์นญ ์•”ํ˜ธํ™”๋Š” ์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™”์— ๋™์ผํ•œ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.

๐Ÿ“ŒAES์˜ ๊ธฐ๋ณธ ๊ฐœ๋…

ES๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”ํ•  ๋•Œ, ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋ฅผ 128๋น„ํŠธ ๋ธ”๋ก ๋‹จ์œ„๋กœ ๋‚˜๋ˆ„์–ด ์•”ํ˜ธํ™”ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ธ”๋ก์€ ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ๋ผ์šด๋“œ(Round)๋ฅผ ๊ฑฐ์ณ ์•”ํ˜ธํ™”๋˜๋ฉฐ, ๋ผ์šด๋“œ์˜ ํšŸ์ˆ˜๋Š” ํ‚ค ๊ธธ์ด์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

AES-128: 10 ๋ผ์šด๋“œ
AES-192: 12 ๋ผ์šด๋“œ
AES-256: 14 ๋ผ์šด๋“œ

๊ฐ ๋ผ์šด๋“œ์—์„œ๋Š” ์น˜ํ™˜(Substitution), ์ „์น˜(Permutation), ํ‚ค ํ™•์žฅ(Key Expansion) ๋“ฑ์˜ ์—ฐ์‚ฐ์ด ์ด๋ฃจ์–ด์ ธ ๋ฐ์ดํ„ฐ๊ฐ€ ์ ์  ๋” ์•”ํ˜ธํ™”๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“Œ์•”ํ˜ธํ™” ๋ชจ๋“œ(Encryption Modes)

AES๋Š” ์•”ํ˜ธํ™” ๋ชจ๋“œ์— ๋”ฐ๋ผ ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ๋ฐฉ์‹์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์•”ํ˜ธํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋Œ€ํ‘œ์ ์ธ ๋ชจ๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค:

ECB (Electronic Codebook)
๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ์‹์œผ๋กœ, ๋™์ผํ•œ ํ‰๋ฌธ ๋ธ”๋ก์ด ํ•ญ์ƒ ๋™์ผํ•œ ์•”ํ˜ธ๋ฌธ ๋ธ”๋ก์œผ๋กœ ์•”ํ˜ธํ™”๋ฉ๋‹ˆ๋‹ค. ๋ณด์•ˆ์ด ์ทจ์•ฝํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ž˜ ์‚ฌ์šฉ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

CBC (Cipher Block Chaining)
๊ฐ ๋ธ”๋ก์„ ์•”ํ˜ธํ™”ํ•  ๋•Œ ์ด์ „ ๋ธ”๋ก์˜ ์•”ํ˜ธ๋ฌธ๊ณผ XOR ์—ฐ์‚ฐ์„ ํ•œ ํ›„ ์•”ํ˜ธํ™”ํ•˜๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ๋ณด์•ˆ์„ฑ์ด ๋›ฐ์–ด๋‚˜๋ฉฐ,
์ดˆ๊ธฐํ™” ๋ฒกํ„ฐ(IV)๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

GCM (Galois/Counter Mode)
๊ณ ์† ์•”ํ˜ธํ™”์™€ ๋ฌด๊ฒฐ์„ฑ ๊ฒ€์ฆ ๊ธฐ๋Šฅ์„ ๋™์‹œ์— ์ œ๊ณตํ•˜๋Š” ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค. ๋ณด์•ˆ์„ฑ๊ณผ ์„ฑ๋Šฅ์ด ๋ชจ๋‘ ๋›ฐ์–ด๋‚˜๋ฉฐ, ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์ด๋‚˜ HTTPS์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

CTR (Counter Mode)
๊ฐ ๋ธ”๋ก์— ๊ณ ์œ ํ•œ ์นด์šดํ„ฐ ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•œ ์•”ํ˜ธํ™” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์„ฑ๋Šฅ์ด ์ข‹๊ณ , ๋‹ค์–‘ํ•œ ์šฉ๋„๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ŒAES์˜ ํŠน์ง•

๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™”
๋™์ผํ•œ ํ‚ค๋ฅผ ์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™” ๋ชจ๋‘์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ‚ค ๊ด€๋ฆฌ๊ฐ€ ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ณ ์ •๋œ ๋ธ”๋ก ํฌ๊ธฐ
AES๋Š” 128๋น„ํŠธ ๊ณ ์ • ๋ธ”๋ก ํฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

ํ‚ค ๊ธธ์ด
AES๋Š” 128๋น„ํŠธ, 192๋น„ํŠธ, 256๋น„ํŠธ ์„ธ ๊ฐ€์ง€ ํ‚ค ๊ธธ์ด๋ฅผ ์ง€์›ํ•˜์—ฌ ๋ณด์•ˆ ์ˆ˜์ค€์„ ์œ ์—ฐํ•˜๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋น ๋ฅธ ์ฒ˜๋ฆฌ ์†๋„
ํ•˜๋“œ์›จ์–ด ๋ฐ ์†Œํ”„ํŠธ์›จ์–ด ๋ชจ๋‘์—์„œ ๋งค์šฐ ๋น ๋ฅด๊ฒŒ ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์–ด, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์•”ํ˜ธํ™”์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ŒAES์˜ ์žฅ๋‹จ์ 

๐Ÿ“์žฅ์ 

๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ์„ฑ
AES๋Š” ๋Œ€๊ทœ๋ชจ์˜ ํ‚ค ๊ณต๊ฐ„๊ณผ ๋ณต์žกํ•œ ์ˆ˜ํ•™์  ๋ณ€ํ™˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋งค์šฐ ์•ˆ์ „ํ•œ ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ ํ‰๊ฐ€๋ฉ๋‹ˆ๋‹ค. ์–‘์ž ์ปดํ“จํ„ฐ์— ๋Œ€ํ•œ ๋ณด์•ˆ์„ฑ๋„ ์ƒ๋Œ€์ ์œผ๋กœ ๋›ฐ์–ด๋‚ฉ๋‹ˆ๋‹ค.
๋น ๋ฅธ ์„ฑ๋Šฅ
์†Œํ”„ํŠธ์›จ์–ด์™€ ํ•˜๋“œ์›จ์–ด ๋ชจ๋‘์—์„œ ๋น ๋ฅธ ์—ฐ์‚ฐ์ด ๊ฐ€๋Šฅํ•˜์—ฌ, ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ์— ์ ํ•ฉํ•ฉ๋‹ˆ๋‹ค.
์œ ์—ฐ์„ฑ
๋‹ค์–‘ํ•œ ํ‚ค ๊ธธ์ด๋ฅผ ์ง€์›ํ•˜๋ฏ€๋กœ, ์š”๊ตฌ๋˜๋Š” ๋ณด์•ˆ ์ˆ˜์ค€์— ๋”ฐ๋ผ ์œ ์—ฐํ•˜๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“๋‹จ์ 

ํ‚ค ๊ด€๋ฆฌ ๋ฌธ์ œ
๋Œ€์นญ ํ‚ค ์•”ํ˜ธํ™” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์—, ์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™”๋ฅผ ์œ„ํ•ด ๊ฐ™์€ ํ‚ค๋ฅผ ๊ณต์œ ํ•ด์•ผ ํ•˜๋ฉฐ, ์ด ํ‚ค๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.

๊ณ ์ •๋œ ๋ธ”๋ก ํฌ๊ธฐ
AES๋Š” ๊ณ ์ •๋œ 128๋น„ํŠธ ๋ธ”๋ก ํฌ๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๋ฏ€๋กœ, ๋ธ”๋ก ํฌ๊ธฐ๋ฅผ ๋งž์ถ”๊ธฐ ์œ„ํ•ด ํŒจ๋”ฉ์„ ํ•ด์•ผ ํ•  ๊ฒฝ์šฐ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“ŒExample

AES ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ํ†ตํ•ด ์ƒ์„ฑ๋œ key๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ์ €์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์‹คํ–‰ ์‹œ ํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  ํ•ด๋‹น ํ‚ค๋ฅผ ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“application.yml

aes:
  algorithm: AES
  key-size: 128
  secret: ${aes-key}
  mode: AES/CBC/PKCS5Padding
  iv-size: 16

ํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜, ํ‚ค ์‚ฌ์ด์ฆˆ๋ฅผ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์œ„์—์„œ ์„ค๋ช…ํ•œ CBC ๋ชจ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๊ธฐ ๋•Œ๋ฌธ์— ์ด์— ํ•„์š”ํ•œ mode, Initial Vector Size ๋„ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. secret ํ‚ค๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋“ฑ๋ก๋ฐฉ๋ฒ•์€ Link๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๐Ÿ“AesCryptoService

CryptoService ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” AesCryptService๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. AES ํ‚ค ์ƒ์„ฑ, ํ‚ค ์กฐํšŒ, ์•”/๋ณตํ˜ธํ™” ์ฒ˜๋ฆฌ๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.
common.encryption.aes.AesCryptoService

๐ŸŽˆConstructor

@Configuration
@Slf4j
public class AesCryptoService implements CryptoService {
    private final String algorithm;
    private final int keySize;
    private final String aesKey;
    private final String encryptionMode;
    private final byte[] initialVector;

    public AesCryptoService(@Value("${aes.algorithm}") String algorithm,
                            @Value("${aes.key-size}") int keySize,
                            @Value("${aes.secret}") String aesKey,
                            @Value("${aes.mode}") String encryptionMode,
                            @Value("${aes.iv-size}") int ivSize) throws NoSuchAlgorithmException {
        this.algorithm = algorithm;
        this.keySize = keySize;
        this.aesKey = aesKey;
        this.encryptionMode = encryptionMode;
        this.initialVector = new byte[ivSize];
        if (this.aesKey.isEmpty()) {
            log.error("AES key does not exist. create new key. โ–ผ");
            createKey();
        }
    }
    //๊ณ„์†..

application.yml ์— ์„ค์ •ํ•œ ๊ฐ’์„ ์ƒ์„ฑ์ž์—์„œ ๋ถˆ๋Ÿฌ์˜ต๋‹ˆ๋‹ค. AES key๊ฐ€ ์ƒ์„ฑ๋˜์–ด ์žˆ์ง€ ์•Š์„ ๊ฒฝ์šฐ ์ƒˆ๋กœ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.

๐ŸŽˆcreateKey

@Override
public void createKey() throws NoSuchAlgorithmException {
    KeyGenerator keyGen = KeyGenerator.getInstance(this.algorithm);
    keyGen.init(this.keySize);
    SecretKey aesKey = keyGen.generateKey();
    log.info("=================================AES KEY=================================");
    log.info("AES key : {}", Base64.getEncoder().encodeToString(aesKey.getEncoded()));
}

ํ‚ค๋ฅผ ์ƒ์„ฑํ•˜๊ณ  Base64๋กœ ์ธ์ฝ”๋”ฉ ํ•˜์—ฌ ๋กœ๊ทธ๋กœ ์ถœ๋ ฅํ•ฉ๋‹ˆ๋‹ค. ์ถœ๋ ฅ๋œ ํ‚ค ๊ฐ’์„ ํ™˜๊ฒฝ๋ณ€์ˆ˜์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค. IntelliJ์—์„œ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ•์€ Link๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

๐ŸŽˆDecode key

ํ‚ค๋ฅผ Base64 ๋กœ decoding ํ•˜์—ฌ ์ „๋‹ฌํ•ฉ๋‹ˆ๋‹ค. ServiceException ์— ๋Œ€ํ•ด์„œ๋Š” Link ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.

@Override
public SecretKey getPublicKey() {
    byte[] decodeKey = Base64.getDecoder().decode(this.aesKey);
    return new SecretKeySpec(decodeKey, 0, decodeKey.length, this.algorithm);
}

๐ŸŽˆencrypt, decrypt

๋™์ผํ•œ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์•”/๋ณตํ˜ธํ™” ํ•˜๋Š” ๋ฉ”์„œ๋“œ๋ฅผ ์ž‘์„ฑํ•ฉ๋‹ˆ๋‹ค.

@Override
public String decrypt(String encryptedText) {
	if(StringUtils.isEmpty(encryptedText)) return encryptedText;
    try {
        Cipher cipher = Cipher.getInstance(this.encryptionMode);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(this.initialVector);
        cipher.init(Cipher.DECRYPT_MODE, getPublicKey(), ivParameterSpec);
        byte[] decodedBytes = Base64.getDecoder().decode(encryptedText);
        byte[] decryptedBytes = cipher.doFinal(decodedBytes);
        return new String(decryptedBytes);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
             | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
        log.error("Decryption error. encryptedText : {}", encryptedText);
        throw new ServiceException(ErrorCode.SERVICE_ERROR, e);
    }
}

@Override
public String encrypt(String plainText) {
	if(StringUtils.isEmpty(plainText)) return plainText;
    try {
        Cipher cipher = Cipher.getInstance(this.encryptionMode);
        IvParameterSpec ivParameterSpec = new IvParameterSpec(this.initialVector);
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(), ivParameterSpec);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes());
        return Base64.getEncoder().encodeToString(encryptedBytes);
    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IllegalBlockSizeException
             | BadPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
        throw new ServiceException(ErrorCode.SERVICE_ERROR, e);
    }
}

์ด์ œ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด AES key ๊ฐ€ ํ˜„์žฌ๋Š” ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ฝ˜์†”์— ์ƒ์„ฑ๋œ key๊ฐ€ ์ถœ๋ ฅ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
console

AES key does not exist. create new key. โ–ผ
=================================AES KEY=================================
AES key : wcofmroZy...

์ถœ๋ ฅ๋œ ํ‚ค๋ฅผ ๋ณต์‚ฌํ•ด์„œ ์œ„์—์„œ ๋“ฑ๋กํ•œ ํ™˜๊ฒฝ๋ณ€์ˆ˜ aes-key์˜ ๊ฐ’์— ๋“ฑ๋กํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“์ž๋ฆฌ ์ˆ˜ ์„ค์ •

๋งŒ์ผ ์•”ํ˜ธํ™” ๋œ ๊ฐ’์˜ ์ž๋ฆฌ์ˆ˜ ๊ณ ์ • ์š”์ฒญ์ด ์žˆ๋‹ค๋ฉด ์•„๋ž˜์˜ ๋ฉ”์„œ๋“œ๋ฅผ ํ™œ์šฉํ•ฉ๋‹ˆ๋‹ค. ์•”ํ˜ธํ™”๋œ ๊ฐ’ + ๋žœ๋ค ํ…์ŠคํŠธ๋กœ 256์ž๋ฆฌ์ˆ˜๋ฅผ ๋งŒ๋“œ๋Š” ๋ฉ”์„œ๋“œ ์ž…๋‹ˆ๋‹ค.

    private String padTo256(String base64Encoded) {
        int encryptedTextLength = 256;
        StringBuilder padded = new StringBuilder(base64Encoded);
        SecureRandom random = new SecureRandom();
        String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
        while (padded.length() < encryptedTextLength) {
            char randomChar = characters.charAt(random.nextInt(characters.length()));
            padded.append(randomChar);
        }
        return padded.substring(0, encryptedTextLength);
    }

ํ•ด๋‹น ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค๋ฉด ๋ณตํ˜ธํ™” ์‹œ์—๋„ ๋žœ๋ค ํ…์ŠคํŠธ๋ฅผ ์ž˜๋ผ๋‚ด์–ด ์›๋ž˜์˜ ์•”ํ˜ธํ™” ๊ฐ’๋งŒ ๋‚จ๊ธฐ๋„๋ก ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ฃผ์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

encryptedText = encryptedText.substring(0, encryptedText.indexOf("==") + 2);

๐Ÿ“CryptoController

์ด์ „ RSA๋ฅผ ๊ตฌํ˜„ํ•  ๋•Œ ์‚ฌ์šฉํ–ˆ๋˜ CryptoController์— AES ํ‚ค ์š”์ฒญ method ๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@RestController
@RequiredArgsConstructor
@Tag(name = "์•”ํ˜ธํ™” ๊ด€๋ จ ์ •๋ณด ์š”์ฒญ", description = "๋ณด์•ˆ์ด ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์•”ํ˜ธํ™” ํ•˜๊ธฐ ์œ„ํ•œ ํ‚ค ์š”์ฒญ")
@RequestMapping("v1")
public class CryptoController {
    private final CryptoService rsaCryptoService;
    private final CryptoService aesCryptoService; //์ถ”๊ฐ€
    private final MessageConfig messageConfig;
    
    //์ƒ๋žต..
    
    @Operation(summary = "AES Key ์š”์ฒญ", description = """
            """, operationId = "API-999-02")
    @PostMapping(value = "/key/aes", produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<ItemResponse<PublicKeyResponse>> getAESPublicKey() {
        SecretKey key = (SecretKey) this.aesCryptoService.getPublicKey();
        String keyString = Base64.getEncoder().encodeToString(key.getEncoded());
        PublicKeyResponse publicKeyResponse = PublicKeyResponse.builder().publicKey(keyString).build();
        return ResponseEntity.ok()
                .body(ItemResponse.<PublicKeyResponse>builder()
                        .status(messageConfig.getCode(NormalCode.SEARCH_SUCCESS))
                        .message(messageConfig.getMessage(NormalCode.SEARCH_SUCCESS))
                        .item(publicKeyResponse)
                        .build());

์œ„์—์„œ ์ƒ์„ฑํ•œ ํ‚ค๋ฅผ Base64๋กœ ์ธ์ฝ”๋”ฉ ํ•˜์—ฌ ์ „์†กํ•ฉ๋‹ˆ๋‹ค.

์ถ”๊ฐ€์ ์œผ๋กœ ํ‚ค๋ฅผ ์š”์ฒญํ•˜๋Š” URI๋Š” ์ธ์ฆ์ด ํ•„์š”์—†๊ธฐ ๋•Œ๋ฌธ์— Spring Security์˜ ์ธ์ฆ URI ๋ชฉ๋ก์—์„œ ์ œ์™ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๊ธฐ ์œ„ํ•ด SecurityConfig์˜ ignoreUris ๋ชฉ๋ก์— ์ฃผ์†Œ๋ฅผ ์ถ”๊ฐ€ํ•ด ์ค๋‹ˆ๋‹ค.

์ด์ œ ํด๋ผ์ด์–ธํŠธ๋Š” ๋ฐ›์€ key ๋ฅผ Base64๋กœ ๋””์ฝ”๋”ฉ ํ•œ ํ›„ ๋‚˜์˜จ ํ‚ค๋กœ password ๋“ฑ์„ ์•”ํ˜ธํ™” ํ•˜์—ฌ ์ „์†กํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๋ณตํ˜ธํ™”๋Š” RSA์™€ ๋งˆ์ฐฎ๊ฐ€์ง€๋กœ AesCryptoService์˜ decrypt method๋ฅผ ํ˜ธ์ถœํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“ŒConclusion

AES๋Š” ๋น ๋ฅด๊ณ  ๊ฐ•๋ ฅํ•œ ๋ณด์•ˆ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ, ๋งŽ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‹ ๋ขฐ๋ฐ›๋Š” ๋Œ€์นญํ‚ค ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์ž…๋‹ˆ๋‹ค. ํ‚ค ๊ธธ์ด์— ๋”ฐ๋ผ ๋ณด์•ˆ ์ˆ˜์ค€์„ ์กฐ์ ˆํ•  ์ˆ˜ ์žˆ๊ณ , ๋‹ค์–‘ํ•œ ์•”ํ˜ธํ™” ๋ชจ๋“œ๋ฅผ ํ†ตํ•ด ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์— ๋งž๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ์—๋Š” ์•ž์„œ ์•Œ์•„๋ณธ RSA ์™€ AES ๋ฅผ ํ˜ผํ•ฉํ•œ ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ๋ฐฉ์‹์œผ๋กœ ์•”/๋ณตํ˜ธํ™” ๋กœ์ง์„ ๋ณ€๊ฒฝํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

profile
Back-end developer

0๊ฐœ์˜ ๋Œ“๊ธ€