728x90

블록 암호의 주요 패딩 알고리즘

패딩 알고리즘 개요

블록 암호는 정해진 크기(예: 64비트=8바이트, 128비트=16바이트 등)의 블록 단위로 데이터를 암호화합니다. 따라서 메시지 길이가 블록 크기의 배수가 아닌 경우 패딩(padding)을 추가하여 마지막 블록을 채워야 합니다. 패딩은 평문에 일정한 규칙으로 의미 없는 바이트들을 추가하는 작업으로, 복호화 시에도 동일한 규칙으로 이를 제거하여 원래의 평문을 복원할 수 있게 해줍니다. 패딩 방식에 따라 암호화된 결과의 길이가 블록 크기까지 늘어나며, 복호화 프로그램이 패딩된 바이트들을 정확히 인식하고 제거할 수 있도록 특정 패턴을 따릅니다.

패딩을 적용하지 않으면 마지막 블록이 부족한 상태로 암호화를 수행할 수 없을 뿐 아니라, 복호화 시에도 어디까지가 실제 평문이고 어디부터가 쓰레기 데이터인지 구분할 수 없습니다. 예를 들어 평문의 길이가 블록 크기의 정확한 배수인 경우, 별도의 조치 없이 암호화하면 복호화 시 마지막 바이트가 평문의 일부인지 패딩인지 구분할 수 없습니다. 이를 해결하기 위해 패딩 규격들은 항상 최소 1바이트 이상의 패딩을 추가하도록 정의되어 있으며, 평문 길이가 딱 맞아 떨어지는 경우에도 하나의 전체 블록을 패딩으로 채워 구분이 가능하게 합니다.

대표적인 패딩 알고리즘 목록

블록 암호에서 널리 사용되거나 표준으로 정의된 대표적인 패딩 방식은 다음과 같습니다:

  • PKCS#7 패딩 – 패딩으로 추가되는 모든 바이트의 값이 추가된 전체 패딩 바이트의 개수를 나타내는 방식 (PKCS#5는 8바이트 블록 암호에 국한된 동일 방식)
    예를 들어 4바이트를 패딩으로 추가해야 하면 각 바이트에 값 0x04를 넣습니다.
  • ANSI X.923 패딩 – 마지막 바이트를 추가된 패딩 바이트의 개수로 설정하고, 그 밖의 패딩 바이트들은 모두 0x00 (또는 구현에 따라 임의의 값)으로 채우는 방식
    예를 들어 4바이트 패딩 시 마지막 바이트는 0x04, 이전의 3바이트는 0x00으로 채웁니다.
  • ISO/IEC 7816-4 패딩 – 패딩의 첫 바이트로 0x80 하나를 추가하고, 남는 패딩 바이트는 모두 0x00으로 채우는 방식
    만약 패딩이 한 바이트만 필요하면 0x80 한 바이트만 추가합니다.
  • 제로 패딩(Zero Padding) – 필요한 패딩 바이트를 전부 0x00 값으로 채우는 방식
    다른 메커니즘과 달리 패딩 자체에 대한 별도 표준이 아니지만, 실행 환경에서 평문 길이를 별도로 알고 있거나 평문의 마지막에 널(byte 0x00)이 올 수 없는 경우에 종종 사용됩니다
  • ISO 10126 패딩 – 현재는 폐지된 이전 표준으로, 패딩 길이 이외의 패딩 바이트들을 임의의 랜덤 값들로 채우고 마지막 바이트에 패딩 개수를 기록하는 방식입니다

이외에도 특수한 상황에서는 비트 패딩(bit padding)이 사용되기도 하는데, ISO/IEC 7816-4 방식이 이에 해당하며 비트 단위 프로토콜에서도 적용할 수 있는 패딩 방식입니다.

패딩 알고리즘 동작 원리와 예시

PKCS#7 패딩 (PKCS#5 포함)

PKCS#7은 현재 가장 널리 쓰이는 패딩 규격으로, 추가되는 각 바이트의 값으로 추가된 패딩 바이트의 개수를 기록합니다. 즉, N바이트를 패딩해야 한다면 패딩 공간을 N으로 채운 값 N을 가진 바이트들로 모두 채우는 방식입니다. 예를 들어 블록 크기가 8바이트이고 마지막 블록에 5바이트의 패딩이 필요하다면, 0x05 값을 가진 바이트 5개를 추가합니다. 만약 평문 길이가 블록의 배수라 하더라도 규격상 항상 8바이트 패딩 블록을 추가해야 하므로, 이 경우에는 8바이트 모두를 값 0x08로 채운 하나의 패딩 블록이 추가됩니다 

