Base64隐写

原理

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
# -*- coding: utf-8 -*-
import base64
flag = 'flag{Base64isF4n}' #flag
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: #'0.txt'是明文, '1.txt'用于存放隐写后的 base64
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
13
14
15
16
17
d='''str
'''
e=d.splitlines()
binstr=""
base64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
for i in e :
if i.find("==")>0:
temp=bin((base64.find(i[-3])&15))[2:]
#取倒数第3个字符,在base64找到对应的索引数(就是编码数),取低4位,再转换为二进制字符
binstr=binstr + "0"*(4-len(temp))+temp #二进制字符补高位0后,连接字符到binstr
elif i.find("=")>0:
temp=bin((base64.find(i[-2])&3))[2:] #取倒数第2个字符,在base64找到对应的索引数(就是编码数),取低2位,再转换为二进制字符
binstr=binstr + "0"*(2-len(temp))+temp #二进制字符补高位0后,连接字符到binstr
str=""
for i in range(0,len(binstr),8):
str=str+chr(int(binstr[i:i+8],2)) #从左到右,每取8位转换为ascii字符,连接字符到字符串
print(str)