Base64 모듈
Base64 모듈
Base64 모듈은 다음을 위한 메서드를 제공해요.
- 비-ASCII 문자를 포함한 바이너리 문자열을 출력 가능한 ASCII 문자열로 인코딩.
- 그렇게 인코딩된 문자열을 디코딩.
Base64는 바이너리 데이터가 허용되지 않거나 지원되지 않는 상황에서 흔히 쓰여요.
- HTML·CSS 파일 또는 URL 안의 이미지.
- 이메일 첨부 파일.
Base64 인코딩 문자열은 원본보다 약 1/3 더 길어요. 이 모듈은 인코딩·디코딩 메서드 쌍을 세 개 제공해요.
- 인코딩·디코딩에 어떤 문자 집합을 쓸지.
- "패딩(padding)"을 쓸지 여부.
- 인코딩 문자열에 개행 문자가 들어갈지 여부.
출처: Ruby 3.3 API
본문
이 페이지의 예시는 포함 프로그램이 다음을 실행했다고 가정해요.
require 'base64'
인코딩 문자 집합 (Encoding Character Sets)
Base64 인코딩 문자열은 64개 문자 집합으로만 구성돼요.
-
('A'..'Z'). -
('a'..'z'). -
('0'..'9'). -
=, '패딩' 문자. -
%w[+ /]: RFC-2045 준수, URL에는 안전하지 않음. -
%w[- _]: RFC-4648 준수, URL에 안전.
URL에 넣거나 URL에서 가져올 Base64 문자열을 다룬다면 RFC-4648 준수 쌍인 Base64.urlsafe_encode64 와 Base64.urlsafe_decode64를 선택해야 해요. 그 외에는 이 모듈의 어떤 쌍이라도 골라도 돼요. RFC-2045 준수 쌍은 Base64.encode64/Base64.decode64, Base64.strict_encode64/Base64.strict_decode64예요.
패딩 (Padding)
Base64 인코딩은 입력 바이트 3개(triplet)를 출력 문자 4개(quartet)로 바꿔요.
인코드 메서드의 패딩 — 패딩(인코딩 문자열을 뒤에 = 0~2개로 늘리는 것)은 Base64.encode64, Base64.strict_encode64, 그리고 기본적으로 Base64.urlsafe_encode64가 수행해요.
Base64.encode64('s') # => "cw==\n"
Base64.strict_encode64('s') # => "cw=="
Base64.urlsafe_encode64('s') # => "cw=="
Base64.urlsafe_encode64('s', padding: false) # => "cw"
패딩을 적용하면 인코딩 문자열은 항상 길이가 4n이 돼요(n은 0 이상 정수).
# n = 1: 3 bytes => 4 characters.
Base64.strict_encode64('123') # => "MDEy"
# n = 2: 6 bytes => 8 characters.
Base64.strict_encode64('123456') # => "MDEyMzQ1"
- 길이
3n의 입력 바이트는 길이4n의 패딩 없는 출력 문자를 생성해요.# n = 1: 4 bytes => 8 characters. Base64.strict_encode64('1234') # => "MDEyMw==" # n = 2: 7 bytes => 12 characters. Base64.strict_encode64('1234567') # => "MDEyMzQ1Ng==" - 길이
3n+1의 입력 바이트는 끝에 패딩 문자 2개를 가진 길이4(n+1)의 패딩 출력 문자를 생성해요.# n = 1: 5 bytes => 8 characters. Base64.strict_encode64('12345') # => "MDEyMzQ=" # n = 2: 8 bytes => 12 characters. Base64.strict_encode64('12345678') # => "MDEyMzQ1Njc=" - 길이
3n+2의 입력 바이트는 끝에 패딩 문자 1개를 가진 길이4(n+1)의 패딩 출력 문자를 생성해요.
패딩을 억제하면, 양의 정수 n에 대해:
# n = 1: 3 bytes => 4 characters.
Base64.urlsafe_encode64('123', padding: false) # => "MDEy"
# n = 2: 6 bytes => 8 characters.
Base64.urlsafe_encode64('123456', padding: false) # => "MDEyMzQ1"
- 길이
3n의 입력 바이트는 길이4n의 패딩 없는 출력 문자를 생성해요.# n = 1: 4 bytes => 6 characters. Base64.urlsafe_encode64('1234', padding: false) # => "MDEyMw" # n = 2: 7 bytes => 10 characters. Base64.urlsafe_encode64('1234567', padding: false) # => "MDEyMzQ1Ng" - 길이
3n+1의 입력 바이트는 끝에 패딩 문자 2개를 가진 길이4n+2의 패딩 없는 출력 문자를 생성해요.# n = 1: 5 bytes => 7 characters. Base64.urlsafe_encode64('12345', padding: false) # => "MDEyMzQ" # m = 2: 8 bytes => 11 characters. Base64.urlsafe_encode64('12345678', padding: false) # => "MDEyMzQ1Njc" - 길이
3n+2의 입력 바이트는 끝에 패딩 문자 1개를 가진 길이4n+3의 패딩 없는 출력 문자를 생성해요.
디코드 메서드의 패딩 — Base64 디코드 메서드는 모두 패딩을 지원하지만(필수는 아님) 그래요. Base64.decode64는 패딩 크기를 검사하지 않아요.
Base64.decode64("MDEyMzQ1Njc") # => "01234567"
Base64.decode64("MDEyMzQ1Njc=") # => "01234567"
Base64.decode64("MDEyMzQ1Njc==") # => "01234567"
Base64.strict_decode64는 패딩 크기를 엄격히 강제해요.
Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError
Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567"
Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError
Base64.urlsafe_decode64는 str의 패딩을 허용하는데, 있으면 반드시 맞아야 해요.
Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567"
Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567"
Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError.
개행 (Newlines)
Base64.encode64 또는 Base64.urlsafe_encode64가 반환한 인코딩 문자열은 60문자 시퀀스마다 개행 문자가 내장돼 있고, 비어 있지 않다면 끝에도 하나 있어요.
# No newline if empty.
encoded = Base64.encode64("\x00" * 0)
encoded.index("\n") # => nil
# Newline at end of short output.
encoded = Base64.encode64("\x00" * 1)
encoded.size # => 4
encoded.index("\n") # => 4
# Newline at end of longer output.
encoded = Base64.encode64("\x00" * 45)
encoded.size # => 60
encoded.index("\n") # => 60
# Newlines embedded and at end of still longer output.
encoded = Base64.encode64("\x00" * 46)
encoded.size # => 65
encoded.rindex("\n") # => 65
encoded.split("\n").map {|s| s.size } # => [60, 4]
인코딩할 문자열 자체에 개행이 있어도 Base64로 인코딩돼요.
# Base64.encode64("\n\n\n") # => "CgoK\n"
s = "This is line 1\nThis is line 2\n"
Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n"
Public Instance Methods
decode64(str)
RFC-2045 준수 Base64 인코딩 문자열 str을 디코딩한 문자열을 반환해요.
s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n"
Base64.decode64(s) # => "This is line 1\nThis is line 2\n"
str의 비-Base64 문자는 무시돼요. 개행 문자, -, /가 여기 해당돼요.
Base64.decode64("\x00\n-_") # => ""
str의 패딩은 (틀려도) 무시돼요.
Base64.decode64("MDEyMzQ1Njc") # => "01234567"
Base64.decode64("MDEyMzQ1Njc=") # => "01234567"
Base64.decode64("MDEyMzQ1Njc==") # => "01234567"
# File lib/base64.rb, line 241
def decode64(str)
str.unpack1("m")
end
encode64(bin)
bin을 RFC-2045 준수 Base64 인코딩한 문자열을 반환해요.
RFC 2045에 따라 반환 문자열은 URL에 안전하지 않은 + 또는 / 문자를 포함할 수 있어요.
Base64.encode64("\xFB\xEF\xBE") # => "++++\n"
Base64.encode64("\xFF\xFF\xFF") # => "////\n"
반환 문자열은 패딩을 포함할 수 있어요.
Base64.encode64('*') # => "Kg==\n"
반환 문자열은 개행 문자로 끝나고, 충분히 길면 내장 개행 문자가 하나 이상 있을 수도 있어요.
Base64.encode64('*') # => "Kg==\n"
Base64.encode64('*' * 46)
# => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioq\nKg==\n"
인코딩할 문자열 자체에 개행이 있어도 일반 Base64로 인코딩돼요.
Base64.encode64("\n\n\n") # => "CgoK\n"
s = "This is line 1\nThis is line 2\n"
Base64.encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK\n"
# File lib/base64.rb, line 219
def encode64(bin)
[bin].pack("m")
end
strict_decode64(str)
RFC-2045 준수 Base64 인코딩 문자열 str을 디코딩한 문자열을 반환해요.
s = "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK"
Base64.strict_decode64(s) # => "This is line 1\nThis is line 2\n"
str의 비-Base64 문자는 허용되지 않아요. 개행 문자, -, /가 여기 해당돼요.
Base64.strict_decode64("\n") # Raises ArgumentError
Base64.strict_decode64('-') # Raises ArgumentError
Base64.strict_decode64('_') # Raises ArgumentError
str의 패딩은 있으면 반드시 맞아야 해요.
Base64.strict_decode64("MDEyMzQ1Njc") # Raises ArgumentError
Base64.strict_decode64("MDEyMzQ1Njc=") # => "01234567"
Base64.strict_decode64("MDEyMzQ1Njc==") # Raises ArgumentError
# File lib/base64.rb, line 297
def strict_decode64(str)
str.unpack1("m0")
end
strict_encode64(bin)
bin을 RFC-2045 준수 Base64 인코딩한 문자열을 반환해요.
RFC 2045에 따라 반환 문자열은 URL에 안전하지 않은 + 또는 / 문자를 포함할 수 있어요.
Base64.strict_encode64("\xFB\xEF\xBE") # => "++++"
Base64.strict_encode64("\xFF\xFF\xFF") # => "////"
반환 문자열은 패딩을 포함할 수 있어요.
Base64.strict_encode64('*') # => "Kg=="
반환 문자열은 길이와 무관하게 개행 문자를 갖지 않아요.
Base64.strict_encode64('*') # => "Kg=="
Base64.strict_encode64('*' * 46)
# => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg=="
인코딩할 문자열 자체에 개행이 있어도 일반 Base64로 인코딩돼요.
Base64.strict_encode64("\n\n\n") # => "CgoK"
s = "This is line 1\nThis is line 2\n"
Base64.strict_encode64(s) # => "VGhpcyBpcyBsaW5lIDEKVGhpcyBpcyBsaW5lIDIK"
# File lib/base64.rb, line 273
def strict_encode64(bin)
[bin].pack("m0")
end
urlsafe_decode64(str)
RFC-4648 준수 Base64 인코딩 문자열 str을 디코딩한 값을 반환해요.
str은 비-Base64 문자를 포함할 수 없어요.
Base64.urlsafe_decode64('+') # Raises ArgumentError.
Base64.urlsafe_decode64('/') # Raises ArgumentError.
Base64.urlsafe_decode64("\n") # Raises ArgumentError.
str의 패딩은 있으면 반드시 맞아야 해요.
Base64.urlsafe_decode64("MDEyMzQ1Njc") # => "01234567"
Base64.urlsafe_decode64("MDEyMzQ1Njc=") # => "01234567"
Base64.urlsafe_decode64("MDEyMzQ1Njc==") # Raises ArgumentError.
# File lib/base64.rb, line 351
def urlsafe_decode64(str)
# NOTE: RFC 4648 does say nothing about unpadded input, but says that
# "the excess pad characters MAY also be ignored", so it is inferred that
# unpadded input is also acceptable.
if !str.end_with?("=") && str.length % 4 != 0
str = str.ljust((str.length + 3) & ~3, "=")
str.tr!("-_", "+/")
else
str = str.tr("-_", "+/")
end
strict_decode64(str)
end
urlsafe_encode64(bin, padding: true)
bin을 RFC-4648 준수 Base64 인코딩한 값을 반환해요.
RFC 4648에 따라 반환 문자열은 URL에 안전하지 않은 + 또는 /를 포함하지 않고, 그 대신 URL에 안전한 -와 _를 포함할 수 있어요.
Base64.urlsafe_encode64("\xFB\xEF\xBE") # => "----"
Base64.urlsafe_encode64("\xFF\xFF\xFF") # => "____"
기본적으로 반환 문자열은 패딩을 가질 수 있어요.
Base64.urlsafe_encode64('*') # => "Kg=="
선택적으로 패딩을 억제할 수 있어요.
Base64.urlsafe_encode64('*', padding: false) # => "Kg"
반환 문자열은 길이와 무관하게 개행 문자를 갖지 않아요.
Base64.urlsafe_encode64('*') # => "Kg=="
Base64.urlsafe_encode64('*' * 46)
# => "KioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKg=="
# File lib/base64.rb, line 328
def urlsafe_encode64(bin, padding: true)
str = strict_encode64(bin)
str.chomp!("==") or str.chomp!("=") unless padding
str.tr!("+/", "-_")
str
end