PKCS#5 패딩은 PKCS#7의 특별한 경우로, 64비트(8바이트) 블록 암호(예: DES)에 대해서만 정의된 것입니다. 내용적으로 PKCS#7과 동일하며, 단지 블록 크기가 8바이트인 경우에 한해 쓰인 명칭일 뿐이므로 실제 구현이나 사용에서는 PKCS#7과 interchangeably 사용됩니다 

  • 예시: 평문이 "HELLO" (5바이트)이고 블록 크기가 8바이트라고 가정하면, PKCS#7 패딩을 적용하여 3바이트를 추가해야 합니다. 추가되는 바이트들은 모두 패딩 전체 크기인 0x03으로 채워지므로, 실제 암호화되는 최종 바이트열은 "HELLO\x03\x03\x03"이 됩니다. 복호화 측에서는 암호문을 복호화한 결과의 마지막 바이트를 확인하여 0x03이므로 마지막 3바이트를 제거함으로써 원래 평문을 복원합니다.

ANSI X.923 패딩

ANSI X.923 패딩은 미국 ANSI에서 정의한 데이터 패딩 방식으로, 패딩의 마지막 바이트에만 패딩 바이트의 개수를 기록하고 그 이전의 모든 패딩 바이트들은 0값으로 채우는 것이 특징입니다 패딩으로 최소 1바이트에서 최대 블록 크기 바이트까지 추가되며(블록 크기가 8일 경우 1~8바이트), 마지막에 추가된 패딩 바이트의 값은 추가된 패딩 바이트의 수 N을 의미하는 0xN입니다. 표준상 마지막 바이트 이외의 패딩 바이트 값은 무작위 값으로 채울 수 있으나, 일반 구현에서는 편의상 모두 0x00으로 채우는 경우가 많습니다

  • 예시: 블록 크기가 8바이트인데 마지막 블록에 4바이트의 패딩이 필요하다고 가정하면, ANSI X.923 방식에서는 추가되는 4바이트 중 마지막 바이트를 0x04로 설정하고 앞선 3바이트는 0x00으로 채웁니다 따라서 패딩된 최종 블록은 ... | DD DD DD DD 00 00 00 04 |의 형태를 갖습니다. 복호화 시 마지막 바이트의 값 0x04를 읽어 4바이트의 패딩이 추가되었음을 알고, ciphertext 끝의 4바이트를 제거하여 원문을 얻습니다.

PKCS#7 패딩과 ANSI X.923 패딩은 동일한 정보를 약속된 다른 형태로 기록할 뿐 기능적으로 등가(equivalent)합니다 두 방식 모두 마지막 바이트에 패딩 길이를 담고 있으며 최대 255 바이트까지 패딩을 표현할 수 있습니다. 차이는 PKCS#7은 패딩 바이트들을 모두 동일한 값으로 채우는 반면 ANSI X.923은 마지막 바이트를 제외한 패딩 영역을 0 또는 임의의 값들로 채운다는 점뿐입니다. 이 미묘한 차이로 인한 유의미한 이점은 거의 없으며, 실제 보안성이나 성능 면에서 두 방식은 대등합니다 

ISO/IEC 7816-4 패딩

