현대 암호학

[현대 암호학] 05. 실습(1)

Uggjjini 2021. 6. 23. 16:19

[실습] 3DES(TDES)-CBC 사용하여 메시지를 암복호화 하는 프로그램 개발

사용시스템

kali

 

3DES(TDES, DES-3, DES3)사용하는 메세지를 암호화 또는 복호화 하는 프로그램 제작

프로그램 제작시 다음과 같은 사항에 대해서 참고하여야 한다.

 

3DES(Triple DES)

  • 입력 : 8 bytes (64 bits) 평문 입력
  • 출력 : 8 bytes (64 bits) 암호문 출력
  • 블록 단위 : 8 bytes (64 bits)
  • 키 길이 : 24bytes (K1(8) + K2(8) + K3(8))[참고] 3DES-EDE2, 3DES-EDE3

 

Block Cipher Mode : CBC

  • IV : 8 bytes(64 bits)의 iv 필요
  • Padding : 패딩(padding)에 대한 처리(암호화: pad, 복호화: unpad)

 

PyCryptodome 패키지에서 byte string(EX: b'hello world') 사용해야 한다.

  • plaintext, keytext, ivtext는 encode('utf-8') 필요

 

DES3FromMsg.py

###!/usr/bin/python3
# DES3-CBC
#
# 1) DES3-EDE3
# * input  : 8 bytes
# * key    : 24 bytes(k1,k2,k3)
# * output : 8 bytes
# 2) Block Cipher : CBC Mode
# * IV     : 8 bytes
# * padding

from Crypto.Cipher import DES3
from Crypto.Hash import SHA256 as SHA

def main():
    # 1) Encryption Side
    plaintext = 'We are no longer the knights who say ni!'
    keytext = 'samsjang'
    ivtext = '123456789'

    msg = plaintext.encode()

    hash = SHA.new()
    hash.update(keytext.encode())
    key = hash.digest()
    key = key[:24]

    hash.update(ivtext.encode())
    iv = hash.digest()
    iv = iv[:8]

    cipher = DES3.new(key, DES3.MODE_CBC, iv)
    encmsg = cipher.encrypt(msg)
    print("Plaintext : ", plaintext)
    print("Encrypted : ", encmsg)

    send_msg = encmsg
    send_key = key
    send_iv = iv

    # 2) Decryption Side
    recv_msg = send_msg
    recv_key = send_key
    recv_iv = send_iv

    cipher2 = DES3.new(recv_key, DES3.MODE_CBC, recv_iv)
    decmsg = cipher2.decrypt(recv_msg)
    print('Decrypted : ', decmsg)


if __name__ == '__main__':
    main()

 

Plaintext :  We are no longer the knights who say ni!
Encrypted :  b'\xf9G\x9a\x8d\xf3m~NX)kg\xb5\x8c\x93\xff\t\xec \x95\x0eW\xb6\xc9!\xa6N\x14\xa2\xb7\x11\x060\xca\xd5>\x13\xb1\x11\x9b'
Decrypted :  b'We are no longer the knights who say ni!'

 

 

DES3FromMsg2.py

 

DES3From.py 파일을 class 로 변경하여 제작해 보자.

# DES3-CBC
#
# 1) DES3-EDE3
# * input  : 8 bytes
# * key    : 24 bytes(k1,k2,k3)
# * output : 8 bytes
# 2) Block Cipher : CBC Mode
# * IV     : 8 bytes
# * padding

from Crypto.Cipher import DES3
from Crypto.Hash import SHA256 as SHA

class MyDES():

    def __init__(self, keytext, ivtext):
        myhash = SHA.new()

        myhash.update(keytext.encode())
        self.key = myhash.digest()
        self.key = self.key[:24]

        myhash.update(ivtext.encode())
        self.iv = myhash.digest()
        self.iv = self.iv[:8]

    def enc(self, msg):
        des3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)

        return des3.encrypt(msg.encode())

    def dec(self, msg):
        dec3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)

        return dec3.decrypt(msg)


