๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐Ÿ’Š Java & Kotlin & Spring/- Java & kotlin

[Java] Bouncy Castle ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•˜์—ฌ ํŒŒ์ผ ์•”ํ˜ธํ™”, ๋ณตํ˜ธํ™” ํ•˜๊ธฐ (feat.๋ธ”๋ก ์•”ํ˜ธ์˜ SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜)

by Wonit 2021. 6. 19.

์ตœ๊ทผ BoB ๋ฉด์ ‘์„ ์ค€๋น„ํ•˜๋ฉด์„œ ์ง€๋‚œ ํ”„๋กœ์ ํŠธ๋“ค์„ ๋˜๋Œ์•„๋ณด๊ณ  ์žˆ์—ˆ๋‹ค.

 

๋‚ด ์ง€๋‚œ ํ”„๋กœ์ ํŠธ ์ค‘์— ํ•™๊ณผ ์—ฐ๊ตฌ์‹ค์—์„œ ํ•™์‚ฌ ์กธ์—… ๋…ผ๋ฌธ์— ์ฐธ์—ฌํ•ด์„œ ํŒŒ์ผ ์•”๋ณตํ˜ธํ™” ๋ชจ๋“ˆ์„ ๊ตฌํ˜„ํ–ˆ๋˜ ๊ฒฝํ—˜์ด ์žˆ๋‹ค.

 

ํ˜„์žฌ ํ•ด๋‹น ํ”„๋กœ๊ทธ๋žจ์˜ ์†Œ์Šค ์ฝ”๋“œ๋Š” ๋ณด์•ˆ์ƒ ๊ณต๊ฐœ๋˜์–ด ์žˆ์ง€ ์•Š๊ณ  ๋‚˜๋„ 2๋…„ ์ „์˜ ํ”„๋กœ์ ํŠธ๋ผ์„œ ๊ธฐ์–ต์ด ์ž˜ ๋‚˜์ง€ ์•Š์•˜๋‹ค.

 

๊ทธ๋ž˜์„œ ์ตœ๋Œ€ํ•œ ๊ทธ ๊ธฐ์–ต์„ ๋”๋“ฌ์–ด ํŒŒ์ผ ์•”๋ณตํ˜ธํ™” ๋ชจ๋“ˆ์„ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜๋ ค ํ•˜๋Š”๋ฐ, ์ƒ๊ฐ๋ณด๋‹ค ํ•œ๊ธ€๋กœ ๋œ ์ž๋ฃŒ๊ฐ€ ๋งŽ์ง€ ์•Š์•„ ๋‹ค๋ฅธ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ๊ณต์œ ํ•œ๋‹ค๋ฉด ๊ฝค ๋„์›€ ๋  ๊ฒƒ ๊ฐ™์•„์„œ ๊ทธ ๊ณผ์ •์„ ํ•œ ๋ฒˆ ํฌ์ŠคํŒ…ํ•˜๋ ค ํ•œ๋‹ค.

 


๋ชฉ์ฐจ

  • Bouncy Castle
  • ๋ธ”๋ก ์•”ํ˜ธ, SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ž€?
  • ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
    • ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ
    • ์˜์กด์„ฑ ์ถ”๊ฐ€
    • FileUtil.class ๊ตฌํ˜„
    • BouncyModule.class ๊ตฌํ˜„
    • Encryption.class ๊ตฌํ˜„
  • ํ…Œ์ŠคํŠธ

Bouncy Castle

์šฐ์„  ๋‚˜๋Š” ํŒŒ์ผ ์•”ํ˜ธํ™” ๋ณตํ˜ธํ™”๋ฅผ ์œ„ํ•ด Bouncy Castle ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ด์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

Bouncy Castle์€ ์œ ๋ช…ํ•œ ์•”ํ˜ธํ™” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋กœ Java, C# ๋ฒ„์ „์— ๋”ฐ๋ผ ๋ฐฐํฌ๋œ๋‹ค.

 

๋Œ€์นญํ‚ค ์•”ํ˜ธ, ๋ธ”๋ก ์•”ํ˜ธ, SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ž€?

 

