파이썬 실습/GUI,윈도우 암호화 프로그램 만들기

파이썬 GUI/윈도우 암호화 프로그램 만들기 - 3.암호화 처리 부분

파기차차 2022. 11. 24. 07:46
728x90
반응형
SMALL
반응형
ㅁ 개요

 

O 프로그램 소개
 

 - 이번 프로그램은 이전글(2022.11.20 - [분류 전체보기] - 파이썬 GUI/윈도우 암호화 프로그램 만들기 - 2.패스워드 입력 및 해시 처리)에 이은 3번째 글로 암호화 하기 위해 입력받은 패스워드와 선택된 파일을 암호화 처리하는 방식에 대하여 설명합니다.

(본 블로그의 내용은 유튜브 동영상(파이썬 GUI/윈도우 암호화 프로그램 만들기-3.암호화 처리(making GUI/Windows Encryption program byPython 3.encryption))에서 더욱 자세히 보실 수 있습니다.)

 

 

 

 

O 완성된 프로그램 실행 화면

 

 - 최종 완성된 프로그램의 결과화면은 아래와 같습니다.

 

1. 원본 파일(aa.txt)을 확인결과 파일내용이 'aa'로 확인 됩니다.(없는 경우 하나 만드시기 바랍니다.)

 

 

2. 아래와 같이 프로그램 실행 후 (1) 패스워드 입력, (2) 암호화할 파일 선택, (3) 암호화 버튼 클릭 하면 파일('aa.txt')이 정상적으로 암호화 됩니다.

 

3. 실제 폴더에 가서 파일 확인 결과 이전 파일 내용('aa')과는 다른 암호화된 내용으로 잘 변경되었음을 확인합니다.

 

 

 


 

O 시작전 준비 사항

 

 

 - 프로그램을 실행하기 위해서는 아래 모듈들이 필요합니다. 아래와 같이 임포트 해줍니다.

 

import base64

import hashlib
from Crypto.Cipher import AES # 대칭키를 사용하기 위한 모듈 임포트

 

 

***에러 발생시 조치 사항(에러가 없는 경우 안보셔도 됩니다.)

--------------------------------------------------------------------------------------

만일 아래와 같이 에러 발생 시

ModuleNotFoundError: No module named 'Crypto'

 

pip install pycrypto <-- 현재 이 모듈은 더 이상 안전하지 않아 설치 되지 않음
pip install pycryptodome <-- 이 모듈을 설치

 

 

위의 모듈 설치 후에도 계속 동일한 에러 발생 시

ModuleNotFoundError: No module named 'Crypto'


아래 부분을 에서 와 같이 수정
from Crypto.cipher import PKCS1_OAEP # 소문자를

 

이렇게 수정

from Crypto.Cipher import PKCS1_OAEP # 대문자로 수정

--------------------------------------------------------------------------------------

 

 

여기까지 이상없이 되셨다면 이제 우리는 다음 단계로 넘어갈 준비가 되었습니다.


 

ㅁ 세부 내용
 
O 완성된 소스

 

# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5.QtGui import *
import base64
import hashlib
from Crypto.Cipher import AES # 대칭키를 사용하기 위한 모듈 임포트


form_class = uic.loadUiType("gui_encryption_program4.ui")[0]