def main():
    message = 'We are no longer the knights who say ni!'
    keytext = 'samsjang'
    ivtext = '1234'

    mycipher = MyDES(keytext, ivtext)
    encrypted = mycipher.enc(message)
    decrypted = mycipher.dec(encrypted)

    print("Plaintext : ", message)
    print("Encrypted : ", encrypted)
    print("Decrypted : ", decrypted.decode())



if __name__ == '__main__':
    main()

 

Plaintext  : We are no longer the knights who say ni!
Encypted  : b'\xf9G\x9a\x8d\xf3m~NX)kg\xb5\x8c\x93\xff\t\xec \x95\x0eW\xb6\xc9!\xa6N\x14\xa2\xb7\x11\x060\xca\xd5>\x13\xb1\x11\x9b'
Decrypted : We are no longer the knights who say ni!

 

 

기능 추가(!!!! Padding 처리 문제 !!!!)

message8바이트 단위가 아니면(: message='abcde') 다음과 같은 에러가 발생된다.

ValueError: Data must be padded to 8 byte boundary in CBC mode

패딩 처리가 되어 있지 않기 때문이다.

따라서, 8바이트 단위로 만들기 위해서 다음과 같은 함수를 선언한다.

 

def make8string(msg):         # msg = 'abcde'
    msglen = len(msg)          # msglen = 5
    filler = ''
    if msglen % 8 != 0:
        filler = '0' * (8 - msglen % 8)
    msg += filler

    return msg

 

그리고, 다음 파일의 내용을 조금 수정한다.

 

DES3FromMsg2.py

# DES3-CBC
#
# 1) DES3-EDE3
# * input  : 8 bytes
# * key    : 24 bytes(k1,k2,k3)
# * output : 8 bytes
# 2) Block Cipher : CBC Mode
# * IV     : 8 bytes
# * padding

from Crypto.Cipher import DES3
from Crypto.Hash import SHA256 as SHA

class MyDES():

    def __init__(self, keytext, ivtext):
        myhash = SHA.new()

        myhash.update(keytext.encode())
        self.key = myhash.digest()
        self.key = self.key[:24]

        myhash.update(ivtext.encode())
        self.iv = myhash.digest()
        self.iv = self.iv[:8]

    def enc(self, msg):
        msg = make8string(msg)
        des3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)

        return des3.encrypt(msg.encode())

    def dec(self, msg):
        dec3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)

        return dec3.decrypt(msg)


def make8string(msg):
    msglen = len(msg)
    filler = ''
    if msglen % 8 != 0:
        filler = '0' * (8 - msglen % 8)
    msg += filler

    return msg

def main():
    # message = 'We are no longer the knights who say ni!'
    message = 'abcde'
    keytext = 'samsjang'
    ivtext = '1234'

    mycipher = MyDES(keytext, ivtext)
    encrypted = mycipher.enc(message)
    decrypted = mycipher.dec(encrypted)

    print("Plaintext : ", message)
    print("Encrypted : ", encrypted)
    print("Decrypted : ", decrypted.decode())



if __name__ == '__main__':
    main()

 

Plaintext   :  abcde
Encrypted :  b'ut\xe6b\xb4q\xc4-'
Decrypted :  abcde000

 

 

 

 

직접 pad, unpad 처리하기

 

(pad 처리 부분)

msg8 bytes 단위로 만들어서(pad 처리) MyDES.enc() Method에 넣고, MyDES.enc() Method의 출력은 암호문과 filler 개수를 return 한다.

  • msg -> msg += fillter -> MyDES.enc(msg.encode())
  • encmsg, fillternum = myDES.enc(msg.encode())

 

(unpad 처리 부분)

encmsg, fillernumMyDES.dec() Method의 인자값으로 사용해서 decmsg 생성할 때, encmsg를 복호화한 decmsgfillernum 개수만큼을 제거하는 작업을 한다.

  • decmsg = myDES.dec(encmsg, fillternum)
  • encmsg, fillernum -> decmsg -> decmsg[-fillernum]

 

