호우동의 개발일지

Today :

article thumbnail

썸네일

 

DES3의 개념

- DES의 단점인 키 길이가 충분하지 않다는 점을 보완하기 위해 나온 모델


- 3개의 DES키를 이용한다는 의미

 

3 DES는 DES의 단점을 발전형이기 때문에
해당 글에서는 DES를 알고 있다는 가정 하에 설명하고 있다.


그리고 코드 또한 DES에서 구현했던 것과 똑같이 사용하기 때문에
부연설명을 하진 않았다.

 

그러므로 아래 링크로 들어가서
DES에 관해 먼저 안 뒤에 이 글을 읽기 바란다.

 

https://howudong.tistory.com/90

 

[네트워크 보안] DES 개념 및 암/복호화 구현(Python)

DES의 개념 - 64bit 평문을 64bit 암호문으로 암호화 하는 대표적인 비밀키 방식의 대칭 암호 알고리즘 - 암호화/복호화 할때 쓰는 비밀키가 동일함 DES 암호화 방식 평문을 64비트로 나눠 56비트의 키

howudong.tistory.com

 

 

 

DES3 암호화 방식

 

n번 키로  암호화하는 것을 En
n번 키로 복호화하는 것을 Dn이라고 가정한다

 

암호문 = E3(D2(E1(평문)))

 

즉, 평문을 1번 키로 암호화하고 2번 키로 복호화하고
3번 키로 암호화한 것이 암호란 것이다.

 


그렇다면 이 암호문을 복호화하기 위해서는

 

평문 = D1(E2(D3(암호문)))

 


즉, 역순으로 3번 키로 복호화하고 2번 키로 암호화한 뒤
마지막으로 1번 키로 복호화해야지 원래의 평문이 된다.

 

 

구현

 

 

DES3.py

from ast import Bytes
from base64 import encode
from hmac import digest
from Crypto.Cipher import DES3
from Crypto.Hash import SHA256 as SHA

class myDES3():
    #DES3 초기화
    def __init__(self, keytext, ivtext):
        hash = SHA.new()
        hash.update(keytext.encode('utf-8'))
        key = hash.digest()
        
        # DES키가 3개이므로 8Byte의 3배수인 24Byte
        self.key = key[:24]
        
        hash.update(ivtext.encode('utf-8'))
        iv=hash.digest()
        # IV는 DES와 같은 8BYTE
        self.iv=iv[:8]
    
    # CBC 모드로 암호화
    def encrypt_CBC(self, plaintext):
        while(len(plaintext) % 8 != 0):
            plaintext += ' '
        des3=DES3.new(self.key,DES3.MODE_CBC,self.iv)
        encryptMsg = des3.encrypt(plaintext.encode())
        return encryptMsg
        
    # CBC 모드로 복호화
    def decrypt_CBC(self,ciphertext):
        des3 = DES3.new(self.key, DES3.MODE_CBC,self.iv)
        descryptMsg = des3.decrypt(ciphertext)
        return descryptMsg
    
    # CTR 모드로 암호화
    def encrypt_CTR(self, plaintext):
        while(len(plaintext) % 8 != 0):
            plaintext += ' '
        des3=DES3.new(self.key,DES3.MODE_CTR,self.iv)
        encryptMsg = des3.encrypt(plaintext.encode())
        return encryptMsg
        
    # CTR 모드로 복호화
    def decrypt_CTR(self,ciphertext):
        des3 = DES3.new(self.key, DES3.MODE_CTR,self.iv)
        descryptMsg = des3.decrypt(ciphertext)
        return descryptMsg

DES3의 초기화와 암호화 및 복호화 함수를
담아놓은 DES3 클래스이다.

 

DES3와 다른 점은 키를 생성할 때
24Byte의 키를 사용해야 한다는 것이다.


왜냐하면 DES 키를 3개를 사용하기 때문에
8 Bytes x 3 = 24 Bytes 이기 때문이다.

 

그리고 DES3에는 ECB 모드 대신 CTR 모드가 존재한다.

 

