암호학 강의

[암호학] 운용모드(운영모드) Modes of Operation

crypsec 2023. 11. 5. 22:08
반응형

Modes of Operation은 우리말로 운영모드 또는 운용모드라고도 합니다. 저는 운용모드라고 하겠습니다.

 

블록암호는 n-bit 평문을 암호화합니다. AES경우 128-bit 블록암호이기 때문에 128-bit를 넘어가는 평문은 128-bit 단위로 나누어 암호화해야 합니다. 만약 평문이 192-bit라면 128-bit 한 블록으로 나누어 암호화하고 나머지 64-bit 평문에는 패딩(Padding)이라는 작업을 해주어 128-bit 크기로 만든 후 암호화를 진행합니다.

 

즉, 패딩(padding)이란 블록암호 알고리즘에서 블록의 크기를 일정하게 맞추기 위해 일정한 법칙에 따라 블록에 모자란 크기만큼 값을 채워주는 것을 의미합니다. 대표적으로 PKCS#7이라는 패딩 방법이 있습니다.

 

그렇다면 운용모드는 왜 사용하는 것일까요?

 

여러 이유가 있지만 대표적으로 운영모드를 사용하면 동일한 평문 블록이라도 다른 암호문이 생성됩니다. 이는 데이터 중복이나 패턴을 감추는 데 도움이 됩니다.


ECB 모드 (Electronic CodeBook)

학생들에게 "매우 긴 평문을 어떻게 암호화 시킬래?" 라고 질문하면 일반적으로 하는 답변이 바로 ECB 모드입니다.

 

ECB는 평문을 미리 정의된 크기의 블록으로 나누고, 각 블록을 개별적으로 암호화합니다. 일반적으로 블록 크기는 64비트(8바이트) 또는 128비트(16바이트)가 사용됩니다.

 

block cipher에는 AES, LEA 등의 블록암호가 들어갈 수 있습니다.

 

동일한 평문 블록은 항상 동일한 암호문 블록을 생성됩니다. 같은 평문 블록이 들어가면 항상 동일한 암호문 블록이 나옵니다. 이로 인해 평문 패턴이 반복되면 암호문에서도 패턴이 드러날 수 있습니다.

 

ECB는 각 블록을 독립적으로 암호화합니다. 이것은 암호화된 블록 간에 상호작용이 없다는 의미입니다. 이로 인해 블록 간에 관계가 없는 데이터의 경우에는 사용하기 적절할 수 있습니다.

 

평문 블록이 패턴이나 구조를 가지고 있다면, 암호문에서도 같은 패턴이 나타날 수 있습니다. 이로 인해 ECB는 패턴이 드러날 가능성이 높습니다.

 

각 블록이 독립적으로 암호화되기 때문에 여러 블록을 동시에 암호화할 수 있습니다. 즉, 병렬 처리가 가능합니다. 이는 하드웨어에서의 성능을 향상하는 데 사용될 수 있습니다.

 

암호문의 1비트 오류는 복호화 연산에서 해당 블록에만 영향을 미칩니다. 즉, 오류의 전파가 없습니다.

ECB는 블록의 순서 변경, 추가, 삭제가 가능합니다. 만약 암호문이 변경된다면 복호화된 평문도 오류가 생깁니다. 즉, 메시지가 변조될 수 있습니다. 따라서 데이터의 무결성을 보장하지 않습니다.

 

ECB는 특정 상황에서 사용될 수 있지만, 보안적인 측면에서는 안전하지 않은 암호화 방식으로 간주됩니다. 보다 안전한 대안으로 CBC (Cipher Block Chaining)나 GCM (Galois/Counter Mode) 등의 암호화 모드가 사용됩니다.

 

CBC에 대해 설명하기 전에 ECB의 특징을 직접 코드로 보겠습니다.

 

 

더보기

아래 Python 코드는 example.bmp 파일을 불러와 AES 블록암호를 이용하여 ECB, CBC 각각으로 암호화하는 코드입니다. 기본적으로 픽셀은 빛의 삼원소 red, green, blue로 이루어지는데 이 데이터들을 암호화하고 암호화된 결과를 이미지로 볼 수 있도록 코드를 구성한 것입니다.

 

다음 두 파이썬 라이브러리 설치가 필요합니다.

$ pip install pycryptodome
$ pip install image
from Crypto.Cipher import AES
from PIL import Image
import binascii, os, random, struct

def get_pixels(data):
    r, g, b = tuple(map(lambda d: [data[i] for i in range(0,len(data)) if i % 3 == d], [0, 1, 2]))
    pixels = tuple(zip(r,g,b))
    return pixels

def encrypt_image_file(secret_key, encryption_mode, initialization_vector, input_file, output_file = None):
    image = Image.open(input_file)
    data = image.convert("RGB").tobytes()
    original_length = len(data)
    pad_length = 16 - len(data) % 16
    pad = pad_length.to_bytes(1, byteorder='big', signed = False) * pad_length
    data += pad
    encryptor = AES.new(secret_key, encryption_mode)
    encrypted_data = get_pixels(encryptor.encrypt(data)[:original_length])
    new_image = Image.new(image.mode, image.size)
    new_image.putdata(encrypted_data)
    new_image.save(output_file)
    print ("{} is encrypted.".format(input_file))

secret_key = bytes.fromhex("1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d")
initialization_vector = bytes.fromhex("1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d")

encryption_mode = AES.MODE_ECB
input_filename = "example.bmp"
output_filename = "example.ecb.bmp"
encrypt_image_file(secret_key, encryption_mode, initialization_vector, input_filename, output_filename)

encryption_mode = AES.MODE_CBC
output_filename = "example.cbc.bmp"
encrypt_image_file(secret_key, encryption_mode, initialization_vector, input_filename, output_filename)

 

 

