03_1 SDES
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