class MyWindow(QMainWindow, form_class):
    def __init__(self):
        global pad, unpad
        super().__init__()
        BS = 16 # blocksize를 16바이트로 고정시켜야 함(AES의 특징)

        # AES에서는 블럭사이즈가 128bit 즉 16byte로 고정되어 있어야 하므로 문자열을 encrypt()함수 인자로 전달시
        # 입력 받은 데이터의 길이가 블럭사이즈의 배수가 아닐때 아래와 같이 패딩을 해주어야 한다.
        # 패딩: 데이터의 길이가 블럭사이즈의 배수가 아닐때 마지막 블록값을 추가해 블록사이즈의 배수로 맞추어 주는 행위
        pad = (lambda s: s+ (BS - len(s) % BS) * chr(BS - len(s) % BS).encode())
        unpad = (lambda s: s[:-ord(s[len(s)-1:])])

        self.setFixedSize(700,700)
        self.setWindowIcon(QIcon("pagichacha.png"))
        self.setupUi(self)

        self.toolButton_4.clicked.connect(self.select_toEncryptFile)
        self.pushButton_3.clicked.connect(self.trigger_encrypt)


    ##################################################################################
    # 1. 키(패스워드) 생성 + 해시 처리
    ##################################################################################
    def make_key(self):
        global key
        self.textEdit.clear()

        key_org = self.lineEdit_4.text()
        self.textEdit.append("1. 원본 키(key) : "+key_org)

        self.key = hashlib.sha256(key_org.encode()).digest()
        print("AES Key(Key 문장 암호화) : ", self.key)
        self.textEdit.append("2. Key에 해시 적용 후 결과 : "+str(self.key)+"\n")


        return self.key
    
    ##################################################################################
    # 2.암호화 
    ##################################################################################
    def select_toEncryptFile(self):
        global toEncryptFile
        toEncryptFile = QFileDialog.getOpenFileName(self, "Open file", './')
        print(type(toEncryptFile))
        self.textEdit.append('{}'.format(toEncryptFile[0]))
        # return toEncryptFile

    def encrypt(self, message):
        message = message.encode()
        raw = pad(message)
        key = self.make_key()
        cipher = AES.new(key, AES.MODE_CBC, self.__iv().encode('utf8'))
        enc = cipher.encrypt(raw)
        return base64.b64encode(enc).decode('utf-8')

    def trigger_encrypt(self):
        global encrypt_data
        self.textEdit.clear()
        # print(toEncryptFile[0])
        f = open(toEncryptFile[0], "r", encoding="euckr")
        data = f.read()
        f.close()
        print("원문 내용", data)

        encrypt_data = self.encrypt(data)

        # f = open("aa_enc.txt", "w")
        f = open(toEncryptFile[0], "w")
        f.write(str(encrypt_data))
        f.close()

        print("-"*100, "\n")
        print("원문을 키로 암호화 결과: ", encrypt_data)
        print("-"*100, "\n")
        self.textEdit.append("-"*70)
        self.textEdit.append("3. 원문 내용 : "+data)
        self.textEdit.append("4. 원문을 키로 암호화 결과:"+ encrypt_data)
        self.textEdit.append("-"*70)

        QMessageBox.about(self, "암호화!!", "파일이 암호화 되었습니다.")

    def __iv(self):
        return chr(0) * 16

app=QApplication(sys.argv)
window = MyWindow()
window.show()
print("Before event loop")
app.exec_()
print("After event loop")

 

 

 

 

O 소스 다운로드 및 실행
 
 - 소스파일 다운로드 후 cmd 또는 파워쉘 등에서 아래와 같이 실행하시기 바랍니다.
('gui_encryption_program4.ui' 파일은 'total2.py' 실행파일과 동일한 위치에 놓으시기 바랍니다.)
 
 
 > python total2.py

 

 


 
 
O 소스 분석

아래 12번까지는 이전글(2022.11.20 - [분류 전체보기] - 파이썬 GUI/윈도우 암호화 프로그램 만들기 - 2.패스워드 입력 및 해시 처리)과 동일하며, 13번부터 새롭게 추가 되었습니다.

 

