_빌런 2023. 3. 30. 10:23

Simplified DES는 말 그대로 DES를 간이 형태로 만든 것이다.

DES는 64bit의 입력 블록, 56bit 키, 16Rounds, 각 회전에서 48bit 보조키를 사용하지만,

SDES는 4bit의 입력 블록, 6bit 키, 2 Round 만을 사용한다.

 

아래에는 직접 코드를 작성하여 구현한 SDES이다.

SDES의 복호화와 암호화 외에도 6bit의 Key도 생성하는 키 스케쥴 알고리즘도 같이 있다.

 

S_DES() 함수에서는 간이 DES의 암 복호화 알고리즘이다. 하위는 S_DES 구성 함수이다.

String_2_Int() : 입력받은 2글자 영문자를 해당하는 이진수로 바꿔주는 함수

IP() : 초기 치환 함수, 8bit 이진수를 정해진 인덱스로 위치를 바꿔주는 함수

IP_1() : 마지막 치환 함수, 8bit 이진수를 정해진 인덱스로 위치를 바꿔주는 함수

Split() : 8bit 입력을 좌우 각 4bit로 나누는 함수

Expansion() : 4bit를 6bit로 확장하는 E-Box 함수

XOR() : 주어진 두 수를 XOR 연산하는 함수

Substitution() : 6bit를 4bit로 압축하는 S-Box 함수

PS() : 4bit 이진수를 정해진 인덱스로 위치를 바꿔주는 함수

Int_2_String() : 8bit 이진수에 해당하는 2글자 영문자로 바꿔주는 함수

Key_Generator() 함수에서는 Key를 생성하는 키 스케쥴 생성 알고리즘이다. 하위는 Key_Generator 구성 함수이다.
Select_Permutation() : 8bit 이진수를 정해진 인덱스로 위치를 바꿔주는 함수

Split_N_Shift() : 8bit를 4bit로 나눈 뒤, 4bit 이진수를 정해진 인덱스로 위치를 바꿔주는 함수

Substitution() : 8bit를 6bit로 압축하는 S-Box 함수

 

# -------------------- Import --------------------
from collections import deque
import sys, random
input = sys.stdin.readline

