[文字コード] Base64
Base64
データを64種類の英数字を用い, それ以外の文字を扱うことのできない環境にてマルチバイト文字やバイナリデータを扱うためのエンコーディング方式である.
RFC 2045の6.8項で定義されている.
使用できる文字は, A - Z
, a - z
, 0 - 9
, +
, /
の64文字とパディング用の記号=
の計65文字である.
MIMEによって規定されており, 7ビットのデータしか扱うことのできない電子メールにて広く利用されている.
Base64で変換されたデータは元データの4/3(約133%)となる.
また, MIMEでは76文字毎に改行コードが入る仕様のため, この2バイト分を含めると元データの約137%となる.
生まれた経緯
現在では拡張機能により8bit以上のマルチバイト文字やバイナリデータも送ることが可能だが, かつてはASCII文字で表現できる文字しか送ることができなかった.
そこで, メール上で様々なフォーマットを扱えるようにするMIME(Multipurpose Internet Mail Extensions)という規格が規定され, その中でBase64というエンコーディング方式が定義された.
今日では, JSONで特殊文字を含まないように画像データをエンコードしたり, Webページを表示する際にリクエスト数を減らすためにBase64でエンコードした画像をHTMLに埋め込むなどの用途で用いられている.
変換表
数値と文字の対応を以下に示す.
10進数 | 2進数 | 文字 | 10進数 | 2進数 | 文字 | 10進数 | 2進数 | 文字 | 10進数 | 2進数 | 文字 |
---|---|---|---|---|---|---|---|---|---|---|---|
0 | 000000 | A | 16 | 010000 | Q | 32 | 100000 | g | 48 | 110000 | w |
1 | 000001 | B | 17 | 010001 | R | 33 | 100001 | h | 49 | 110001 | x |
2 | 000010 | C | 18 | 010010 | S | 34 | 100010 | i | 50 | 110010 | y |
3 | 000011 | D | 19 | 010011 | T | 35 | 100011 | j | 51 | 110011 | z |
4 | 000100 | E | 20 | 010100 | U | 36 | 100100 | k | 52 | 110100 | 0 |
5 | 000101 | F | 21 | 010101 | V | 37 | 100101 | l | 53 | 110101 | 1 |
6 | 000110 | G | 22 | 010110 | W | 38 | 100110 | m | 54 | 110110 | 2 |
7 | 000111 | H | 23 | 010111 | X | 39 | 100111 | n | 55 | 110111 | 3 |
8 | 001000 | I | 24 | 011000 | Y | 40 | 101000 | o | 56 | 111000 | 4 |
9 | 001001 | J | 25 | 011001 | Z | 41 | 101001 | p | 57 | 111001 | 5 |
10 | 001010 | K | 26 | 011010 | a | 42 | 101010 | q | 58 | 111010 | 6 |
11 | 001011 | L | 27 | 011011 | b | 43 | 101011 | r | 59 | 111011 | 7 |
12 | 001100 | M | 28 | 011100 | c | 44 | 101100 | s | 60 | 111100 | 8 |
13 | 001101 | N | 29 | 011101 | d | 45 | 101101 | t | 61 | 111101 | 9 |
14 | 001110 | O | 30 | 011110 | e | 46 | 101110 | u | 62 | 111110 | + |
15 | 001111 | P | 31 | 011111 | f | 47 | 101111 | v | 63 | 111111 | / |
変換アルゴリズム
文字列ABCDEFG
を例にエンコードを行う.
1. 2進数に変換
元データ | 16進数表現 | 2進数表現 |
---|---|---|
A | 0041 | 01000001 |
B | 0042 | 01000010 |
C | 0043 | 01000011 |
D | 0044 | 01000100 |
E | +0045 | 01000101 |
F | 0046 | 01000110 |
G | 0047 | 01000111 |
2. 6bitずつに分割
010000
010100
001001
000011
010001
000100
010101
000110
010001
11
3. ゼロパディング
最後の2bitが余っているので, 0
でパディングする.
010000
010100
001001
000011
010001
000100
010101
000110
010001
110000
4. 文字に変換
変換表を参考に4文字ずつ変換する.
QUJD
REVG
Rw
5. パディング
2文字余っているので, =
でパディングする.
QUJD
REVG
Rw==
6. 繋げる
QUJDREVGRw==
Python3による実装
変換表(JSON形式)
{ "000000": "A", "000001": "B", "000010": "C", "000011": "D", "000100": "E", "000101": "F", "000110": "G", "000111": "H", "001000": "I", "001001": "J", "001010": "K", "001011": "L", "001100": "M", "001101": "N", "001110": "O", "001111": "P", "010000": "Q", "010001": "R", "010010": "S", "010011": "T", "010100": "U", "010101": "V", "010110": "W", "010111": "X", "011000": "Y", "011001": "Z", "011010": "a", "011011": "b", "011100": "c", "011101": "d", "011110": "e", "011111": "f", "100000": "g", "100001": "h", "100010": "i", "100011": "j", "100100": "k", "100101": "l", "100110": "m", "100111": "n", "101000": "o", "101001": "p", "101010": "q", "101011": "r", "101100": "s", "101101": "t", "101110": "u", "101111": "v", "110000": "w", "110001": "x", "110010": "y", "110011": "z", "110100": "0", "110101": "1", "110110": "2", "110111": "3", "111000": "4", "111001": "5", "111010": "6", "111011": "7", "111100": "8", "111101": "9", "111110": "+", "111111": "/" }
Base64(Python3)
#!/usr/bin/env python import sys import json # 2進数に変換 def str_to_bin(str): bin = '' for char in str: bin += format(ord(char), 'b').zfill(8) return bin # 6bitずつに分割 def split(bin, split_cnt): split_bin = [bin[i: i + split_cnt] for i in range(0, len(bin), split_cnt)] return split_bin # ゼロパディング def zero_padding(split_bin, padding_interval): for i in range(padding_interval - 1): if len(split_bin) >= padding_interval: break split_bin += '0' return split_bin # '='でパディング def equal_padding(base64, padding_interval): padding_num = len(base64) % padding_interval for i in range(padding_num): base64 += '=' return base64 def main(): # コマンドライン引数を受け取る argvs = sys.argv argc = len(argvs) # 引数が1つでなければ処理を行わず終了 if argc != 2: print('usage: python %s STRING' %argvs[0]) sys.exit() # 2進数に変換 bin = str_to_bin(argvs[1]) # 6bitずつに分割 split_cnt = 6 split_bin = split(bin, split_cnt) # ゼロパディング split_bin[-1] = zero_padding(split_bin[-1], 6) # 変換表の読み込み base64_table = json.loads(open('base64_table.json', 'r').read()) # 文字に変換 base64 = '' for i in split_bin: base64 += base64_table[i] # '='でパディング base64 = equal_padding(base64, 4) # 出力 print(base64) if __name__ == '__main__': main()
実行
$ python base64.py ABCDEFG
実行結果
QUJDREVGRw==