์šฐ๋ฆฌ๋Š” Bouncy Castle ๋กœ ์•”ํ˜ธํ™”๋ฅผ ์ˆ˜ํ–‰ํ•  ๊ฒƒ์ธ๋ฐ, ์‹ค์งˆ์ ์œผ๋กœ ์•”ํ˜ธํ™”๋ฅผ ์ˆ˜ํ–‰ํ•  ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ๋Œ€์นญํ‚ค ์•”ํ˜ธ ์‹œ์Šคํ…œ์„ ์ด์šฉํ•  ๊ฒƒ์ด๋‹ค.

 

๋Œ€์นญํ‚ค ์•”ํ˜ธ๋Š” ์•”ํ˜ธํ™” ํ‚ค์™€ ๋ณตํ˜ธํ™” ํ‚ค๊ฐ€ ๋™์ผํ•œ ์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

 

๋Œ€์นญ ํ‚ค ์•”ํ˜ธ ์‹œ์Šคํ…œ์—์„œ๋Š” 2๊ฐ€์ง€ ๋ฐฉ๋ฒ•์ด ๋Œ€ํ‘œ์ ์ด๋‹ค.

 

  1. ๋ฐ์ดํ„ฐ๋ฅผ ๋ธ”๋ก ๋‹จ์œ„๋กœ ์•”ํ˜ธํ™” : ๋ธ”๋ก ์•”ํ˜ธ
  2. ๋ฐ์ดํ„ฐ๋ฅผ ์ŠคํŠธ๋ฆผ ๋‹จ์œ„๋กœ ์•”ํ˜ธํ™” : ์ŠคํŠธ๋ฆผ ์•”ํ˜ธ

 

๋ธ”๋ก ์•”ํ˜ธ๋ž€?

๋Œ€ํ‘œ์ ์ธ ๋ธ”๋ก ์•”ํ˜ธ์˜ ๊ตฌ์กฐ๋Š” Feistal ๊ณผ SPN ๊ตฌ์กฐ๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ์šฐ๋ฆฌ๋Š” ํŽ˜์ด์Šคํƒˆ ๊ตฌ์กฐ๋ฅผ ์ด์šฉํ•˜๋ ค ํ•œ๋‹ค.

 

ํŽ˜์ด์Šคํƒˆ ๊ตฌ์กฐ๋Š” ๋ผ์šด๋“œ ํ•จ์ˆ˜๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ ์šฉ๋˜๋Š” ๊ตฌ์กฐ๋กœ ๋Œ€ํ‘œ์ ์œผ๋กœ๋Š” DES์™€ ๊ตญ์‚ฐ ์ œํ’ˆ์ธ SEED๊ฐ€ ์กด์žฌํ•œ๋‹ค.

 

์ฐธ๊ณ ๋กœ SPN ๊ตฌ์กฐ๋Š” ๊ฐ€์žฅ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋Š” AES๊ฐ€ ์กด์žฌํ•œ๋‹ค

 

์šฐ๋ผ๋Š” ๋ธ”๋ก ์•”ํ˜ธ์˜ SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•˜๋ ค ํ•œ๋‹ค.

 

SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋ž€?

 

SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ 1999๋…„ 2์›” ํ•œ๊ตญ์ธํ„ฐ๋„ท์ง„ํฅ ์›๊ณผ ๊ตญ๋‚ด ์•”ํ˜ธ์ „๋ฌธ๊ฐ€๋“ค์ด ์ˆœ์ˆ˜ ๊ตญ๋‚ด๊ธฐ์ˆ ๋กœ ๊ฐœ๋ฐœํ•œ 128๋น„ํŠธ ๋ธ”๋ก ์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด๋‹ค.

 

1999๋…„ ๊ฐœ๋ฐœ๋˜์—ˆ๋Š”๋ฐ 2005๋…„ ๊ตญ์ œ ํ‘œ์ค€ํ™” ๊ธฐ๊ตฌ์ธ ISO/IEC ๊ตญ์ œ ๋ธ”๋ก์•”ํ˜ธ์•Œ๊ณ ๋ฆฌ์ฆ˜ IETFํ‘œ์ค€์œผ๋กœ ์ œ์ •๋˜์—ˆ๋‹ค.

 

์ด์ œ ์–ด๋Š ์ •๋„ ๊ธฐ๋ณธ์€ ๋˜์—ˆ์œผ๋‹ˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์‹ค์ œ๋กœ ๋งŒ๋“ค์–ด๋ณด์ž!

 

ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ

 

