はじめに
はじめまして、普段はctfのcrypto問題を解いたりしているpond-eです
さて、今世の中にはbase64やハフマン符号など色々な符号化手法があります。
自分はctfでcryptoをしているうちに符号化について興味を持って色々調べたところ、baseXX(XXは任意の2の累乗)は実装が比較的簡単で自分の好きなように作れることに気が付きました。そこで、自分だけの符号化手法を作ろうと思ったのです。
この記事で最終的に出来ること
base64で使われる64個の文字を違う文字にすることでオレオレbase64が出来た事とします!
base64の原理
この記事ではbase64を例に説明していきます。base64が分かればbase32やbase128も同じ要領で理解できるのでとりあえずbase64だけ。
base64の変換手順は次のようになります。
- 元データを先頭から6bitずつに分ける(6bitに満たない分は後ろに0を追加して調整)
- 6bitの値を変換表に基づいて4文字ずつ変換
- 4文字に満たないときは後ろに=を追加
変換表は次のようになります。
ビット列 | Base64文字 | ビット列 | Base64文字 | ビット列 | Base64文字 |
---|---|---|---|---|---|
000000 | A | 011011 | b | 111111 | / |
000001 | B | 省略 | 省略 | ||
000010 | C | 110100 | 0 | ||
000011 | D | 110101 | 1 | ||
省略 | 省略 | 省略 | 省略 | ||
011010 | a | 111110 | + |
base64の64は6bitで表現できる文字の数なので(2の6乗)もし、base32とかを作りたかったら手順1.で5bitずつに分けるという感じでやれば出来ます。(実際には手順2.も変える必要があるが省略)
Pythonによるbase64の実装(encodeのみ)
Python 3.10.5 でbase64(encodeのみ)を実装してみました。(雑実装ですみません。。)。ちなみにdecodeはこれを逆実装するだけです。
base = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
text = input('') # ASCIIのみ対応
tmp = 0
result = ''
# 定義からの直感的な処理, 3文字で一周しているのは6(bit)と8(bit)の最大公約数が24(bit)(3文字)であることを利用している.
for i in range(len(text)):
if(i % 3 == 0):
result += base[ord(text[i]) >> 2]
tmp = ord(text[i]) & 0x03
elif(i % 3 == 1):
result += base[tmp*16 + (ord(text[i]) >> 4)]
tmp = ord(text[i]) & 0x0f
elif(i % 3 == 2):
result += base[tmp*4 + (ord(text[i]) >> 6)]
result += base[ord(text[i]) & 0x3f]
tmp = 0
# 文字の末尾部分の処理
if(len(text) % 3 == 1):
tmp = ord(text[-1]) << 4
tmp = tmp & 0x3f
result += base[tmp]
elif(len(text) % 3 == 2):
tmp = ord(text[-1]) << 2
tmp = tmp & 0x3f
result += base[tmp]
# 最後の=についての処理
if(len(result) % 4 == 1):
result += '==='
elif(len(result) % 4 == 2):
result += '=='
elif(len(result) % 4 == 3):
result += '='
print(result)
3文字で1週する様子。赤色は6bitの区切り線。黒色は8bitの区切り線。
base64適用前は3文字なのが適用後は4文字になっているのが分かる。
base64に使う文字を変えてみよう!
文字を変えるだけなら上記のコードのbase変数の中身を変えれば自分専用のbase64を作ることが出来ます!
これで今回のオレオレbase64の実装は終わりです。また機会があれば今度は基数も変えて作ってみたいですね