운용모드에 따른 암호화 결과

원본, ECB, CBC


CBC 모드 (Cipher Block Chaining)

IV (Initialization Vector)라는 개념이 나오는데 이는 랜덤값으로 엄밀히 따지면 비밀값은 아닙니다.

IV는 블록 암호화에서 각 블록에 대한 초기 상태를 설정하는 역할을 합니다. 이를 통해 동일한 평문이라도 IV가 다르면 다른 암호문이 생성되므로, 암호문의 예측이 어려워집니다.

 

CBC (Cipher Block Chaining) 모드에서는 이전 블록의 암호문을 현재 블록의 일부로 사용하여 각 블록을 암호화합니다. 이때 IV는 첫 번째 블록의 암호화에 사용되며, 이후 각 블록은 이전 블록의 암호문과 XOR 연산을 수행한 후에 암호화됩니다. 이를 통해 각 블록이 서로 영향을 미치게 되어 동일한 평문 블록이라도 암호문이 다르게 생성됩니다.
따라서 블록의 순서 변경, 추가, 삭제가 불가능합니다.


CFB 모드 (Ciphertext FeedBack)

CFB (Cipher Feedback) 모드는 블록 암호를 스트림 암호처럼 사용하는 모드 중 하나입니다. 이러한 특성 때문에 CFB 모드는 암호화된 메시지의 일부분을 복호화하기 위해 전체 메시지를 기다릴 필요가 없습니다.

 

CFB 모드에서는 암호화된 블록과 평문 블록의 XOR 연산 결과가 됩니다.

 

CFB 모드의 동작은 다음과 같습니다.

  • IV가 암호화 알고리즘에 입력되어 첫 번째 암호화된 블록이 생성됩니다.
  • 암호화된 블록과 평문 블록을 XOR 연산하여 암호문을 생성합니다. 이때 암호문을 하나 복사합니다.
  • 복사한 암호문을 다시 암호화하고 다음 평문 블록에 XOR연산하여 암호문을 생성합니다.

이러한 과정을 반복하여 전체 메시지를 암호화합니다.


OFB 모드 (Output FeedBack)

OFB 모드는 CFB 모드와 유사합니다. 따라서 동작 그림과 차이점만 알고 가시면 좋을 것 같습니다.

 

  • CFB 모드는 이전 블록의 암호문과 XOR 연산을 수행하기 때문에, 한 블록이 오류가 있더라도 그 이후 블록들에는 영향을 미치지 않습니다.
  • OFB 모드는 연속된 암호문 블록을 생성하기 때문에, 한 블록이 오류가 있으면 그 이후 블록들도 영향을 받습니다.
  • CFB 모드는 이전 암호문이 현재 블록의 암호화에 사용되므로, 동일한 IV와 동일한 평문 블록은 동일한 암호문을 생성합니다.
  • OFB 모드는 이전 암호문이 계속해서 사용되지만, 암호문과 평문의 XOR 연산으로 생성되기 때문에 동일한 IV와 동일한 평문 블록이라도 항상 다른 암호문을 생성합니다.

요약하면, CFB 모드는 암호문 블록을 계속해서 사용하여 스트림을 생성하고, OFB 모드는 연속된 암호문 블록을 생성하여 스트림을 생성합니다. 이로 인해 OFB 모드가 한 블록에 대한 에러를 전파시키지 않고, 실시간 통신에도 적합하다는 장점이 있습니다.


CTR 모드 (CounTeR)

CTR (Counter) 모드는 블록 암호를 사용하여 스트림 암호를 구현하는 암호화 모드 중 하나입니다. CTR 모드는 다음과 같은 특징을 가집니다.

  1. CTR의 역할
    • CTR(counter)는 0부터 시작합니다. 이후 블록에서는 "(이전 블록의 CTR값 + 1)의 n-bit "를 CTR 값으로 사용합니다.
  2. 암호화 순서
    • 카운터 값과 nonce를 조합하여 값을 생성합니다. Nonce는 한 번만 사용되는 값으로, 같은 CTR 값을 사용해도 다른 nonce를 사용하면 다른 값이 생성됩니다. 암호문에 입력할 값이 16 바이트라면 앞의 8바이트는 nonce로 뒤의 8바이트는 CTR값으로 생성합니다. 
  3. 동일한 평문 블록에 대한 암호문의 예측 불가능성
    • 동일한 평문 블록을 여러 번 암호화해도, 각각 다른 카운터 값이 사용되므로 예측이 불가능합니다.
  4. 병렬화 가능
    • CTR 모드는 병렬화가 가능하여, 여러 블록을 동시에 암호화할 수 있습니다. 이는 높은 처리량과 속도를 제공하는 장점을 가지고 있습니다. 실시간 통신에서 유리합니다.
  5. 인크리멘탈 암호화
    • CTR 모드는 암호문의 한 부분만 변경하려고 할 때, 해당 부분만 다시 암호화할 수 있는 장점이 있습니다. 이를 인크리멘탈 암호화라고 합니다.

요약하면, CTR 모드는 블록 암호를 사용하여 스트림 암호를 구현하며, CTR과 nonce를 사용하여 각 블록에 대한 카운터 값을 생성합니다. 이를 통해 각 블록이 독립적으로 암호화되며, 예측이 어려워집니다.

 

이 외에도 여러 모드가 있으며 가장 대표적인 5가지 운용모드를 살펴보았습니다. 각 운용모드의 영문 풀네임이 왜 이렇게 붙은 것인지 생각해 보면 단순하게 동작과정과 일치하기 때문입니다.

 

질문은 공개 댓글로 남겨주세요.

반응형