ํ”„๋กœ์ ํŠธ๋Š” Gradle ํ”„๋กœ์ ํŠธ๋กœ ์ƒ์„ฑํ•˜๋„๋ก ํ•˜์ž!

 

 

๊ทธ๋ฆฌ๊ณ  Bouncy Castle ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์˜์กด์„ฑ์„ build.gradle ์— ์ถ”๊ฐ€ํ•ด์ฃผ์ž!

 

dependencies {
    implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.68'
}

 

๊ทธ๋ฆฌ๊ณ  ์•„๋ž˜ ๊ธฐ์ˆ ๋œ ๋‚ด์šฉ๋Œ€๋กœ ์ž˜ ๊ตฌํ˜„ํ•œ๋‹ค๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋ฅผ ๊ฐ–๊ฒŒ ๋  ๊ฒƒ์ด๋‹ค

 

 

FileUtil.java ๊ตฌํ˜„

 

ํ•ด๋‹น ํด๋ž˜์Šค๋Š” ์•”ํ˜ธํ™”ํ•  ํŒŒ์ผ์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ์•”ํ˜ธํ™”๋œ ํŒŒ์ผ์„ ์ €์žฅํ•  ์œ ํ‹ธ ํด๋ž˜์Šค์ด๋‹ค.

 

public class FileUtil {

    private FileInputStream fileInputStream;
    private FileOutputStream fileOutputStream;

    public byte[] getFileBytesFrom(String path) throws IOException {
        // ํŒŒ์ผ ๊ฐ์ฒด ์ƒ์„ฑ
        File file = new File(path);
        fileInputStream = new FileInputStream(file);

        byte[] fileBytes = new byte[(int)file.length()];

        fileInputStream.read(fileBytes);

        fileInputStream.close();
        return fileBytes;
    }

    public void saveFile(String path, byte[] fileData) throws IOException {
        fileOutputStream = new FileOutputStream(path);

        fileOutputStream.write(fileData);

        fileOutputStream.close();
    }
}

 

BouncyModule.java ๊ตฌํ˜„

 

์ด์ œ ์‹ค์ œ๋กœ BouncyCastle ๋กœ ๋ธ”๋ก ์•”ํ˜ธ๋ฅผ ์ด์šฉํ•ด์„œ ํŒŒ์ผ์„ ์•”ํ˜ธํ™” ํ•ด๋ณด์ž

 

public class BouncyModule {

    public byte[] encrypt(String key, byte[] plainText) {
        byte[] keyBytes = key.getBytes();

        // ๋ธ”๋ก ์•”ํ˜ธ ์šด์šฉ
        // ๋ธ”๋ก๋ณด๋‹ค ๋ฐ์ดํ„ฐ๊ฐ€ ์งง์„ ๊ฒฝ์šฐ ํŒจ๋”ฉ์„ ์‚ฌ์šฉํ•จ
        // ๋ธ”๋ก ์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ๋Š” SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•จ
        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new SEEDEngine());
        // ์ดˆ๊ธฐํ™” ๋ฐ ํ‚ค ํŒŒ๋ผ๋ฏธํ„ฐ ์ƒ์„ฑ ์ฒซ ๋ฒˆ์งธ ๋งค๊ฐœ๋ณ€์ˆ˜๊ฐ€ true ๋ผ๋ฉด ์•”ํ˜ธํ™” ๋ชจ๋“œ
        cipher.init(true, new KeyParameter(keyBytes));

        return getBytes(plainText, cipher);
    }

    public byte[] decrypt(String key, byte[] cipherText) {
        byte[] keyBytes = key.getBytes();

        BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new SEEDEngine());
        cipher.init(false, new KeyParameter(keyBytes));

        return getBytes(cipherText, cipher);
    }

    private byte[] getBytes(byte[] targetData, BufferedBlockCipher cipher) {
        byte[] outputData = new byte[cipher.getOutputSize(targetData.length)];

        int tam = cipher.processBytes(targetData, 0, targetData.length, outputData, 0);

        try {
            cipher.doFinal(outputData, tam);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return outputData;
    }
}

 

๋ชจ๋“œ๋Š” ๋ธ”๋ก ์•”ํ˜ธ ๋ชจ๋“œ๋ฅผ ์šด์šฉํ•œ๋‹ค.

 