# DES3-CBC
#
# 1) DES3-EDE3
# * input  : 8 bytes
# * key    : 24 bytes(k1,k2,k3)
# * output : 8 bytes
# 2) Block Cipher : CBC Mode
# * IV     : 8 bytes
# * padding

from Crypto.Cipher import DES3
from Crypto.Hash import SHA256 as SHA

class MyDES():

    def __init__(self, keytext, ivtext):
        myhash = SHA.new()

        myhash.update(keytext.encode())
        self.key = myhash.digest()
        self.key = self.key[:24]

        myhash.update(ivtext.encode())
        self.iv = myhash.digest()
        self.iv = self.iv[:8]

    def enc(self, msg):
        msg, fillernum = make8string(msg)
        des3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)

        return des3.encrypt(msg.encode()), fillernum

    def dec(self, msg, fillernum):
        dec3 = DES3.new(self.key, DES3.MODE_CBC, self.iv)
        decmsg = dec3.decrypt(msg)
        decmsg = decmsg.decode()

        if fillernum != 0:
            decmsg = decmsg[:-fillernum]

        return  decmsg

def make8string(msg):
    msglen = len(msg)
    filler = ''
    if msglen % 8 != 0:
        filler = '0' * (8 - msglen % 8)

    fillernum = len(filler)
    msg += filler

    return msg, fillernum

def main():
    # message = 'We are no longer the knights who say ni!'
    message = 'abcde'
    keytext = 'samsjang'
    ivtext = '1234'

    mycipher = MyDES(keytext, ivtext)
    encrypted, fillernum = mycipher.enc(message)
    decrypted = mycipher.dec(encrypted, fillernum)

    print("Plaintext : ", message)
    print("Encrypted : ", encrypted)
    print("Decrypted : ", decrypted)



if __name__ == '__main__':
    main()

 

Plaintext :  abcde
Encrypted :  b'ut\xe6b\xb4q\xc4-'
Decrypted :  abcde

 

 

 

DES3FromMsg_CBC.py

 

다음 사항을 수정하였다.

 

key, iv 값을 Crypto.Random 모듈 사용

  • from Crypto.Random import get_random_bytes
  • key = get_random_bytes(24)
  • iv = get_random_bytes(8)

 

직접 패딩 처리를 하지 않고 Crypto.Util.Padding 모듈 사용

  • from Crypto.Util.Padding import pad, unpad
  • c = AES.new(key, AES.MODE_CBC, iv)
  • ct = c.encrypt(pad(data, 8))
  • pt = unpad(c2.decrypt(ct), 8)

 

# DES3-CBC
#
# 1) DES3-EDE3
# * input  : 8 bytes
# * key    : 24 bytes(k1,k2,k3)
# * output : 8 bytes
# 2) Block Cipher : CBC Mode
# * IV     : 8 bytes
# * padding

from Crypto.Cipher import DES3
from Crypto.Random import get_random_bytes
from Crypto.Util.Padding import pad, unpad

mymsg = b'hello world'
key = get_random_bytes(24)
iv = get_random_bytes(8)

cipher = DES3.new(key, DES3.MODE_CBC, iv)
encrypted = cipher.encrypt(pad(mymsg, 8))

cipher2 = DES3.new(key, DES3.MODE_CBC, iv)
decrypted = unpad(cipher2.decrypt(encrypted), 8)

print("Plaintext : ", mymsg.decode())
print("Encrypted : ", encrypted)
print("Decrypted : ", decrypted.decode())

 

Plaintext :  hello world
Encrypted :  b'`\xd3\xdb\xb8\xd4\x1d\x15\xdc\xd8\xb5V\x9f@\xf7\x81G'
Decrypted :  hello world

'현대 암호학' 카테고리의 다른 글

[현대 암호학] 05. 실습(3)  (0) 2021.06.24
[현대 암호학] 05. 실습(2)  (0) 2021.06.23
[현대 암호학] 05-5. CTR 모드  (0) 2021.06.23
[현대 암호학] 05-4. CFB 모드  (0) 2021.06.23
[현대 암호학] 05-3. CBC 모드  (0) 2021.06.23