[목차]

 

 

1. 3DES 메시지 암복호화 프로그램

* pad 함수 추가 코딩

* pad / unpad 함수 추가 코딩

* pad/unpad 모듈 끌어와 사용

 

 

2. AES

* AES-CBC 암복호화 프로그램

* AES-CTR 암복호화 프로그램

* AES-EAX 암복호화 프로그램

 

 

 

 

 

 


 

 

 

[3DES 메시지 암복호화 프로그램]

 

 

 

어제에 이어 동일한

3DES(TDES, DES-3, DES3) 사용하는 메세지를

암호화 또는 복호화 하는 프로그램 제작

 

 

 

* 참조

1) 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

 

2) Block Cipher Mode : CBC

IV : 8 bytes(64 bits)의 iv 필요

Padding : 패딩(padding)에 대한 처리(암호화: pad, 복호화: unpad)

 

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

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

 

 

 

* 어제와 다른점

어제는 메세지의 데이터를 8바이트에 맞춰 설정을 했지만

만약 메세지의 데이터 값이 8바이트 단위가 아니면

오류가 난다. 그때는 CBC 특성상 패딩처리를 해줘야하는데

직접 pad, unpad 처리하는 함수를 만들어 본다.

 

 

 

1. pad 함수 추가 코딩

 DES3FromMsg2.py

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


class MyDES():   

    def __init__(self, key, iv):
        myhash = SHA.new()

        myhash.update(key.encode())
        tkey = myhash.digest()
        self.key = tkey[:24] # self = 전역변수로 사용됨. key '' 이렇게 클래스 바로 밑에 정의해 둬도 됨

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

        #self.en_msg = msg.encode() 아래 msg를 따로 만들자


    def enc(self, msg):
        #print("==> ", msg)
        msg = self.make8string(msg)
        #print("==> ", msg) ; input()
        des3 = DES.new(self.key, DES.MODE_CBC, self.iv)
        encmsg = des3.encrypt(msg.encode()) # 암호화 하는 자리

        return encmsg


    def dec(self, msg):
        des3 = DES.new(self.key, DES.MODE_CBC, self.iv)
        decmsg = des3.decrypt(msg)
        #decmsg = decmsg.decode()
        return decmsg.decode()


    def make8string(self, msg):
        msglen = len(msg)
        fillter = ''
        if msglen % 8 != 0:
            fillter = 'O' * (8 - msglen % 8)
        msg += fillter

        return msg

def main():
    # mymsg = 'We are no longer the knights who say ni!'
    mymsg = 'abcde'
    mykey = 'samsjang'
    myiv = '1234'

    mycipher = MyDES(mykey, myiv)
    encrypted = mycipher.enc(mymsg)
    print('Plaintext  :', mymsg)
    print('Encrypted  :', encrypted)

    decrypted = mycipher.dec(encrypted)
    print('Decrypted  :', decrypted)
    print("==> ") ; input()

if __name__ == '__main__':
    main()

 

 

 

 

2. pad + unpad 함수 추가 코딩

 DES3FromMsg2.py

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


class MyDES():    #상속받는게 없으니 괄호 빼도됨

    def __init__(self, key, iv):
        myhash = SHA.new()

        myhash.update(key.encode())
        tkey = myhash.digest()
        self.key = tkey[:24] # self = 전역변수로 사용됨. key '' 이렇게 클래스 바로 밑에 정의해 둬도 됨

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

        #self.en_msg = msg.encode() 아래 msg를 따로 만들자

    def enc(self, msg):
        #print("==> ", msg)
        msg, fillernum = self.make8string(msg)
        #print("==> ", msg) ; input()
        des3 = DES.new(self.key, DES.MODE_CBC, self.iv)
        encmsg = des3.encrypt(msg.encode()) # 암호화 하는 자리

        return encmsg, fillernum

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

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

        return decmsg


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

        fillernum = len(filler)
        msg += filler

        return msg, fillernum

def main():
    # mymsg = 'We are no longer the knights who say ni!'
    mymsg = 'abcdefhij'
    mykey = 'samsjang'
    myiv = '1234'

    mycipher = MyDES(mykey, myiv)
    encrypted, fillter_num = mycipher.enc(mymsg)
    print('Plaintext  :', mymsg)
    print('Encrypted  :', encrypted)

    decrypted = mycipher.dec(encrypted, fillter_num)
    print('Decrypted  :', decrypted)