๋งŒ์•ฝ ๋ธ”๋ก๋ณด๋‹ค ๋ฐ์ดํ„ฐ์˜ ๊ธธ์ด๊ฐ€ ์งง์„ ๊ฒฝ์šฐ ํŒจ๋”ฉ์„ ์‚ฌ์šฉํ•˜๊ณ , ๋ธ”๋ก ์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์œผ๋กœ SEED ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์‚ฌ์šฉํ•œ๋‹ค๊ณ  ์ง€์ •ํ•ด์ค€๋‹ค.

 

EncryptUtil.java ๊ตฌํ˜„

 

์œ„์˜์—์„œ ์ƒ์„ฑํ•œ ํŒŒ์ผ ์œ ํ‹ธ๊ณผ bouncy castle ๋ชจ๋“ˆ์„ ์ด์šฉํ•ด์„œ ์•”ํ˜ธํ™” ์œ ํ‹ธ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž

 

public class EncryptUtil {
    private static BouncyModule bouncyModule = new BouncyModule();
    private static FileUtil fileUtil = new FileUtil();

    public static void encryption(String key, String filePath) throws IOException {
        byte[] plainFileBytes = fileUtil.getFileBytesFrom(filePath);
        byte[] encryptedFileBytes = bouncyModule.encrypt(key, plainFileBytes);
        fileUtil.saveFile(filePath, encryptedFileBytes);
    }

    public static void decryption(String key, String filePath) throws IOException {
        byte[] encryptedFileBytes = fileUtil.getFileBytesFrom(filePath);
        byte[] decryptedFile = bouncyModule.decrypt(key, encryptedFileBytes);
        fileUtil.saveFile(filePath, decryptedFile);
    }
}

ํ…Œ์ŠคํŠธ

 

์ด์ œ ๊ตฌํ˜„์ด ๋๋‚ฌ์œผ๋‹ˆ ํŒŒ์ผ ํ•˜๋‚˜๋ฅผ ์žก๊ณ  ํ…Œ์ŠคํŠธํ•ด๋ณด์ž

 

๋‚˜๋Š” ๋ฐ”ํƒ•ํ™”๋ฉด์— ์žˆ๋Š” ํ•™๊ต ๋กœ๊ณ  png ํŒŒ์ผ์„ ์•”ํ˜ธํ™” ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ๋‹ค!

 

 

์•”ํ˜ธํ™”๋ฅผ ํ•˜๊ธฐ ์ „์—๋Š” ํŒŒ์ผ์ด ์ž˜ ์—ด๋ฆฐ๋‹ค.

 

์ด์ œ main ํ•จ์ˆ˜์—์„œ ์•”ํ˜ธํ™”๋ฅผ ์ˆ˜ํ–‰ํ•˜์ž

 

public class Main {
    public static void main(String[] args) throws Exception {

        String key = "$2a$10$mxLAM1fAEDPWkFz83IPDH.7yvyY6njmIMSk937jdH9UD3HhbqYPgO";
        String path = "/Users/my/Desktop/logo.png";

        EncryptUtil.encryption(key, path);
    }
}

 

๊ทธ๋Ÿผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ํŒŒ์ผ์„ ์—ด ์ˆ˜ ์—†๋‹ค๊ณ  ๋‚˜์˜จ๋‹ค

 

 

๊ทธ๋ฆฌ๊ณ  ๋ณตํ˜ธํ™”๋ฅผ ์ˆ˜ํ–‰ํ•ด๋ณด์ž

 

public class Main {
    public static void main(String[] args) throws Exception {

        // key ์ƒ์„ฑ (60 ๊ธธ์ด)
        String key = "$2a$10$mxLAM1fAEDPWkFz83IPDH.7yvyY6njmIMSk937jdH9UD3HhbqYPgO";
        String path = "/Users/jangwonik/Desktop/logo.png";

        // EncryptUtil.encryption(key, path);
        EncryptUtil.decryption(key, path);
    }
}

 

๊ทธ๋Ÿผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋‹ค์‹œ ํŒŒ์ผ์„ ์—ด ์ˆ˜ ์žˆ๊ฒŒ ๋˜์—ˆ๋‹ค!

 

 

๋Œ“๊ธ€