base64 #
编码 #
Base64是一种基于64个可打印字符来表示二进制数据的表示方法,主要用途是将不可见字符变为可打印字符
64个可打印字符依次为A-Za-z0-9+/
,可用6bit二进制数作为索引映射这64个字符,对应编码见下表
编码例子
base64(Man) = TWFu
我们经常会遇到base64编码结果中有
=
的情况,为什么会有=
?如果需要表示上面的64个字符,那么需要6bit(2^6=64)
base64的核心思想就是,将3个字节(3*8=24bit)拆分成4个6bit,然后使用每个6bit的值作为索引映射对应64个字符,也即是每3个字节最终结果将变成4个字符(字节)
但如果原始字符串长度不是3的倍数,则对应的二进制位数不是6的倍数,需要在末尾用0填充:
- 若剩1个字符则末尾填充4个0(补足了
1*8+4=2*6=12bit
),并在编码结果后加2个=
- 若剩2个字符则末尾填充2个0(补足了
2*8+2=3*6=18bit
),并在编码结果后加1个=
隐写 #
base64也可以隐写,主要工作原理是利用上述padding的补齐机制:上述末尾填充的0,会在解码时被丢弃,不对还原原始数据产生影响
可以看出一串base64的编码最多也 只有4bit 的隐写空间,所以实现隐写往往需要大量base64编码串
隐写时把隐写数据的每个字符用8位二进制数表示,由此将整个明文串转为bit串,按顺序填入base64编码串的可隐写位中即可实现隐写
如下base64decode的数据为
I have had my invitation to this$world's festival,$and thus$my$life has$been blessed.
Early in the day it was whispered that we should sail in a boat,only thou and I,and never a soul in the world would know of this our pilgrimage to no country and to no end.
In the meanwhile I smile and I sing all alone. In the meanwhile the air is filling with the perfume of promise.The time that my journey takes is long and the way of it long.
I came out on the chariot of the first gleam of light,and pursued'my'voyage througiçthe wildernesses of worlds'leaving my track on many a'star and'planet.Give me the strength lightly to bear my joys and sorrows.Give me the strength to make my love fruitful in service.
Give me the$strengti$never$to$disown the poor or bend$my$knees$before insolent might.
Give me the strength to raise my mind high above daily trifles.And give me the strength to surrender my strength to thy will with love.
If the day is done,if birds sing no more,if the wind has flagged tired, then draw the veil of darkness thick upon me,even as thou hast wrapt the earth with the coverlet of sleep and tenderly closed the petals of the drooping lotus at dusk.
From the traveller,whose sack of rrovisions is empty before the voyage is ended, whose garment is torn and dustladen,whose strength is exhausted,remove shame and poverty,and renew his life like a flower under the cover of thy kindly night.
When grace is lost from life, come with a burst of song.
I know that the day will come when my sight of this earth shall be lost,and life%will take its leave in silence, drawing the last curtain%over my eyes.
Yet stars will watch at night,and morning rise as before,and hours heave like sea waves casting up pleasures and pains.
When I think of this end of my moments,the barrier of the moments breaks and I see by the light of death thy world with its careless treasures.Rare is its lowliest seat,rare is its meanest of lives.
Things that I longed for in vain and things that I got---let them pass.Let me but truly possess the things that I ever spurned and overlooked.
----Excerpt from Tagore &Gitanjali"
隐写的数据为Gitanjali
SSBoYXZlIGhhZCBteSBpbnZpdGF0aW9uIHRvIHRoaXMkd29ybGQncyBmZXN0aXZhbCwkYW5kIHRodXMkbXkkbGlmZSBoYXMkYmVlbiBibGVzc2VkLk==
RWFybHkgaW4gdGhlIGRheSBpdCB3YXMgd2hpc3BlcmVkIHRoYXQgd2Ugc2hvdWxkIHNhaWwgaW4gYSBib2F0LH==
b25seSB0aG91IGFuZCBJLG==
YW5kIG5ldmVyIGEgc291bCBpbiB0aGUgd29ybGQgd291bGQga25vdyBvZiB0aGlzIG91ciBwaWxncmltYWdlIHRvIG5vIGNvdW50cnkgYW5kIHRvIG5vIGVuZC6=
SW4gdGhlIG1lYW53aGlsZSBJIHNtaWxlIGFuZCBJIHNpbmcgYWxsIGFsb25lLiBJbiB0aGUgbWVhbndoaWxlIHRoZSBhaXIgaXMgZmlsbGluZyB3aXRoIHRoZSBwZXJmdW1lIG9mIHByb21pc2Uu
VGhlIHRpbWUgdGhhdCBteSBqb3VybmV5IHRha2VzIGlzIGxvbmcgYW5kIHRoZSB3YXkgb2YgaXQgbG9uZy5=
SSBjYW1lIG91dCBvbiB0aGUgY2hhcmlvdCBvZiB0aGUgZmlyc3QgZ2xlYW0gb2YgbGlnaHQs
YW5kIHB1cnN1ZWQnbXkndm95YWdlIHRocm91Z2nndGhlIHdpbGRlcm5lc3NlcyBvZiB3b3JsZHMnbGVhdmluZyBteSB0cmFjayBvbiBtYW55IGEnc3RhciBhbmQncGxhbmV0Ln==
R2l2ZSBtZSB0aGUgc3RyZW5ndGggbGlnaHRseSB0byBiZWFyIG15IGpveXMgYW5kIHNvcnJvd3Mu
R2l2ZSBtZSB0aGUgc3RyZW5ndGggdG8gbWFrZSBteSBsb3ZlIGZydWl0ZnVsIGluIHNlcnZpY2Uu
R2l2ZSBtZSB0aGUkc3RyZW5ndGkkbmV2ZXIkdG8kZGlzb3duIHRoZSBwb29yIG9yIGJlbmQkbXkka25lZXMkYmVmb3JlIGluc29sZW50IG1pZ2h0Lk==
R2l2ZSBtZSB0aGUgc3RyZW5ndGggdG8gcmFpc2UgbXkgbWluZCBoaWdoIGFib3ZlIGRhaWx5IHRyaWZsZXMu
QW5kIGdpdmUgbWUgdGhlIHN0cmVuZ3RoIHRvIHN1cnJlbmRlciBteSBzdHJlbmd0aCB0byB0aHkgd2lsbCB3aXRoIGxvdmUu
SWYgdGhlIGRheSBpcyBkb25lLG==
aWYgYmlyZHMgc2luZyBubyBtb3JlLB==
aWYgdGhlIHdpbmQgaGFzIGZsYWdnZWQgdGlyZWQsIHRoZW4gZHJhdyB0aGUgdmVpbCBvZiBkYXJrbmVzcyB0aGljayB1cG9uIG1lLG==
ZXZlbiBhcyB0aG91IGhhc3Qgd3JhcHQgdGhlIGVhcnRoIHdpdGggdGhlIGNvdmVybGV0IG9mIHNsZWVwIGFuZCB0ZW5kZXJseSBjbG9zZWQgdGhlIHBldGFscyBvZiB0aGUgZHJvb3BpbmcgbG90dXMgYXQgZHVzay7=
RnJvbSB0aGUgdHJhdmVsbGVyLJ==
d2hvc2Ugc2FjayBvZiBycm92aXNpb25zIGlzIGVtcHR5IGJlZm9yZSB0aGUgdm95YWdlIGlzIGVuZGVkLCB3aG9zZSBnYXJtZW50IGlzIHRvcm4gYW5kIGR1c3RsYWRlbiy=
d2hvc2Ugc3RyZW5ndGggaXMgZXhoYXVzdGVkLK==
cmVtb3ZlIHNoYW1lIGFuZCBwb3ZlcnR5LG==
YW5kIHJlbmV3IGhpcyBsaWZlIGxpa2UgYSBmbG93ZXIgdW5kZXIgdGhlIGNvdmVyIG9mIHRoeSBraW5kbHkgbmlnaHQu
V2hlbiBncmFjZSBpcyBsb3N0IGZyb20gbGlmZSwgY29tZSB3aXRoIGEgYnVyc3Qgb2Ygc29uZy4=
SSBrbm93IHRoYXQgdGhlIGRheSB3aWxsIGNvbWUgd2hlbiBteSBzaWdodCBvZiB0aGlzIGVhcnRoIHNoYWxsIGJlIGxvc3Qs
YW5kIGxpZmUld2lsbCB0YWtlIGl0cyBsZWF2ZSBpbiBzaWxlbmNlLCBkcmF3aW5nIHRoZSBsYXN0IGN1cnRhaW4lb3ZlciBteSBleWVzLl==
WWV0IHN0YXJzIHdpbGwgd2F0Y2ggYXQgbmlnaHQs
YW5kIG1vcm5pbmcgcmlzZSBhcyBiZWZvcmUs
YW5kIGhvdXJzIGhlYXZlIGxpa2Ugc2VhIHdhdmVzIGNhc3RpbmcgdXAgcGxlYXN1cmVzIGFuZCBwYWlucy6=
V2hlbiBJIHRoaW5rIG9mIHRoaXMgZW5kIG9mIG15IG1vbWVudHMs
dGhlIGJhcnJpZXIgb2YgdGhlIG1vbWVudHMgYnJlYWtzIGFuZCBJIHNlZSBieSB0aGUgbGlnaHQgb2YgZGVhdGggdGh5IHdvcmxkIHdpdGggaXRzIGNhcmVsZXNzIHRyZWFzdXJlcy7=
UmFyZSBpcyBpdHMgbG93bGllc3Qgc2VhdCw=
cmFyZSBpcyBpdHMgbWVhbmVzdCBvZiBsaXZlcy5=
VGhpbmdzIHRoYXQgSSBsb25nZWQgZm9yIGluIHZhaW6gYW5kIHRoaW5ncyB0aGF0IEkgZ290LS0tbGV0IHRoZW0gcGFzcy6=
TGV0IG1lIGJ1dCB0cnVseSBwb3NzZXNzIHRoZSB0aGluZ3MgdGhhdCBJIGV2ZXIgc3B1cm5lZCBhbmQgb3Zlcmxvb2tlZC6=
LS0tLUV4Y2VycHQgZnJvbSBUYWdvcmUgJkdpdGFuamFsaSJ=
import re
path = './stego.txt'
b64char = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
with open(path, 'r')as f:
cipher = [i.strip() for i in f.readlines()]
plaintext = ''
for i in cipher:
if i[-2] == '=': # There are 4-bit hidden info while end with two '='
bin_message = bin(b64char.index(i[-3]))[2:].zfill(4)
plaintext += bin_message[-4:]
elif i[-1] == '=': # There are 2-bit hidden info while end with one '='
bin_message = bin(b64char.index(i[-2]))[2:].zfill(2)
plaintext += bin_message[-2:]
plaintext = re.findall('.{8}', plaintext) # 8bits/group
plaintext = ''.join([chr(int(i,2)) for i in plaintext])
print(plaintext)
https://cltheorem.github.io/2018/10/base64%E9%9A%90%E5%86%99/