if __name__ == '__main__':
    main()

 

 

 

 

 

3. pad, unpad 모듈을 끌어와 쓰는 경우 (가장 편하고 쉬움)

DES3FromMsg_CBC.py

# 1) Choose Cipher : DES3 (triple DES) - EDE3(encrypt,decrypt,encrypt)
#   * plaintext : 8 bytes
#   * cihertext : 8 bytes
#   * key       : 8 bytes (8 * 3 = 24 bytes)
# 2) Choose Block Cipher Mode : CBC
#   * IV        :   8 bytes
#   * padding(pad/unpad)


from Crypto.Cipher import DES3 as DES
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)


cipher1 = DES.new(key, DES.MODE_CBC, iv)
encrypted = cipher1.encrypt(pad(mymsg, 8))
print("Plaintext: ", mymsg)
print("Encrypted: ", encrypted)


#암복호화 각각 객체를 따로 만들어 줘야 한다
cipher2 = DES.new(key, DES.MODE_CBC, iv)
decrypted = unpad(cipher2.decrypt(encrypted), 8)
print("Decrypted: ", decrypted.decode())

 

 

 


 

 

 

 

[AES]

 

 

 

1. AES-CBC 암복호화 프로그램

 

 

■ AES 알고리즘을 사용하여

메시지를 암호화/복호화 하는 프로그램을 개발

 

 

*프로그램 개발시 다음과 같은 사항을 참고 한다.

 

1) AES

입력 : 16 bytes(128 bits) 평문 입력

출력 : 16 bytes(128 bits) 암호문 출력

블록 단위 : 16 bytes(128 bites)

키 길이 : 16 bytes(128(16), 192(24), 256(32))

 

2) Block Cipher Mode : CBC

IV : 16 바이트(128비트)의 iv 필요

Padding : 패딩(padding)에 대한 처리(암호화: pad, 복호화: unpad)

 

3) PyCryptodome 패키지에서 byte string 사용해야 한다.

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

 

 

 

 

# AES256-CBC
# Cipher Algorithm : AES256
# * input : 128 bits block(16 bytes)
# * key   : 128(16), 256(32), 512(64) bits
# * output: 128 bits block(16 bytes)
# * Padding
# Cipher Mode : CBC
# * IV

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

#
# (1) Encryption Side
#

msg = b'hello world!'
key = get_random_bytes(32)  # 32 x 8 = 256
iv = get_random_bytes(16)   # 16 x 8 = 128

cipher1 = AES.new(key, AES.MODE_CBC, iv)
encrypted_ciphertext = cipher1.encrypt(pad(msg, 16))

send_msg = encrypted_ciphertext
send_key = key
send_iv = iv

print('Plaintext :', msg)
print('Encrypted :', encrypted_ciphertext)


#
# (2) Decryption Side
#

encrypted_ciphertext = send_msg
key = send_key
iv = send_iv


cipher2 = AES.new(key, AES.MODE_CBC, iv)
decrypted = unpad(cipher2.decrypt(encrypted_ciphertext), 16)

print('Decrypted  :', decrypted.decode())

 

 

 

 

2. AES-CTR을 사용하여 메시지 암복호화

1) AES 알고리즘

* 입력 : 16 bytes(128 bits)

* 출력 : 16 bytes(128 bits)

* 키 : 16(128)/24(192)/32(256)

 

2) CTR 암호 모드

* IV 필요 없음

* Padding 처리할 필요 없음

* counter value (nonce + counter) 필요함

 

 

 

1. AESFromMsg_CTR.py

 

# AES256-CTR or AES128-CTR
# 1) Cipher Algorythm : AES256
#   * input  : 16 bytes
#   * key    : 32 bytes(256 bits) / 16 bytes (128 bits)
#   * output : 16 bytes
# 2) Cipher Mode : CTR
#   * counter value(nonce + count)
#   * nonce   : 초기화시 설정되는 고정된 nonce(비표) -> 상대에게 보내줘야 하는 값
#    * counter : 1씩 증가(빅엔디안 인코딩)

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

#
# (1) Encryption Side
#

msg = b'hello world'
recv_key = get_random_bytes(16)

cipher1 = AES.new(recv_key, AES.MODE_CTR)
recv_ciphertext = cipher1.encrypt(msg)
#nonce = ciphertext.nonce # nonce 값은 자동 생성됨
print("Plaintext :", msg)
print("Encrypted :", recv_ciphertext)

