padding?

  • SEED, ARIA, AES등 암호화 알고리즘은 지정된 block Size 단위로 암호화 복호화를 수행한다
  • 암복호화 하려는 입력 데이터를 block Size 단위로 쪼개어 반복 호출하여 전체 데이터를 암복호화 할 수 있다
  • 입력 데이터가 block Size의 배수가 아닌 경우 부족한 만큼 데이터를 추가하는 것을 Padding 이라 한다
  • 데이터를 추가하는 방식에 따라 PKCS5, PKCS7, X923 등 구분 된다

참고자료: https://www.di-mgt.com.au/cryptopad.html

X923

(in_data, out_data, padded의 데이터 표현은 모두 16진수이다)

  • X923 패딩은 block Size의 부족한 만큼을 0 값으로 채우며 마지막 바이트는 padding 된 바이트 수를 기록한다
    • ex) blockSize = 16
    • in_data1 = 00 01 02 03 04 05 06
    • padded1 = 00 01 02 03 04 05 06 00 00 00 00 00 00 00 00 09
    • in_data2 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d
    • padded2 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 00 02
    • in_data3 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e
    • padded3 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
  • X923 패딩된 데이터를 복원시키려면 마지막 바이트의 값만큼 뒤에서부터 데이터를 잘라주면 된다
    • padded1 = 00 01 02 03 04 05 06 00 00 00 00 00 00 00 00 09
    • out_data1 = 00 01 02 03 04 05 06 00 00 00 00 00 00 00 00 09
    • padded2 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 00 02
    • out_data2 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 00 02
    • padded3 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
    • out_data3 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
  • 입력 데이터가 block Size의 배수이면 padding 이 필요없을까?
    • 입력 데이터가 항상 block Size의 배수라는 보장이 있다면 padding을 사용할 필요가 없을 것이다
  • 입력 데이터가 block Size의 배수가 아닐 때만 padding 한다면?
    • ex) blockSize = 16
    • in_data1 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e
    • padded1 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
    • in_data2 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
    • padded2 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
    • 두 개 입력값에 대한 결과값이 같게 나오게 된다. 이후 padding 을 제거하려하면
    • data1 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e
    • data2 = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
    • padding 전의 원본 데이터가 data1, data2 중 어느 것인지 판단할 수가 없다
  • 입력 데이터가 block Size의 배수일 경우 padding 방법
    • block Size 만큼 padding 하는 것이다
    • in_data = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01
    • padded = 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10

참고자료: bouncycastle https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/paddings/X923Padding.java

egov X923

전자정부프레임워크의 X923 Padding 알고리즘은 입력 데이터가 block Size 의 배수인 경우 padding을 하지 않고 있다. 그로 인해 데이터 복원 시 정상적으로 되지 않을 수 있다. 아래는 Padding 클래스만을 테스트한 코드이다.

import egovframework.rte.fdl.cryptography.impl.aria.AnsiX923Padding;

public class TestPadding {

    public static void main(String[] arg) {
        AnsiX923Padding padding = new AnsiX923Padding();
        for (int length = 1; length <= 32; length++) {
            byte[] data = new byte[length];
            for (int index = 0; index < length; index++) {
                data[index] = (byte) (Math.random() * 256);
            }
            byte[] padded = padding.addPadding(data, 16);
            byte[] unpadded = padding.removePadding(padded, 16);

            System.out.println("----------------------------");
            
            PrintStream out = System.out;
            if (data.length != unpadded.length) {
                out = System.err;
            }
            out.println("  src:" + bytesToHex(data));
            out.println("  pad:" + bytesToHex(padded));
            out.println("unpad:" + bytesToHex(unpadded));
        }
    }

    private final static char[] hexArray = "0123456789ABCDEF".toCharArray();

    public static String bytesToHex(byte[] bytes) {
        String[] hexStrings = new String[bytes.length];
        for (int j = 0; j < bytes.length; j++) {
            int v = bytes[j] & 0xFF;
            hexStrings[j] = hexArray[v >>> 4] + "" + hexArray[v & 0x0F];
        }
        return String.join(" ", hexStrings);
    }
}

출력내용


----------------------------
  src:61
  pad:61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0F
unpad:61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0F
----------------------------
  src:04 A0
  pad:04 A0 00 00 00 00 00 00 00 00 00 00 00 00 00 0E
unpad:04 A0
----------------------------
  src:86 DB 8B
  pad:86 DB 8B 00 00 00 00 00 00 00 00 00 00 00 00 0D
unpad:86 DB 8B
----------------------------
  src:E8 1C 4B 63
  pad:E8 1C 4B 63 00 00 00 00 00 00 00 00 00 00 00 0C
