[목차]
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())
'정보보안공부 > 정보보안전문과정' 카테고리의 다른 글
정보보안 과정 Day 83 : 암복호화 파일저장 및 통신2 (0) | 2021.01.05 |
---|---|
정보보안 과정 Day 82 : 암복호화 파일저장 및 통신1 (0) | 2021.01.04 |
정보보안 과정 Day80-1 : 3DES 실습 (0) | 2020.12.30 |
정보보안 과정 Day80 : 암호학 5 (0) | 2020.12.30 |
정보보안 과정 Day79 : 암호학 4 (0) | 2020.12.29 |