send_msg = recv_ciphertext
send_key = recv_key
send_nonce = cipher1.nonce

#
# (2) Decryption Side
#

recv_ciphertext = send_msg
recv_key = send_key
recv_nonce = send_nonce

cipher2 = AES.new(recv_key, AES.MODE_CTR, nonce=recv_nonce)
plaintext = cipher2.decrypt(recv_ciphertext)
print("Decrypted :", plaintext.decode())

 

 

 

 

2. Web방식 송수신

json 포멧으로 인코딩해 보내자

 

AESFromMsg_CTR2.py

 

# AES128-CTR
# 1) Cipher Algorithm : AES128
#   * input : 16 bytes
#   * key   : 16 bytes
#   * output: 16bytes
# 2) Cipher Mode : CTR
#   * counter value(nonce + count)


from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

import json
from base64 import b64encode, b64decode

#
# 1) Encryption Side
#

msg = b'hello world'
key = get_random_bytes(16)
cipher1 = AES.new(key, AES.MODE_CTR)
encrypted = cipher1.encrypt(msg)
print("Plaintext :", msg.decode())
print("Encrypted :", encrypted)

# 웹으로 보낸다고 가정
# 웹에서 보낼떈 base64방식으로 인코딩해 보내야 한다. 특수문자나 개행문자등 때문에 로스율이 생길 수 있다.
send_msg = b64encode(encrypted).decode()
send_nonce = b64encode(cipher1.nonce).decode('UTF-8')
send_key = key
data = {'msg': send_msg,
        'nonce': send_nonce} # hash값으로 검색하기 때문에 순서는 상관 없다
#print(data)
send_data = json.dumps(data) # 행 변환. json포멧으로 인코딩해 보냄 / serialization
print("Send MSG :", send_data)

#
# 2) Decryption Side
#

recv_msg = send_data # nonce 값이 들어있음
recv_key = send_key

b64 = json.loads(send_data) #json dumps로 보내고 loads로 받는다. deserialization
#print(b64)
#print(b64['msg'], b64['nonce'])
msg = b64decode(b64['msg'])
nonce = b64decode(b64['nonce'])
key = recv_key
#print(msg)
#print(nonce)
#print(key)

cipher2 = AES.new(key, AES.MODE_CTR, nonce=nonce)
decrypted = cipher2.decrypt(msg)
print("Decrypted :", decrypted.decode('utf-8'))

 

 

 

3. 웹 데이터 송신시 인증을 추가해 보내기

 

AES-EAX 사용하여 메시지 암복호화

암호화해서 전송할때 JSON 포맷으로 변경하여 전송하고, 받는 쪽에서 복호화한다.

AES128 키를 생성하고 데이터를 파일로 암호화 한다.

수신자가 무단 수정을 감지할 수 있도록 EAX 모드를 사용한다.

 

AESFromMsg_EAX.py

 

 

import json
from base64 import b64encode, b64decode
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

#
# (1) Encryption
#
header = b'header'
data = b'hello world!'
key = get_random_bytes(16)

cipher1 = AES.new(key, AES.MODE_EAX) # 객체 생성 = cipher1
cipher1.update(header)
ciphertext, tag = cipher1.encrypt_and_digest(data) # hash 함수 생성해 tag에 넣음

json_k = ['nonce', 'header', 'ciphertext', 'tag']
json_v = [b64encode(x).decode('utf-8') for x in (cipher1.nonce, header, ciphertext, tag)]
#print(json_k, json_v)
#print(zip(json_k, json_v))
#print(list(zip(json_k, json_v)))
#print(dict(zip(json_k, json_v)))
#print(dict(list(zip(json_k, json_v)))) ; input()
send_data = json.dumps(dict(zip(json_k, json_v)))

print('Original Message       :', data.decode())
print('Encrypted Transmission :', send_data)


#
# (2) Decryption
#

json_input = send_data

b64 = json.loads(json_input)
json_k = ['nonce', 'header', 'ciphertext', 'tag']
jv = {k: b64decode(b64[k]) for k in json_k}
#print(jv) ; input(0)

cipher2 = AES.new(key, AES.MODE_EAX, nonce=jv['nonce'])
cipher2.update(jv['header'])
plaintext = cipher2.decrypt_and_verify(jv['ciphertext'], jv['tag'])
print("Decrypted Message      : " + plaintext.decode())
728x90

+ Recent posts