unpad:E8 1C 4B 63
----------------------------
  src:FC 8E 7E 28 E0
  pad:FC 8E 7E 28 E0 00 00 00 00 00 00 00 00 00 00 0B
unpad:FC 8E 7E 28 E0
----------------------------
  src:6B D3 C1 3E A6 B4
  pad:6B D3 C1 3E A6 B4 00 00 00 00 00 00 00 00 00 0A
unpad:6B D3 C1 3E A6 B4
----------------------------
  src:EC F1 DB D5 63 42 D3
  pad:EC F1 DB D5 63 42 D3 00 00 00 00 00 00 00 00 09
unpad:EC F1 DB D5 63 42 D3
----------------------------
  src:9E F2 ED CD 2E 49 EA 4E
  pad:9E F2 ED CD 2E 49 EA 4E 00 00 00 00 00 00 00 08
unpad:9E F2 ED CD 2E 49 EA 4E
----------------------------
  src:06 7F 60 84 38 F7 C1 DF 6D
  pad:06 7F 60 84 38 F7 C1 DF 6D 00 00 00 00 00 00 07
unpad:06 7F 60 84 38 F7 C1 DF 6D
----------------------------
  src:01 73 18 AC 69 C0 CA 20 35 EE
  pad:01 73 18 AC 69 C0 CA 20 35 EE 00 00 00 00 00 06
unpad:01 73 18 AC 69 C0 CA 20 35 EE
----------------------------
  src:A7 70 0A 99 79 70 EB 67 86 15 B7
  pad:A7 70 0A 99 79 70 EB 67 86 15 B7 00 00 00 00 05
unpad:A7 70 0A 99 79 70 EB 67 86 15 B7
----------------------------
  src:17 33 81 26 D7 7C 20 35 7F A2 5A 83
  pad:17 33 81 26 D7 7C 20 35 7F A2 5A 83 00 00 00 04
unpad:17 33 81 26 D7 7C 20 35 7F A2 5A 83
----------------------------
  src:05 3A 64 9B 00 F6 29 22 9A B6 F6 94 A2
  pad:05 3A 64 9B 00 F6 29 22 9A B6 F6 94 A2 00 00 03
unpad:05 3A 64 9B 00 F6 29 22 9A B6 F6 94 A2
----------------------------
  src:D1 E5 87 CA 09 93 87 3A 65 B2 1D D0 EF 79
  pad:D1 E5 87 CA 09 93 87 3A 65 B2 1D D0 EF 79 00 02
unpad:D1 E5 87 CA 09 93 87 3A 65 B2 1D D0 EF 79
----------------------------
  src:FF 52 67 C6 60 C9 26 09 DB 1C B6 AB D9 95 2B
  pad:FF 52 67 C6 60 C9 26 09 DB 1C B6 AB D9 95 2B 01
unpad:FF 52 67 C6 60 C9 26 09 DB 1C B6 AB D9 95 2B 01
----------------------------
  src:BB 33 CB E4 16 64 CC 27 2F EE F1 05 BC 6E 04 03
  pad:BB 33 CB E4 16 64 CC 27 2F EE F1 05 BC 6E 04 03
unpad:BB 33 CB E4 16 64 CC 27 2F EE F1 05 BC 6E 04 03
----------------------------
  src:6F 6C C2 5A CB 31 CF EF A9 D4 4E D7 09 0F 51 E5 E8
  pad:6F 6C C2 5A CB 31 CF EF A9 D4 4E D7 09 0F 51 E5 E8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0F
unpad:6F 6C C2 5A CB 31 CF EF A9 D4 4E D7 09 0F 51 E5 E8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0F
----------------------------
  src:E2 22 96 AA 8E 4B E6 B2 3E D6 97 61 A6 ED F5 74 BF 7C
  pad:E2 22 96 AA 8E 4B E6 B2 3E D6 97 61 A6 ED F5 74 BF 7C 00 00 00 00 00 00 00 00 00 00 00 00 00 0E
unpad:E2 22 96 AA 8E 4B E6 B2 3E D6 97 61 A6 ED F5 74 BF 7C
----------------------------
  src:90 4B 57 DF 1F 25 1C F9 8A AC B9 48 09 A6 FA B2 91 9C FF
  pad:90 4B 57 DF 1F 25 1C F9 8A AC B9 48 09 A6 FA B2 91 9C FF 00 00 00 00 00 00 00 00 00 00 00 00 0D
unpad:90 4B 57 DF 1F 25 1C F9 8A AC B9 48 09 A6 FA B2 91 9C FF
----------------------------
  src:C6 D1 9F 55 26 C9 22 20 A1 44 FE A2 50 96 62 17 A4 AE 4E 41
  pad:C6 D1 9F 55 26 C9 22 20 A1 44 FE A2 50 96 62 17 A4 AE 4E 41 00 00 00 00 00 00 00 00 00 00 00 0C
