Base64 이론과 파이썬 예제
BASE64
개요
우리는 데이터를 처리할 때, 문자열(ASCII) 데이터를 사용하기도 하고 이진(Binary)데이터를 사용하기도 한다.
문자열 데이터든, 이진 데이터든, 최종적으로 컴퓨터는 이진 데이터로 변환해 처리하지만, 이진 데이터는 사람이 읽기 힘들고, 문자열을 주로 전송하는 프로토콜(SMTP, HTTP 등)에서 원활한 작동이 일어나지 않을 수 있다.
따라서 이진 데이터를 문자열 데이터로 변환하는 과정이 필요하다.
이 과정에서 이진 데이터를 16진수(HEX)로 변환하는 방법이 고안되었다.
예를 들어, '01000101 00110001 01001100'이라는 데이터가 있다.
이 이진 데이터는 사람이 읽기도 힘들고, 무슨 데이터를 뜻하는지 확인하기 어렵다.
따라서 이 데이터를 표기할 때 10진수나 16진수를 이용하여 표현한다.
010001010011000101001100 -> 45 31 4C
위와 같이 3바이트에 해당하는 내용을 단 여섯 문자로 표현할 수 있으며,
16진수의 표기범위인 0~F를 직관적으로 이해할 수 있기에 파일 데이터를 분석할 때 주로 HEX 표기를 사용한다.
다만, 이렇게 Binary를 HEX로 변환하는 것은, 데이터의 분석을 조금 더 쉽게 하기 위함일 뿐이지, Binary 데이터를 문자열로 변환하는 목적으로는 잘 사용되지 않는다.
그러면 어떻게 Binary 데이터를 문자열로, 그것도 효율적으로 바꿀 수 있을까.
ASCII
바로 Binary 데이터와 ASCII 문자를 서로 연결하는 사전을 만들어서, 해당 사전에 맞게 Binary 데이터를 ASCII 문자로 변환한다. 이전의 HEX 표기처럼 특정한 패턴의 Binary 데이터를 ASCII 문자에 대칭시키는 것이다.
다만 이러한 방법을 생각해 내도 문제가 발생한다. 1바이트는 256개의 값을 가질 수 있고, ASCII 코드는 128개의 값을 가진다. 그것도 일부 문자들은 unprintable control code로, 실제 출력할 수 있는 문자가 아니라 운영체제 등을 제어하는 기능을 위해 존재하기 때문에, 실제로 사용할 수 있는 문자는 128개보다 훨씬 적다.
따라서 Binary 데이터와 ASCII 문자를 연결하는 사전에는 실제로 출력할 수 있는 문자, 그리고 각종 통신 프로토콜에서 문제없이 동작할 수 있는 문자를 사용해야 한다.
그렇게 사용할 수 있는 문자는 대문자 'A'부터 'Z'까지, 소문자 'a'부터 'z'까지, 숫자 '0'부터 '9'까지, 그리고 '+'와 '/'가 있다. 이렇게 총 64개의 문자를 사용하여 Binary 데이터를 표현한다.
Binary - ASCII 사전
이제 Binary 데이터를 ASCII 코드로 변환할 차례다. 하나 문제가 있다면, 1바이트는 2^8개의 값을 가지고, 위에서 정한 ASCII 문자들은 2^6개인 것이다. 이에 대한 해결은 간단한데, 8비트짜리 바이트 3개(24비트)를 6비트 4개(24비트)로 쪼개어, 이를 위에서 정한 문자 4개로 표현하는 것이다. 그리고 남은 공간에는 '=' 문자로 채우게 된다.
아래는 Binary 데이터를 ASCII Character로 표기하는 사전이다. 이 사전이 있다면 Binary 데이터를 ASCII 문자로 변환할 수 있고, 그 반대도 가능하다.

Binary - ASCII 인코딩, 디코딩
위의 개요에서 살펴본 '010001010011000101001100' Binary 데이터를 ASCII 문자로 변환해보자. 먼저 3바이트를 6비트짜리 4개 묶음으로 나눈다.
그리고 나누어진 6비트짜리 묶음을 위 사전을 참고해 각각 치환한다.
결과는 'RTFM'으로, 성공적으로 인코딩이 완료되었다. 역순으로 진행하면 디코딩까지 할 수 있다.
파이썬 예제
1. 파일을 Base64로 인코딩하여 텍스트 파일로 출력
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 | import base64 # 파일 경로 file_path = '파일_경로/파일_이름.확장자' # 실제 파일 경로로 수정 output_file_path = '인코딩된_파일.txt' # 저장할 파일명 def encode_file_to_base64(file_path, output_file_path): try: with open(file_path, 'rb') as file: # 파일을 읽어들여 Base64로 인코딩 encoded_content = base64.b64encode(file.read()) # Base64를 텍스트 파일로 저장 with open(output_file_path, 'w') as output_file: output_file.write(encoded_content.decode('utf-8')) print(f'파일이 {output_file_path}로 성공적으로 인코딩되었습니다.') except FileNotFoundError: print('파일을 찾을 수 없습니다.') except Exception as e: print(f'오류 발생: {e}') # 파일을 Base64로 인코딩하고 텍스트 파일로 저장 encode_file_to_base64(file_path, output_file_path) | cs |
2. 인코딩된 텍스트를 파일로 출력
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 | import base64 # Base64로 인코딩된 텍스트 파일 경로 encoded_file_path = '인코딩된_파일.txt' # 실제 파일 경로로 수정 output_file_path = '복원된_파일.bin' # 이진 파일로 저장할 경로 및 파일명 def decode_base64_to_file(encoded_file_path, output_file_path): try: with open(encoded_file_path, 'r') as encoded_file: # Base64로 인코딩된 파일을 읽음 encoded_content = encoded_file.read() # Base64를 디코딩하여 이진 파일로 저장 with open(output_file_path, 'wb') as output_file: output_file.write(base64.b64decode(encoded_content)) print(f'파일이 {output_file_path}로 성공적으로 디코딩되었습니다.') except FileNotFoundError: print('파일을 찾을 수 없습니다.') except Exception as e: print(f'오류 발생: {e}') # Base64로 인코딩된 텍스트 파일을 디코딩하여 이진 파일로 저장 decode_base64_to_file(encoded_file_path, output_file_path) | cs |
끝!
댓글
댓글 쓰기