ISO/IEC 7816-4 패딩은 국제 표준으로, 스마트카드 등의 파일 시스템 규격에서 유래한 패딩 방식입니다 패딩의 첫 번째 바이트를 0x80 값으로 설정하고 나머지 필요한 패딩 바이트들은 모두 0x00으로 채워 블록을 마무리하는 것이 특징입니다 이 방식은 종종 “80h 패딩”, “1-그리고-0 패딩(one-and-zero padding)” 또는 비트 패딩(bit padding)이라고도 불리는데, 이는 이 규격이 실제로 평문 데이터의 끝에 1 비트(1000 0000의 0x80)만 세우고 나머지 패딩 구간은 0으로 채우는 개념이기 때문입니다. 이러한 정의 덕분에 바이트 단위뿐 아니라 비트 단위로도 응용할 수 있어, 메시지 길이가 바이트 경계가 아닐 때도 동일 원리로 패딩을 적용할 수 있습니다.

  • 예시: 블록 크기가 8바이트이고 4바이트의 패딩이 필요한 경우, ISO 7816-4 방식으로 패딩하면 첫 패딩 바이트는 0x80, 나머지 3바이트는 0x00으로 채워집니다. 예를 들면 최종 블록이 ... | DD DD DD DD 80 00 00 00 | 형태가 됩니다. 만약 1바이트의 패딩만 필요했다면 0x80 한 바이트만 추가되어 마지막 블록은 ... | ... DD 80 |와 같이 0x80으로 끝나게 됩니다. 복호화 시에는 복호화된 데이터의 끝부분부터 역방향으로 스캔하며 최초로 나타나는 0x80 바이트를 찾고, 그 바이트부터 끝까지를 패딩으로 간주하여 제거합니다. 만약 역으로 탐색했을 때 0x80이 나타나지 않거나 규칙에 맞지 않는 값이 나오면 패딩 오류로 간주합니다.

ISO 7816-4 패딩은 명시적인 패딩 길이 숫자가 없기 때문에 이론적으로는 무제한 길이의 패딩도 지원할 수 있습니다 다만 일반적으로는 필요한 최소한의 바이트만 패딩으로 추가하며, 다른 패딩들과 마찬가지로 평문 길이가 블록 경계에 정확히 맞아떨어지더라도 0x80과 0으로 이루어진 한 블록의 패딩을 추가하도록 정의합니다 (그렇지 않으면 평문의 마지막 바이트가 우연히 0x80일 때 혼동이 발생할 수 있기 때문입니다).

제로 패딩 (Zero Padding)

제로 패딩은 말 그대로 모든 패딩 바이트를 0x00 값으로 채우는 방식입니다. 예를 들어 4바이트의 패딩이 필요하면 00 00 00 00을 추가하는 식입니다. 이 방식은 엄밀히 말해 암호화 표준으로 공식화된 적은 없지만, 구현이 단순하여 일부 상황에서 관습적으로 사용됩니다. 특히 암호화하는 데이터의 실제 길이를 별도의 메타데이터로 알고 있는 경우나, 평문 데이터가 문자열이고 문자열의 끝에는 0x00 (널 문자) 등이 올 수 없는 환경에서 활용됩니다. 이러한 경우에는 복호화 후 미리 알고 있던 길이만큼만 취하거나, 또는 문자열의 경우 '\0' 이후를 무시하는 방식으로 패딩을 제거하여 원문을 복원할 수 있습니다.

  • 예시: 평문 "ABC" (3바이트)를 8바이트 블록 암호로 암호화한다고 가정하면, 남는 5바이트를 모두 0x00으로 패딩할 수 있습니다. 암호화되는 최종 바이트열은 "ABC\x00\x00\x00\x00\x00"가 되며, 복호화한 쪽에서 원본 데이터의 길이(3바이트)를 알고 있다면 앞의 3바이트 "ABC"만을 취하고 이후의 0x00 바이트들은 버립니다.

제로 패딩은 구현이 가장 간단하지만 패딩을 식별할 수 있는 정보가 존재하지 않으므로 안전한 복원에는 별도의 전제 조건이 필요합니다. 예를 들어 평문 데이터가 임의의 바이너리 데이터일 경우 마지막에 0x00 바이트가 포함되어도 전혀 이상하지 않으므로, 패딩으로 추가된 0x00들과 평문의 실제 0x00 데이터를 구분할 방법이 없습니다. 따라서 평문 길이를 별도로 전달하거나, 혹은 평문이 특정 문자 인코딩 문자열이라서 0x00은 종단 문자로서만 등장한다는 보장이 있을 때에만 사용이 권장됩니다. 만약 이러한 조건 없이 제로 패딩을 사용할 경우 복호화 결과에서 패딩과 실제 데이터를 혼동하여 데이터 무결성이 깨질 위험이 있습니다.

패딩 알고리즘 비교 및 활용

