原理
Base64的编码过程就是将文本字符对应成二进制后,再六个一组对应成索引,转为编码字符。如果字符串长度不是3的 倍数,则对应的二进制位数不是6的倍数,需要在末尾用0填充。若剩1个字符则在编码结果后加2个‘=’;若剩2个字符则 加1个‘=’。
Base64的解码过程,即先丢弃编码后面的‘=’,然后将每个base64字符对应索引转为6bit的二进制数,再8个一组转为ASCII码字符完成解码,最后若剩下不足8位的,则全部丢弃。
所以某些bit位在解码时会被丢弃,换句话说,这些bit值不会对解码结果产生影响。一个简单直观的例子就是QUJDRA和QUJDRC解码后都是ABCD。由此我们便可以将隐藏信息插入这些bit位中实现隐写。
一串Base64的编码最多也只有4bit的隐写空间,所以实现隐写往往需要大量编码串。隐写时把明文的每个字符用8位二进制数表示,由此将整个明文串转为bit串,按顺序填入Base64编码串的可隐写位中即可实现隐写。
加密
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import base64 flag = 'flag{Base64isF4n}' bin_str = ''.join([bin(ord(c)).replace('0b', '').zfill(8) for c in flag]) base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' with open('0.txt', 'rb') as f0, open('1.txt', 'wb') as f1: for line in f0.readlines(): rowstr = base64.b64encode(line.replace('\n', '')) equalnum = rowstr.count('=') if equalnum and len(bin_str): offset = int('0b'+bin_str[:equalnum * 2], 2) char = rowstr[len(rowstr) - equalnum - 1] rowstr = rowstr.replace(char, base64chars[base64chars.index(char) + offset]) bin_str = bin_str[equalnum*2:] f1.write(rowstr + '\n')
|
解密
1 2 3 4 5 6 7 8 9 10 11 12
| b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' with open('1.txt', 'rb') as f: bin_str = '' for line in f.readlines(): stegb64 = ''.join(line.split()) rowb64 = ''.join(stegb64.decode('base64').encode('base64').split()) offset = abs(b64chars.index(stegb64.replace('=','')[-1])-b64chars.index(rowb64.replace('=','')[-1])) equalnum = stegb64.count('=') if equalnum: bin_str += bin(offset)[2:].zfill(equalnum * 2) print(''.join([chr(int(bin_str[i:i + 8], 2)) for i in xrange(0, len(bin_str), 8)]))
|