# -------------------- Function --------------------
def S_DES(INPUT: str, TYPE: str, KEY1: list, KEY2: list) -> str:
    # ---------- Function ----------
    def String_2_Int(input_string: str) -> str:     	#
        alphabet = ["A", "B", "C", "D", "E", "F", "G", "H",  "I",  "J",  "K",  "L",  "M",  "N",  "O", "etc"]
        blphabet = [  0,   1,  10,  11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110,  1111]   # binary alphabet

        left_bit = ""
        for index in range(16):
            if input_string[0] == alphabet[index]:
                left_bit = str('{0:04d}'.format(blphabet[index]))
                break
            else:
                left_bit = "1111"

        right_bit = ""
        for index in range(16):
            if input_string[1] == alphabet[index]:
                right_bit = str('{0:04d}'.format(blphabet[index]))
                break
            else:
                right_bit = "1111"

        return left_bit + right_bit


    def IP(input_bit: list) -> list:                  		# Init Permutation First
        output_bit = [0] * len(input_bit)

        for index in range(len(input_bit)):
            if index % 2 == 0:  # 0 2 4 6 > 4 5 6 7
                output_bit[index // 2 + len(input_bit) // 2] = input_bit[index]
            else:   # 1 3 5 7 > 0 1 2 3
                output_bit[index // 2] = input_bit[index]

        return output_bit


    def IP_1(input_bit: list) -> list:                	# Init Permutation Final
        output_bit = [0] * len(input_bit)

        for index in range(len(input_bit)):
            if index <= 3:
                output_bit[index + (index + 1)] = input_bit[index]
            else:   # index >= 4
                output_bit[index - (len(input_bit) - index)] = input_bit[index]

        return output_bit


    def Split(input_bit: list) -> list:           		# Split Each 4bit
        Left, Right = [], []

        for index in range(len(input_bit)):
            if index < 4:
                Left.append(input_bit[index])
            else:
                Right.append(input_bit[index])

        return Left, Right


    def Expansion(input_bit: list) -> list:       	# E-Box Operation
        output_bit = []
        index_lst = [2, 3, 0, 1, 2, 3]

        for index in index_lst:
            output_bit.append(input_bit[index])

        return output_bit
    

    def XOR(A: list, B: list) -> list:                      # XOR Operation
        result = []

        for index in range(len(A)):     # or range(len(B))
            xor = int(A[index]) ^ int(B[index])
            result.append(str(xor))

        return result


    def Substitution(input_bit: list) -> list:        	# S-Box Operation
        rowB = input_bit[5] + input_bit[0]
        columnB = input_bit[4] + input_bit[3] + input_bit[2] + input_bit[1]

        S = [[14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7],
             [0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8],
             [4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0],
             [15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13]]
        
        rowD, multiple = 0, 0
        for index in range(len(rowB)):
            rowD += 2 ** multiple * int(rowB[index])
            multiple += 1

        columnD, multiple = 0, 0
        for index in range(len(columnB)):
            columnD += 2 ** multiple * int(columnB[index])
            multiple += 1

        tmp = S[rowD][columnD]
        tmp = int(format(tmp, 'b'))

        output_bit = list(str('{0:04d}'.format(tmp)))

        return output_bit


    def PS(input_bit: list) -> list:                  	# Permutation Switch
        output_bit = deque()

        for num in input_bit:
            output_bit.append(num)

        output_bit.rotate(2)

        return list(output_bit)
    

    def Int_2_String(input_intLst: list) -> str:     # Exchagning Int list to String
        alphabet = ["A", "B", "C", "D", "E", "F", "G", "H",  "I",  "J",  "K",  "L",  "M",  "N",  "O", "etc"]
        blphabet = [  0,   1,  10,  11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110,  1111]   # binary alphabet

        first_char, second_char = [], [] 
        for index in range(len(input_intLst)):
            if index <= 3:
                first_char.append(input_intLst[index])
            else:
                second_char.append(input_intLst[index])

        first_char = int(''.join(first_char))
        second_char = int(''.join(second_char))

        for index in range(len(blphabet)):
            if blphabet[index] == first_char:
                first_char = alphabet[index]
            
            if blphabet[index] == second_char:
                second_char = alphabet[index]

        return first_char + second_char

    # ---------- Sub Main ----------
    if TYPE == "Encryption":
        bit = String_2_Int(INPUT)   	# STEP 1_1
        IP = IP(bit)                		# STEP 1_2

    if TYPE == "Decryption":
        INPUT = list(str(INPUT))
        IP = IP(INPUT)              		# STEP 1

    L0, R0 = Split(IP)              		# STEP 2
    ER0 = Expansion(R0)             	# STEP 3
    ER_K0 = XOR(ER0, KEY1)          	# STEP 4
    S0 = Substitution(ER_K0)        	# STEP 5_1
    PS0 = PS(S0)                    		# STEP 5_2

    L1, R1 = R0, XOR(L0, PS0)       	# STEP 6
    ER1 = Expansion(R1)             	# STEP 7
    ER_K1 = XOR(ER1, KEY2)          	# STEP 8
    S1 = Substitution(ER_K1)        	# STEP 9_1
    PS1 = PS(S1)                    		# STEP 9_2

    L2, R2 = R1, XOR(L1, PS1)       	# STEP 10
    L2, R2 = R2, L2                 		# STEP 11
    IP_1 = IP_1(L2 + R2)            		# STEP 12

    if TYPE == "Encryption":
        return IP_1
    
    if TYPE == "Decryption":
        OUTPUT = Int_2_String(IP_1) 	# STEP 12

        return OUTPUT

    return False


def Key_Generator(TYPE: str) -> list:
    # ---------- Function ----------
    def Select_Permutation(input_bit: list) -> list:          	# Fixed PC
        output_bit = []
        index_lst = [2, 5, 3, 7, 6, 4, 1, 0]

        for index in index_lst:
            output_bit.append(input_bit[index])

        return output_bit


    def Select_Permutation_Random(input_bit: list) -> list:   # Random PC (option)
        output_bit = []
        index_lst = []

        while len(output_bit) != 8:
            index = random.randrange(0, 8)
            
            if index not in index_lst:
                index_lst.append(index)
                output_bit.append(input_bit[index])

        return output_bit


    def Split_N_Shift(input_bit: list, shift: int) -> list:        	# Split to left and right bit
        left_bit, right_bit = deque(), deque()

        for index in range(len(input_bit)):
            if index <= 3:
                left_bit.append(input_bit[index])
            else:
                right_bit.append(input_bit[index])

        left_bit.rotate(shift)
        right_bit.rotate(shift)

        return list(left_bit), list(right_bit)
    

    def Substitution(left_bit: list, right_bit: list) -> list:      	# S-Box Operation
        input_bit = left_bit + right_bit
        output_bit = []

        index_lst = [6, 4, 0, 7, 5, 1]
        for index in index_lst:
            output_bit.append(input_bit[index])

        return output_bit


    # ---------- Sub Main ----------
    Key0 = "10011001" # init_key
    Key1, Key2 = [], []

    #shift = -1 if TYPE == "Encryption" else shift = 1
    if "Encryption" in TYPE:
        shift = -1
    if "Decryption" in TYPE:
        shift = 1

    PC_K = Select_Permutation(list(Key0))   	# STEP 1
    if "Random" in TYPE: PC_K = Select_Permutation_Random(list(Key0)) 
    
    C, D = Split_N_Shift(PC_K, shift)       	# STEP 2
    Key1 = Substitution(C, D)               	# STEP 3

    C, D = Split_N_Shift(C + D, 2)          	# STEP 4
    Key2 = Substitution(C, D)               	# STEP 5
    
    return Key1, Key2


# -------------------- Main --------------------
plain_text, cipher_text = "", ""
EKey1, EKey2, DKey1, DKey2 = [], [], [], []

print(" ___       ___  ___  ___ ")
print("/ __> ___ | . \| __>/ __>")
print("\\__ \\|___|| | || _> \\__ \\")
print("<___/     |___/|___><___/\n")

while True:
    print("Mode | 1. Key Scheduling(Fixed)\t2. Key Scheduling(Random)") # 3. Key Scheduling(Custom)
    print("       3. Encryption\t\t4. Decryption\t\t\t5. Quit")
    print("MODE SELECT >>> ", end="")
    selectMode = int(input())
    
    if selectMode == 1:
        EKey1, EKey2 = Key_Generator("Encryption")
        DKey1, DKey2 = Key_Generator("Decryption")
        print("Complete key generating, plz continue encryption or decryption\n")
        
    if selectMode == 2:
        EKey1, EKey2 = Key_Generator("EncryptionRandom")
        DKey1, DKey2 = EKey2, EKey1
        print("Complete key generating, plz continue encryption or decryption\n")
            
    if selectMode == 3:
        if not EKey1:
            print("Plz generate key first.\n")
            continue
        
        print("평문을 입력해주세요 : ", end="")
        plain_text = input()

        cipher_text = S_DES(plain_text, "Encryption", EKey1, EKey2)
        print("암호문 :", ''.join(cipher_text))
        print()
        
    if selectMode == 4:
        if not EKey1:
            print("Plz generate key first.\n")
            continue
        
        print("암호문을 입력해주세요 : ", end="")
        cipher_text = input().rstrip()
        
        plain_text = S_DES(cipher_text, "Decryption", DKey1, DKey2)
        print("평문 :", ''.join(plain_text))
        print()
        
    if selectMode == 5:
        print("해당 프로그램을 종료합니다.")
        break