대표적인 패딩 방식들의 원리를 살펴보았으므로, 이제 각 방식별로 어떤 상황에 적합하고 어떤 장단점이 있는지 비교해보겠습니다. 아래는 각 패딩 방식의 권장 활용 분야와 장단점을 정리한 내용입니다:

  • PKCS#7 패딩
    • 적합한 상황: 범용적으로 가장 많이 사용되는 패딩으로, 특별한 요구 사항이 없다면 기본 선택지로 적합합니다. 다양한 프로그래밍 언어나 암호화 라이브러리에서 기본 제공되며, 과거 TLS 등 여러 프로토콜에서도 채택되었을 만큼 폭넓게 활용됩니다
    • 장점: 표준으로 명확히 정의되어 있어 상호운용성이 높고 구현이 쉬우며, 패딩 길이 정보가 명시적으로 포함되어 있어 복호화 시 처리도 간단합니다. 또한 모든 패딩 바이트가 동일한 값이므로, 패딩 무결성 검증시 한 번에 검사가 가능하여 오류를 쉽게 잡아낼 수 있습니다.
    • 단점: 평문이 블록 경계에 딱 맞을 경우에도 전체 블록을 추가로 패딩해야 하므로 데이터 길이가 늘어나는 오버헤드가 있습니다. 예컨대 16바이트 단위 AES에서 16바이트짜리 평문 하나를 암호화하면 16바이트를 더 패딩으로 붙여 총 32바이트 암호문이 됩니다. 하지만 이러한 단점은 ANSI X.923 등의 다른 표준 패딩도 동일하며, 패딩 자체로 인한 성능 부담은 일반적으로 미미한 편입니다.
  • ANSI X.923 패딩
    • 적합한 상황: 과거 금융권 등 특정 표준을 준수해야 하는 시스템에서 주로 사용되었습니다. 현재는 PKCS#7로 대체되는 추세지만, 기존 VB6/ASP.NET 등 일부 구현이 ANSI X.923을 기본 사용하는 경우가 있어 이들과의 호환이 필요할 때 선택합니다.
    • 장점: PKCS#7과 마찬가지로 명시적인 패딩 길이 정보를 포함하여 확실한 패딩 제거가 가능합니다. 모든 패딩 바이트를 0으로 채우므로 필요시 평문을 패딩 전후로 시각적으로 구분하기가 다소 수월할 수 있으며 (패딩 영역이 모두 00으로 보임), 임의의 값으로 패딩을 채울 유연성도 있습니다. 또한 PKCS#7로 패딩된 암호문을 X.923 패딩으로 간주하고 해제하거나 그 반대의 처리도 이론적으로는 가능할 정도로 유사합니다.
    • 단점: PKCS#7 대비 특별한 우위점이 거의 없어 현대의 암호 표준에서 잘 쓰이지 않는 방식입니다. 패딩 바이트 중 마지막 한 바이트만 유의미하고 나머지는 모두 0이어서, 만약 패딩 영역에서 단일 바이트 오류가 발생해도 (예: 0이 아닌 값으로 변조돼도) 패딩 길이만 맞으면 검출이 어려울 수 있다는 지적이 있습니다. 실제 구현에서는 패딩 바이트 전체에 대한 무결성 검사를 수행하므로 이러한 차이는 크지 않지만, 패딩 오라클 공격 등 취약성 관점에서 PKCS#7에 비해 더 안전하다고 볼 근거는 없습니다.
  • ISO/IEC 7816-4 패딩
    • 적합한 상황: 스마트카드 응용이나 특정 임베디드 시스템에서 주로 사용됩니다. 또한 비트 단위의 메시지 길이를 처리해야 할 때 (예를 들어, 마지막에 1 비트만 세우고 남은 비트를 패딩하는 경우) 이 방식을 일반화하여 쓸 수 있습니다. 일반 소프트웨어 환경에서는 드물지만, 암호 라이브러리에서 옵션으로 제공되는 경우가 있어 특수한 프로토콜 구현에 사용되기도 합니다.
    • 장점: 패딩에 고정된 구분 마커(0x80)를 사용하므로 패딩의 시작 지점을 뚜렷이 표시할 수 있으며, 패딩 길이와 무관하게 일정한 패턴을 가집니다. 0x80 한 바이트만 찾으면 패딩 전체를 식별할 수 있기 때문에, 블록 경계가 아닌 임의의 길이(비트 단위)에도 확장할 수 있는 융통성이 있습니다 . 또한 패딩 영역이 모두 0x80 또는 0으로 구성되어 있어, 패딩 데이터가 암호문에 미치는 영향이 상대적으로 단순합니다.
    • 단점: 패딩을 제거하려면 역순으로 바이트를 검사해야 하며 (특히 여러 블록에 걸쳐 패딩이 존재할 경우 조금 더 복잡해짐) 최악의 경우 평문의 처음까지 확인해야 하는 오버헤드가 있습니다. 하지만 블록 크기가 크지 않으므로 이 성능 영향은 미소합니다. 또한 다른 표준에 비해 대중적인 구현체가 적어 호환성 측면에서 덜 보편적입니다. 패딩의 특정 바이트 값(0x80) 의존 특성상, 평문에 0x80이 많이 등장하는 경우 패딩 부분과 혼동될 여지가 있지 않냐는 의문이 있을 수 있으나, 규칙상 평문 끝에 바로 패딩 마커를 붙이도록 정의되어 있어 실제 혼동이 발생하지는 않습니다.
  • 제로 패딩
    • 적합한 상황: 평문의 실제 길이를 별도로 관리하는 프로토콜이나, 평문이 문자열 데이터로 마지막에 0x00 문자가 올 수 없다고 보장되는 경우에 한해 사용이 권장됩니다. 예를 들어 네트워크 프로토콜에서 암호화 전에 평문의 길이를 따로 전송하거나, 암호화 파일 포맷에서 원본 데이터 크기를 별도 메타데이터로 저장하는 경우 등이 이에 해당합니다. 이 밖에 C언어 스타일의 널 종단 문자열(null-terminated string)을 암호화할 때 문자열 끝의 '\0'들을 패딩으로 활용하는 용도로 쓰이기도 합니다 
    • 장점: 가장 구현이 단순하며, 추가적인 정보 없이도 직관적으로 패딩을 채울 수 있기 때문에 오류 가능성이 적은 편입니다. 또한 패딩 바이트가 모두 0x00이므로 사람이 확인하기에도 분명하고, 특정 상황에서는 패딩 제거 연산을 생략하고도 자연스럽게 평문을 얻을 수 있습니다 (예: null-terminated 문자열을 복호화한 경우, 문자열 연산에서 '\0' 이후를 읽지 않으므로 패딩을 자동 무시하게 됨).
    • 단점: 패딩과 평문을 구분할 명확한 방법이 없기 때문에 위험합니다. 별도의 평문 길이 정보가 없으면, 복호화 결과의 뒤쪽에 있는 0x00들이 원래 평문에 포함된 값인지 패딩인지 판단할 수 없습니다. 이러한 모호성 때문에 일반 암호 프로토콜에는 잘 사용되지 않으며, 표준화된 규격도 존재하지 않습니다. 잘못 사용할 경우 데이터 일부가 손실되거나 불필요한 바이트가 덧붙는 부작용이 발생할 수 있습니다.
  • ISO 10126 패딩 (참고)
    • 적합한 상황: 현재는 권고되지 않는 구식 방식으로, 특별한 이유가 없다면 사용되지 않습니다. 과거에 임의 바이트로 채워서 분석을 어렵게 하려는 의도로 고안되었으나, 현대에는 임의의 IV나 AEAD 알고리즘으로 동일한 효과를 얻기 때문에 의미가 줄어들었습니다.
    • 장점: 패딩 바이트들을 랜덤한 값들로 채우므로 암호문만 보았을 때 패딩 부분에 규칙성이 거의 없습니다. 이론적으로 동일한 평문이라도 암호화를 할 때마다 패딩이 달라질 수 있어, 마지막 블록의 암호문이 매번 바뀌는 효과를 냅니다.
    • 단점: ANSI X.923과 마찬가지로 마지막 한 바이트 외에는 패딩 데이터로서 별 의미가 없고, 그 값들이 랜덤이므로 복호화 시 검증이 사실상 불가능합니다. 즉 패딩 길이만 맞으면 어떤 값이든 받아들이게 되므로, 오류 탐지가 어렵고 보안적으로 이점이 없습니다. ISO 10126 표준 자체도 2007년에 폐지되었으며 , 현재 주요 라이브러리에서는 지원하지 않는 경우가 많습니다.