unpad:C6 D1 9F 55 26 C9 22 20 A1 44 FE A2 50 96 62 17 A4 AE 4E 41
----------------------------
  src:F1 B6 C4 FF 6F C9 7E 13 1E 77 4F 64 29 96 E6 42 AF 6A 9D 9B E0
  pad:F1 B6 C4 FF 6F C9 7E 13 1E 77 4F 64 29 96 E6 42 AF 6A 9D 9B E0 00 00 00 00 00 00 00 00 00 00 0B
unpad:F1 B6 C4 FF 6F C9 7E 13 1E 77 4F 64 29 96 E6 42 AF 6A 9D 9B E0
----------------------------
  src:14 96 9D 69 3F 10 03 09 30 35 10 07 A2 45 6C E7 65 06 15 7A 4E E0
  pad:14 96 9D 69 3F 10 03 09 30 35 10 07 A2 45 6C E7 65 06 15 7A 4E E0 00 00 00 00 00 00 00 00 00 0A
unpad:14 96 9D 69 3F 10 03 09 30 35 10 07 A2 45 6C E7 65 06 15 7A 4E E0
----------------------------
  src:19 C9 D3 E0 31 F9 AB 2B 0B 69 D3 19 D1 CA AD 2C 93 E0 53 C6 1E D6 C8
  pad:19 C9 D3 E0 31 F9 AB 2B 0B 69 D3 19 D1 CA AD 2C 93 E0 53 C6 1E D6 C8 00 00 00 00 00 00 00 00 09
unpad:19 C9 D3 E0 31 F9 AB 2B 0B 69 D3 19 D1 CA AD 2C 93 E0 53 C6 1E D6 C8
----------------------------
  src:26 60 F3 72 C8 97 67 2A AE 6E AD 2E 83 94 B3 99 C4 A7 8F 20 44 F2 0B A3
  pad:26 60 F3 72 C8 97 67 2A AE 6E AD 2E 83 94 B3 99 C4 A7 8F 20 44 F2 0B A3 00 00 00 00 00 00 00 08
unpad:26 60 F3 72 C8 97 67 2A AE 6E AD 2E 83 94 B3 99 C4 A7 8F 20 44 F2 0B A3
----------------------------
  src:95 0E C4 8E A0 93 CC F8 E4 BF 28 62 65 78 71 1E 30 27 0D AE DD 8C 5F DC 17
  pad:95 0E C4 8E A0 93 CC F8 E4 BF 28 62 65 78 71 1E 30 27 0D AE DD 8C 5F DC 17 00 00 00 00 00 00 07
unpad:95 0E C4 8E A0 93 CC F8 E4 BF 28 62 65 78 71 1E 30 27 0D AE DD 8C 5F DC 17
----------------------------
  src:3F 08 ED 79 7D 52 0F 9C A7 3C 19 2B 33 78 B3 3C E5 E5 42 00 B3 A5 67 FE 3C 18
  pad:3F 08 ED 79 7D 52 0F 9C A7 3C 19 2B 33 78 B3 3C E5 E5 42 00 B3 A5 67 FE 3C 18 00 00 00 00 00 06
unpad:3F 08 ED 79 7D 52 0F 9C A7 3C 19 2B 33 78 B3 3C E5 E5 42 00 B3 A5 67 FE 3C 18
----------------------------
  src:4A C5 90 39 B7 EF C8 05 E9 C6 35 8C D9 B7 DC 1F 22 F0 A5 10 C9 2F D8 00 C9 E6 7F
  pad:4A C5 90 39 B7 EF C8 05 E9 C6 35 8C D9 B7 DC 1F 22 F0 A5 10 C9 2F D8 00 C9 E6 7F 00 00 00 00 05
unpad:4A C5 90 39 B7 EF C8 05 E9 C6 35 8C D9 B7 DC 1F 22 F0 A5 10 C9 2F D8 00 C9 E6 7F
----------------------------
  src:73 DC 28 DE F6 C3 DB 5A 67 3F D2 31 83 20 2F D9 EF F0 70 1F 37 41 2E FF 45 35 3D B5
  pad:73 DC 28 DE F6 C3 DB 5A 67 3F D2 31 83 20 2F D9 EF F0 70 1F 37 41 2E FF 45 35 3D B5 00 00 00 04