1.from Crypto.Cipher import AES <-- 대칭키를 사용하기 위한 모듈 임포트
2.BS = 16 <-- blocksize를 16바이트로 고정시켜야 함(AES의 특징)
3.pad = (lambda s: s+ (BS - len(s) % BS) * chr(BS - len(s) % BS).encode()) <-- 패딩 처리
# AES에서는 블럭사이즈가 128bit 즉 16byte로 고정되어 있어야 하므로 문자열을 encrypt()함수 인자로 전달시
# 입력 받은 데이터의 길이가 블럭사이즈의 배수가 아닐때 아래와 같이 패딩을 해주어야 한다.
# 패딩: 데이터의 길이가 블럭사이즈의 배수가 아닐때 마지막 블록값을 추가해 블록사이즈의 배수로 맞추어 주는 행위
4.unpad = (lambda s: s[:-ord(s[len(s)-1:])]) <-- 패딩처리된 부분은 원래대로 처리
5.self.setupUi(self) <-- 위에서 만든 UI를 클래스에 반영
6.self.pushButton_3.clicked.connect(self.test) <-- 'pushButton_3'(암호화) 버튼이 클릭되면 test함수 호출
7.key = self.make_key() <--make_key()함수의 리턴값을 key변수에 저장
8.self.textEdit.clear() <-- 텍스트에디트('실행결과' 화면)를 클리어(빈 화면으로)
9.key_org = self.lineEdit_4.text() <-- lineEdit_4의 입력값(패스워드(키)입력 값)을 key_org변수에 할당
10.self.textEdit.append("1. 원본 키(key) : "+key_org) <-- 텍스트에디트('실행결과' 화면)에 입력한 패스워드를 보여줌
11.self.key = hashlib.sha256(key_org.encode()).digest() <-- 키가 쉽게 노출되는 것을 막기 위해 키를 어렵게 처리하는 과정으로 보통 해시를 적용
12.self.textEdit.append("2. Key에 해시 적용 후 결과 : "+str(self.key)+"\n") <-- 텍스트에디트('실행결과' 화면)에 입력한 패스워드의 해시처리된 값을 보여줌

13.global toEncryptFile <-- toEncryptFile변수를 다른 함수에서 사용할 수 있도록 global 처리
14.toEncryptFile = QFileDialog.getOpenFileName(self, "Open file", './') <-- 파일선택
15.self.textEdit.append('{}'.format(toEncryptFile[0])) <-- 실행결과 화면에 선택된 파일의 전체 경로를 보여줌
16.key = self.make_key() <-- 입력한 패스워드를 해시처리한 값을 리턴
17.cipher = AES.new(key, AES.MODE_CBC, self.__iv().encode('utf8')) <-- AES 알고리즘 적용
18.enc = cipher.encrypt(raw) <-- AES알고리즘으로 암호화 처리
19.f = open(toEncryptFile[0], "r", encoding="euckr") <-- 파일을 읽기모드로 연다.
20.encrypt_data = self.encrypt(data) <-- data(원문)를 암호화 처리 
21.
def __iv(self): <--패딩처리를 위한 함수
        return chr(0) * 16


 

O 주요 내용

 

 

1.기본 소스에 대한 설명은 위에서 설명 드린 바와 같으며, 'total2.py' 소스 실행 후 암호화할 파일을 클릭(toolButton_4)하면암호화할 파일 선택할 수 있습니다. 그리고 나서 암호화 버튼(pushButton_3)을 클릭하면 trigger_encrypt() 함수가 실행되고,

 

 

 

 

2. trigger_encrypt() 함수는

-선택한 파일의 내용을 읽은 후 읽은 데이터('aa')를 encrypt(data) 함수에 넘겨 주고, 암호화된 값(encrypt_data)을 리턴 받습니다.

- 이후 동일한 파일명(toEncryptFile[0]) <-- 'aa.txt')으로 해당 파일에 리턴 받은 값(암호화된 값)을 쓰기 작업으로 파일을 만듭니다.

- 그리고 나서 '정상적으로 암호화가 되었다' 라고 메시지 박스를 띄웁니다.

 

 

 

 

 3. 실제 암호화 처리 함수인 encrypt()함수는 전달받은 메시지('aa')를 AES 암호화 알고리즘으로 암호화 처리 후 그 결과를 리턴합니다.

 

 

 

 

 


 

ㅁ 정리
 
O 우리가 배운 내용
 

 
 - 오늘 우리가 배운 핵심 내용을 간단히 정리해 보면 아래와 같습니다.
 
 > 1. 입력한 패스워드 해시 처리
 > 2. 암호화할 파일 선택
 > 3. 선택한 파일을 입력한 해시 처리 패스워드를 키로 해서 AES 암호화 처리/적용
 
 
 

 

오늘은 여기까지이며, 위의 내용이 유익하셨다면, 좋아요와 구독 부탁드립니다.

 

 

감사합니다.

728x90
반응형
LIST