CTR 모드는 IV가 존재한다.

Client.py

import socket
from DES3 import myDES3

HOST = 'localhost'
PORT = 8081

def getFileFromServer(filename):
    data_transferred = 0

    #IP_4 Version으로 TCP방식으로 설정
    with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as sock:
        sock.connect((HOST,PORT))
        sock.sendall(filename.encode())
		
        # 키와 IV, 데이터 받기(데이터는 한줄이기 때문에 편의상 한줄만 전송)
        key = sock.recv(24)
        iv = sock.recv(8)
        data = sock.recv(1024)
        
        if not data:
            print('파일[%s]: 서버에 존재하지 않거나 오류 발생'%filename)
            return
		
        # 파일 쓰기 
        with open(filename+'.des3-CTR','wb') as f:
            try:
                des3 = myDES3(key.decode(),'')
                while data:
                    des = des3.decrypt_CTR(data)
                    f.write(des)
                    data_transferred +=len(data)
                    data = sock.recv(1024)
                    

            except Exception as e:
                print(e)

            print('파일 [%s] 전송 종료. 전송량 [%d]' %(filename, data_transferred))
        
getFileFromServer('example.txt')

DES와 동일하게 받으면 되는데 이와 차이점은
키를 받을 때 24Byte를 받는다는 것이다.

 


이 외에는 모두 같다.

Server.py

import socketserver
from DES3 import myDES3
from os.path import exists
HOST = ''
PORT = 8081
DES3KEY = 'eightkey'
DES3IV = '1234'

# 들어오는 요청을 처리하는 핸들러 클래스를 재정의한 요청처리기
class MyTcpHandler(socketserver.BaseRequestHandler):
    def handle(self):
        data_transferred = 0
        print('[%s]연결됨' % self.client_address[0])
        # 1024 바이트 받기
        filename = self.request.recv(1024)
        filename = filename.decode()

        if not exists(filename):
            return

        print('파일 [%s] 전송 시작..' % filename)
        
        #키와 IV 값을 클라이언트에게 보냄
        self.request.send(DES3KEY.encode('utf-8'))
        self.request.send(DES3IV.encode('utf-8'))
        
        with open(filename,'r') as file:
            try:
            	# 편의상 한줄이므로 라인으로 읽어도 됨
                line = file.readline()
                des3 = myDES3(DES3KEY,DES3IV)
                # DES3로 암호화
                enc = des3.encrypt_CTR(line)
                data_transferred += self.request.send(enc)
            except Exception as e:
                print(e)
                
        print('암호화된 텍스트 : %s\n',enc)
        print('\n')
        print('\n')

        print('전송 완료[%s],전송량[%d]' % (filename, data_transferred))

def runServer():
     print('파일 서버 시작')
     try:
        server = socketserver.TCPServer((HOST, PORT), MyTcpHandler)
        # Ctrl + C 하기 전까진 계속 서버 실행
        server.serve_forever()
     except KeyboardInterrupt:
         print('파일 서버 종료')            
runServer()

사용 함수가 DES에서 DES3로 바뀐 것 외에 큰 차이는 없다.

 

텍스트

클라이언트가 해당 example.txt 파일을 서버에 요청했다.

 


서버는 해당 파일을 키와 iv를 이용하여
DES3로 암호화하여 전송해줘야 한다.


방식은 CTR모드를 사용한다.

 


클라이언트는 파일을 읽기 위해서
파일을 받으면 암호문을 복호화해야 한다.

 

이 상황을 가정해서 한번 테스트를 해보자.

출력

Server.py의 실행 시 터미널의 출력이다.

 

해당 출력에서 정상적인 서버 연결,
파일 전송, DES3로 암호화된 텍스트를 확인할 수 있다.

메모장 텍스트

해당 텍스트파일은 Client에서
정상적으로 복호화가 되었는지 확인하기 위해 작성한 CTR 파일이다.


example.txt와 똑같이 복호화되었다는 것을 확인할 수 있다.