unpad:73 DC 28 DE F6 C3 DB 5A 67 3F D2 31 83 20 2F D9 EF F0 70 1F 37 41 2E FF 45 35 3D B5
----------------------------
  src:BF 95 71 A4 C4 98 BD B4 0C B6 B5 0E 64 DC DD 74 DC E5 30 1F AE 97 93 AD 24 2E B5 8E 43
  pad:BF 95 71 A4 C4 98 BD B4 0C B6 B5 0E 64 DC DD 74 DC E5 30 1F AE 97 93 AD 24 2E B5 8E 43 00 00 03
unpad:BF 95 71 A4 C4 98 BD B4 0C B6 B5 0E 64 DC DD 74 DC E5 30 1F AE 97 93 AD 24 2E B5 8E 43
----------------------------
  src:3E E9 64 0A B4 34 14 55 E7 A2 5E 7D F4 60 A5 A6 09 E5 E4 A0 F4 89 F0 F9 F1 9D BA 7F B7 F9
  pad:3E E9 64 0A B4 34 14 55 E7 A2 5E 7D F4 60 A5 A6 09 E5 E4 A0 F4 89 F0 F9 F1 9D BA 7F B7 F9 00 02
unpad:3E E9 64 0A B4 34 14 55 E7 A2 5E 7D F4 60 A5 A6 09 E5 E4 A0 F4 89 F0 F9 F1 9D BA 7F B7 F9
----------------------------
  src:DD 08 CF 72 8B DA 6A 5E C9 57 78 99 38 F1 15 10 91 8F 4A D7 C4 A1 D8 45 D9 38 D1 6D C9 3E F6
  pad:DD 08 CF 72 8B DA 6A 5E C9 57 78 99 38 F1 15 10 91 8F 4A D7 C4 A1 D8 45 D9 38 D1 6D C9 3E F6 01
unpad:DD 08 CF 72 8B DA 6A 5E C9 57 78 99 38 F1 15 10 91 8F 4A D7 C4 A1 D8 45 D9 38 D1 6D C9 3E F6 01
----------------------------
  src:6E 05 E6 17 D9 BB F1 34 64 D8 45 C5 99 58 95 50 1C AF 96 71 55 11 4E 91 FD CE 81 C5 32 54 58 C2
  pad:6E 05 E6 17 D9 BB F1 34 64 D8 45 C5 99 58 95 50 1C AF 96 71 55 11 4E 91 FD CE 81 C5 32 54 58 C2
unpad:6E 05 E6 17 D9 BB F1 34 64 D8 45 C5 99 58 95 50 1C AF 96 71 55 11 4E 91 FD CE 81 C5 32 54 58 C2

블록사이즈의 배수 +- 1 인 경우 정상적으로 복원되지 않는 현상을 확인할 수 있다. 이 내용에 대해 버그 신고를 하였으나, 다른 인코딩 방식을 사용하거나, KISA에 암호화 알고리즘에 대해 문의하라는 관계 없는 답변만을 주고 있는 상황이다.

문제는 블로그나 깃헙을 통해서 이미 소스코드가 많이 공유가 되어있는 상황이고, 이를 적용한 시스템의 경우 고정된 길이의 입력값만 사용하다가 적용 영역을 늘리는 상황에서 버그가 발생할 수 있다는 것이다.

예상되는 해결방안은 아래와 같다

  1. 문자열의 데이터의 경우 trim() 호출을 통해서 제대로 제거되지 않은 padding를 해결할 수 있을 것이다. 하지만 100% 보장할 수는 없다. (block Size가 클 수록 trim() 으로 제거되지 않으며, 원본값의 앞뒤 공백도 제거하기 때문)
  2. 수정된 padding 알고리즘으로 변환한다. 이 경우 입력값이 block Size의 배수인 경우 padding 결과가 다르기 때문에 데이터 변환 작업이 필요하다. (기존 padding알고리즘으로 제거 후 신규 padding 알고리즘으로 추가)

수정된 자바 코드: http://zsoo.net/assets/java/AnsiX923Padding.java

public class AnsiX923Padding {
    private static final byte PADDING_VALUE = 0x00;

    public byte[] addPadding(byte[] source, int blockSize) {
        int paddingCnt = blockSize - (source.length % blockSize);
        byte[] padded = new byte[source.length + paddingCnt];

        System.arraycopy(source, 0, padded, 0, source.length);
        Arrays.fill(padded, source.length, padded.length - 1, PADDING_VALUE);
        padded[padded.length - 1] = (byte) paddingCnt;

        return padded;
    }

    public byte[] removePadding(byte[] source, int blockSize) {
        int paddingCnt = source[source.length - 1];
        
        byte[] unpadded = new byte[source.length - paddingCnt];
        System.arraycopy(source, 0, unpadded, 0, unpadded.length);

        return unpadded;
    }
}