드림핵 문제 like64 문제를 풀다 궁금했던 부분을 알아봅시다.
Base64 encoding & Decoding 원리를 알아봅시다.
What is Base64
Base64는 ascii 영역의 문자들로 이루어진 문자열로 변환하는 인코딩 기술입니다.
전체의 ascii 영역은 아니며 2^6 -> 64글자를 가지고 인코딩을 하는 방법
입니다.
어떤 방식으로 인코딩과 디코딩이 이루어 지는지 알아봅시다.
Encoding & Decoding
python으로 간단한 문자열을 인코딩 및 복호화를 사용하는 방식입니다.
base64를 import 하여 간단하게 사용할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import base64
text = "glasses96"
print(f"[+] Plain text : {text}")
#[+] Plain text : glasses96
text = text.encode('utf-8')
encoding_text = base64.b64encode(text).decode('utf-8')
print(f"[+] Encoding text : {encoding_text}")
#[+] Encoding text : Z2xhc3Nlczk2
decoding_text = base64.b64decode(encoding_text).decode('utf-8')
print(f"[+] Decoding text : {decoding_text}")
#[+] Decoding text : glasses96
Encoding Principle
인코딩은 어떤방법으로 할 수 있는지 알아봅시다.
테스트는 간단히 AB를 인코딩 하는 방법입니다.
- 인코딩에 사용할 문자열 셋(ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/)
-> 64개(2^6)의 문자 - 문자열을 전부 8비트 2진수로 변환
-> ex) A => 01000001, B => 01000010 - 6비트 씩 묶음
-> 010000 010100 0010 - 6비트가 안되면 0 padding을 추가
-> 010000 010100 001000 - 16, 20, 8로 문자열의 셋의 인덱스로(8,16,8) 사용 -> QUI
- 패딩을 표현하기 위해 “=” 를 추가
-> QUI=
AB를 파이썬 코드에 넣었을때 똑같이 나오는 것을 확인할 수 있습니다.
1
2
[+] Plain text : AB
[+] Encoding text : QUI=
Base64 Encoding Code
파이썬 코드로 만든 base64 인코딩 함수입니다.
위에서 설명한거처럼 8비트에서 6비트로 쪼개서 문자열 셋에 인덱스로 가져오고 6비트가 안되면 0 패딩을 채웁니다.
패딩 문자열 “=” 을 추가하는데 여기서 “=”의 개수를 몇개를 넣어야 하는지를 보면 2진수로 변환된 문자열의 길이를 24로 나눈 나머지를 구합니다.
그리고 24 - 나머지
를 하고 다시 6으로 나눈 몫 만큼 "=" 를 추가
합니다.
24를 나누는 이유는 8비트와 6비트를 사용하기 떄문에 최소 공배수인 24를 사용하고, base64에선 6비트를 1글자로 하기 때문에 6으로 나눈 몫의 값을 =을 추가합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
def custom_base64_encode(text):
# Base64 인코딩에 사용되는 문자셋
base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
# 입력 문자열을 바이트로 변환
binary_data = text.encode('utf-8')
# 바이트를 이진수로 변환
binary_string = ''.join(format(byte, '08b') for byte in binary_data)
# 6비트씩 묶어서 Base64 문자로 매핑
encoded_chars = []
for i in range(0, len(binary_string), 6):
chunk = binary_string[i:i+6]
padding = 6 - len(chunk)
chunk = chunk + '0' * padding
decimal_value = int(chunk, 2)
encoded_chars.append(base64_chars[decimal_value])
# padding 문자 추가
padding = len(binary_string) % 24
if padding > 0:
padding = 24 - padding
encoded_chars.extend(['='] * (padding // 6))
# 리스트를 문자열로 변환하여 반환
return ''.join(encoded_chars)
결과를 보면 똑같은 것을 확인할 수 있습니다.
1
2
3
4
5
6
7
original_text = "glasses96"
encoded_text = custom_base64_encode(original_text)
print("Original Text:", original_text)
#Original Text: glasses96
print("Encoded Text:", encoded_text)
#Encoded Text: Z2xhc3Nlczk2
Decoding Principle
복호화도 알아봅시다.
- 인코딩된 문자열을 6비트로 2진수로 변환
-> ex) QWI= -> 010000010100001000 - ”=” 문자 개수 만큼 “000000”을 붙여줌
-> 010000010100001000000000 - 8비트 문자열로 변환
-> AB
Base64 Decoding Code
파이썬 코드로 만든 base64 디코딩 함수입니다. 인코딩된 문자열을 base64 문자열 셋과 매핑하여 6비트 2진수 값을 이어붙입니다.
= 갯수만큼 000000으로 추가해줍니다.
마지막으로 8비트로 문자열로 바꿔줘 원래의 문자열을 보여줍니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def custom_base64_decode(encoded_text):
# Base64 디코딩에 사용되는 문자셋
base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
# '='를 제거하고 Base64 문자를 이진수로 매핑
binary_string = ''
for char in encoded_text:
if char == '=':
binary_string += "000000"
else:
decimal_value = base64_chars.index(char)
binary_string += format(decimal_value, '06b')
# 이진수를 바이트로 변환하여 반환
return int(binary_string, 2).to_bytes(len(binary_string) // 8, byteorder='big').decode('utf-8')
결과를 보면 잘 디코딩 된것을 알 수 있습니다.
1
2
3
4
5
6
7
8
9
10
original_text = "glasses96"
encoded_text = custom_base64_encode(original_text)
decoded_text = custom_base64_decode(encoded_text)
print("Original Text:", original_text)
#Original Text: glasses96
print("Encoded Text:", encoded_text)
#Encoded Text: Z2xhc3Nlczk2
print("Decoded Text:", decoded_text)
#Decoded Text: glasses96
후기
base64 인/디코딩 원리를 배우니 재밌었습니다! 끝.