보안적 고려사항 (패딩 오라클 공격)

패딩 적용 시에는 **패딩 오라클 공격(padding oracle attack)**에 대한 대비가 필요합니다. 패딩 오라클 공격이란, 암호화된 데이터의 패딩 유효성 여부가 외부에 누설되는 취약점을 이용하여 공격자가 암호문의 일부를 평문으로 해독하거나 임의의 평문을 암호화해내는 기법입니다. 예를 들어 서버 측에서 암호문을 복호화한 뒤 패딩이 올바르지 않으면 에러 메시지를 보내주거나 다른 응답을 보인다면, 공격자는 이를 이용해 평문의 바이트를 하나씩 역추론하거나 잘못된 패딩을 이용해 암호문을 조작할 수 있습니다. 2002년 Serge Vaudenay의 논문으로 CBC 모드에서의 패딩 오라클 공격이 처음 널리 알려졌으며, 이후 웹 애플리케이션 등 다양한 환경에서 실습적으로 이러한 공격이 구현되었습니다.

패딩 오라클 공격은 패딩 방식 자체의 문제라기보다는 구현상의 정보 노출 문제입니다. PKCS#7, ANSI X.923, ISO 7816-4 등 어떤 패딩을 쓰든지, 복호화 과정에서 “패딩이 유효한지” 여부를 공격자가 알아챌 수 있다면 모두 공격에 노출될 수 있습니다. 패딩의 구조적인 차이가 공격 난이도에 약간 영향을 줄 수는 있지만 근본적인 해결책이 되지는 않습니다. 따라서 다음과 같은 대응책을 적용하는 것이 중요합니다:

  • 패딩 오류 정보를 숨기기: 복호화 후 패딩 오류가 발생하더라도 공격자에게 동일한 형태의 응답을 돌려주고, 패딩 오류와 다른 오류를 구별할 수 없게 만듭니다. 예를 들어 패딩이 잘못되어도 그냥 일반적인 “해독 실패” 오류를 내고 추가 정보를 주지 않거나, 오류가 발생한 경우 시간을 일부러 지연시키는 등의 방법으로 공격자가 판단하기 어렵게 합니다.
  • 무결성 검증 (MAC 또는 인증): **메시지 인증 코드(MAC)**나 전자서명 등을 활용하여 평문 패딩까지 포함한 무결성을 검증한 후에만 평문을 처리합니다. 일반적으로는 암호문에 대한 HMAC을 함께 전송하여 복호화 전에 검증하거나, 최신 프로토콜에서는 인증된 암호화(AEAD) 모드를 사용하여 암복호화 시 자동으로 무결성을 확인합니다. 이를 통해 패딩이 잘못된 경우에도 애초에 MAC 검증에서 걸러지므로 패딩 오류 여부가 외부에 드러나지 않게 됩니다.
  • 패딩 대신 스트림 모드 사용 고려: 기술적으로는 패딩을 사용하지 않도록 암호 운용 방식을 선택하는 것도 방법입니다. 예를 들어 CTR이나 CFB와 같은 스트림 모드로 블록 암호를 운영하면 별도의 패딩 없이도 임의 길이의 데이터를 처리할 수 있습니다. 다만 이러한 변경은 시스템 전반의 구조를 바꾸는 것이므로 기존 프로토콜을 유지하면서는 어렵고, 가능하다면 GCM과 같은 AEAD 모드로 교체하는 것이 근본적인 해결책이 될 수 있습니다.

요약하면, 패딩 알고리즘을 선택할 때에는 용도와 환경에 따라 적절한 방식을 고르고, 구현 시에는 패딩으로 인한 보안 취약점이 발생하지 않도록 주의해야 합니다. 대부분의 현대적인 시스템에서는 PKCS#7 패딩을 기본으로 사용하며, 동시에 패딩 오라클 공격을 막기 위한 무결성 체크나 인증된 암호화를 적용하는 것이 일반적입니다. 패딩 자체는 블록 암호를 유연하게 사용하기 위한 필수 요소이므로, 그 원리와 각 방식의 특성을 이해하고 안전하게 활용하는 것이 중요합니다.

728x90

+ Recent posts