编码与加密学习

学习编码、加密方式

编码发展过程

计算机只能处理数字,而且是以二进制形式来存储数据的,在存储前和显示时要进行字符与二进制的转换

ASCII

计算机是美国人发明的,ASCII,即‘美国信息交换标准代码’,是美国人为自己设计的。迄今为止共收录了 128 个字符,包含了基本的拉丁字母(英文字母)、阿拉伯数字(也就是 1234567890)、标点符号(,.!等)、特殊符号(@#$%^&等)以及一些具有控制功能的字符(往往不会显示出来)。

这128个字符占用了一个字节的前7位,最前面的一位统一规定为0

ANSI字符集

ANSI并不是某一种特定的字符编码,而是在不同的系统中,ANSI表示不同的编码

为了扩充ASCII编码,以用于显示本国的语言,不同的国家和地区制定了不同的标准,由此产生了 GB2312, BIG5, JIS 等各自的编码标准;这些使用2个字节来代表一个字符的各种汉字延伸编码方式成为ANSI编码

通常使用 0x000x7f 范围的1 个字节来表示 1 个英文字符。超出此范围的使用0x800xFFFF来编码,即扩展的ASCII编码。

在简体中文Windows操作系统中,ANSI 编码代表 GBK 编码;在繁体中文Windows操作系统中,ANSI编码代表Big5

GB2312和GBK

中国制定了GB2312编码,将中文编了进去,GB 是“国标” 二字的汉语拼音缩写;

由于一个字节能表示的最大整数为255,要表示中文,显然一个字节是不够的,至少需要两个字节,而且还不能与ASCII编码冲突

GB2312是简体中文的字符集

GBK向下与GB2312编码兼容,支持简体中文及繁体中文;GBK,即“国标”“扩展”首字母;

Unicode

但全世界的语言有几百种,各国的编码都不一样;在多语言混合的文本中,会显示乱码

为了解决编码混乱的问题,出现了Unicode编码,它为每种语言中的每个字符设定了统一并且唯一的二进制编码

一般两个字节表示一个字符(偏僻的可能需要四个)

UTF-16 LE是windows上默认的Unicode编码方式

unicode的不同编码类型: \u&#

hello编码成unicode:

hello

你好编码成unicode:

\u4f60\u597d

UTF-8

Unicode 只是一个符号集,它只规定了符号的二进制代码,却没有规定这个二进制代码应该如何存储。

使用unicode编码会带来两个问题:

  • 如何才能区别 Unicode 和 ASCII
  • 如果文本上全都是英文,用Unicode编码比ASCII编码需要多一倍的存储空间

为了解决这个问题,出现了可变长编码UTF-8

UTF-8 是在互联网上使用最广的一种 Unicode 的实现方式

UTF-8的特点是对不同范围的字符使用不同长度的编码;它可以使用1~4个字节表示一个符号,根据不同的符号而变化字节长度。

UTF-8 的编码规则很简单:如果只有一个字节,那么最高的比特位为 0;如果有多个字节,那么第一个字节从最高位开始,连续有几个比特位的值为 1,就使用几个字节编码,剩下的字节均以 10 开头。

具体的表现形式为:

0xxxxxxx:单字节编码形式,这和 ASCII 编码完全一样,因此 UTF-8 是兼容 ASCII 的;
110xxxxx 10xxxxxx:双字节编码形式;
1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式;
11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式。

UTF-8最大的优势是,没有字节序的概念。所以特别适合用于字符串的网络数据传输,不用考虑大小端问题。对于非英文网页(对于我们而言,简单说东亚文字网页),能够避免各种乱码问题。

编码应用实例

将windows默认语言更改了,会发现使用ANSI编码的文本文档出现了乱码,而unicode和utf-8不会出现

在记事本写入英文,发现unicode编码后的字节比utf-8编码后的字节多了一倍

乱码问题:

  • 存文件时乱码:文件内有各个国家的文字,以单一编码格式去保存,则会保存失败,打开时会看到乱码
  • 读文件时乱码:读文件时选择了错误的编码,就会出现乱码

参考:
https://blog.csdn.net/Deft_MKJing/article/details/79460485
https://www.cnblogs.com/weigege2015/p/7583632.html

python字符串的编码与解码

字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。

decode的作用是将其他编码的字符串转换成unicode编码,如str1.decode(‘gb2312’),表示将gb2312编码的字符串转换成unicode编码。

encode的作用是将unicode编码转换成其他编码的字符串,如str2.encode(‘gb2312’),表示将unicode编码的字符串转换成gb2312编码。

在Python3中的字符串类型:

文本字符串类型:

即我们通常定义的str类型的对象。在Python3中,str类型的对象都是Unicode,
因此对于str类型的对象只有encode()方法,没有decode()方法,
(若运行,会报错)。

字节字符串类型:

即bytes类型的对象。对于该类对象,是由str类型对象使用encode()方法产生,
bytes对象可以进行解码过程,从而得到真正的内容。

bytes类型以字节为单位进行操作,而字符串以字符为单位进行操作

示例代码:

1
2
3
4
5
6
7
s = '中文'
s = s.encode('gb2312')
print(s)
print(type(s))
s = s.decode('gb2312')
print(s)
print(type(s))

输出为:

b'\xd6\xd0\xce\xc4'
<class 'bytes'>
中文
<class 'str'>

编码类型与特点

url编码

也称百分号编码:一个字符的ASCII码的16进制再加上百分号

http://%77%77%77%2E%62%61%69%64%75%2E%63%6F%6D/

base编码

base16

base16就是用16(2的4次方)个字符,对二进制数据进行编码的方式

Base16 包含 16 个 16 进制大写数字。索引表:

base32

base32就是用32(2的5次方)个字符,对二进制数据进行编码的方式

Base32 包含 26 个大写字母和 2-7 的数字。索引表:

base36

base36编码,它的编码中包含0~9的数字,加上所有26个字母,不区分大小写,不包含任何标点,所有的字母要不全大写,要不全小写。所以加起来就是

"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"

,或者

'0123456789abcdefghijklmnopqrstuvwxyz'
base58

Base58是用于Bitcoin中使用的一种独特的编码方式,主要用于产生Bitcoin的钱包地址。

Base58不含Base64中的0(数字0)、O(大写字母o)、l(小写字母 L)、I(大写字母i),以及“+”和“/”两个字符。

设计Base58主要的目的是:

避免混淆。在某些字体下,数字0和字母大写O,以及字母大写I和字母小写l会非常相似。
不使用"+"和"/"的原因是非字母或数字的字符串作为帐号较难被接受。
没有标点符号,通常不会被从中间分行。
大部分的软件支持双击选择整个字符串。

采用辗转相除法进行编码

索引表:

base62

26个字母的大小写再加上0-9,一共62个字符。

base64

Base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息;Base64就是一种基于64个可打印字符来表示二进制数据的方法。

base64编码要求把3个8位字节转化为4个6位字节,之后在6位的前面补两个0(对应的十进制最大为63),形成8位一个字节的形式。之后转换为二进制,输出其对应的字符;如果剩下的字符不足3个字节,则用0填充,输出字符使用‘=’,因此编码后输出的文本末尾可能会出现1或2个‘=’

文本:flag

加密后: ZmxhZw==

加密过程

各字符对应的ascii码的二进制:

f - 01100110
l - 01101100
a - 01100001
g - 01100111

1.前3个8位可以转化为4个6位:

011001 100110 110001 100001

在每个6位前补两个0:

00011001 00100110 00110001 00100001

2.最后1个8位用0填充:

01100111 00000000 00000000 

转换为4个6位:

011001 110000 000000 000000

在每个6位前补两个0:

00011001 00110000 00000000 00000000

3.转换后为:

00011001 00100110 00110001 00100001 00011001 00110000 00000000 00000000

其对应的10进制为:

25 38 49 33 25 48 0 0

参照索引表,得到其对应的编码(由于0是补位后得到的,因此转换为=):

Z m x h Z w = =

索引表:

base85

是由Paul E. Rutter为btoa实用程序开发的二进制文本编码形式。通过使用五个ASCII字符来表示四个字节的二进制数据(使编码大小¹/ 4大于原始值,假设每个ASCII字符为8位),它比uuencode或Base64更有效,它使用四个字符来表示三个字节数据的增加(¹/ 3增加,假设每个ASCII字符有8位)。

它的主要现代用途是Adobe的PostScript和可移植文档格式文件格式,以及Git使用的二进制文件的补丁编码。

使用:0–9, A–Z, a–z, 以及23个字符:

!#$%&()*+-;<=>?@^_`{|}~ 

来编码二进制数据。

ascii85

ascii85使用字符33(’!’)至117(’u’)

实体编码

在 HTML 中,某些字符是预留的。不能使用小于号(<)和大于号(>),这是因为浏览器会误认为它们是标签。

如果希望正确地显示预留字符,我们必须在 HTML 源代码中使用字符实体(character entities)。

类型:

&lt; <
&nbsp; 空格
&gt; >

javascript编码

这类编码可直接放在控制台运行

JSfuck编码

类型:

[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])
escape()编码

escape 方法返回一个包含了 charstring 内容的字符串值( Unicode 格式)。所有空格、标点、重音符号以及 其他非 ASCII 字符都用 %xx 编码代替,其中 xx 等于表示该字符的十六进制数。例如,空格返回的是“%20 ” 。字符值大于 255 的以 %uxxxx 格式存储。

文本: The

编码后: %u0054%u0068%u0065

解码: 使用unescape()

这种类型的也为escape编码:

\134\170\65\143\134\170\67\65\134\170\63\60\134\170\63\60\
aaencode编码

类型:

(o^_^o))+ (゚ー゚)+ (゚Д゚)[゚ε゚]+((゚ー゚) + (゚Θ゚))+ (c^_^o)+ (゚Д゚)[゚ε゚]+(゚ー゚)

16进制

1.将其两位一组转化为10进制再对照ASCII编码字符即可
636A56355279427363446C4A49454A7154534230526D684356445A31614342354E326C4B4946467A5769426961453067

或:

\x5c\x75\x30\x30\x35\x33\x5c\x75\x30\x30\x37\x34\x5c\x75\x30\x30\x37\x32\x5c\x75\x30\x30\x36\x39\x5c

2.文件内容进行16进制编码

将16进制数据写入文件gg中,使用linux下的xxd命令:

xxd -p -r gg hex

查看hex文件格式:

ubuntu% file hex
hex: python 2.7 byte-compiled

发现是pyc文件,则将其后缀改为pyc,进行反编译即可:

ubuntu% uncompyle6 hex.pyc 

2进制

有两种情况

1.字符串中字符所对应的2进制ascii码
2.字节串

因此拿到二进制字符串,首先应该判断是否能够整除8,如果能整除则为第一种情况,否则尝试用第二种情况,另外可尝试将0和1进行转换

与佛论禅

文本: flag

加密结果: 佛曰:即盡怯輸殿無冥曳盧哆寫侄死梵迦怯伊夷怯蘇諳隸哆婆無

http://www.keyfc.net/bbs/tools/tudoucode.aspx

社会主义核心价值观编码

文本: hello

加密结果: 公正爱国公正平等公正诚信文明公正友善公正公正友善敬业

https://sym233.github.io/core-values-encoder/

Ook编码

Ook! 
Ook.
Ook?

这三种字符串组成

解密:
http://tool.bugku.com/brainfuck/

另:

..... ..... !?!!. ?.... ..... ..... ..... .?.?! .?... .!...

这种类型的也为oOk加密

BrainFuck

这竟然是一种编程语言

+++++ +++++ [->++ +++++ +++<] >++.+ +++++ .<+++ [->-- -<]

由八种字符构成:

盲文

是专为盲人设计、靠触觉感知的文字

https://www.qqxiuzi.cn/bianma/wenbenjiami.php?s=mangwen

加密类型与特点

栅栏加密

把要加密的明文分成N个一组,然后把每组的第1个字连起来,形成一段无规律的话。

文本: helloworld
key: 2

加密过程:

he 
ll 
ow 
or 
ld

加密结果:

hloolelwrd

http://www.zjslove.com/3.decode/zhalan/index.html

凯撒密码

明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。

当偏移量为13,凯撒密码的名称为ROT13

文本: guest
偏移量: 13

加密过程:

g -> t
u -> h
e -> r
s -> f
t -> g

加密结果:

thrfg

http://www.zjslove.com/3.decode/kaisa/index.html

ASCII移位加密

类似于凯撒加密,将字符的ASCII码进行移动一定位数再转换为字符

文本: e6Z9i~]8R~U~QHE{RnY{QXg~QnQ{^XVlRXlp^XI5Q6Q6SKY8jUAA

将ASCII向前偏移四位:

解密: a2V5ezY4NzQzMDAwNjUwMTczMjMwZTRhNThlZTE1M2M2OGU4fQ==
1
2
3
4
5
6
7
8
key = int(input('请输入移动的位数: '))
string = input('请输入待解密的字符串: ')

decodes = ''
for i in string:
i = chr(ord(i)-key)
decodes+=i
print(decodes)

还有一种ASCII移位加密,并不是字符的ASCII码都移动相同的位数,而是按照次序递增或递减

文本: flag
文本的ascii:102 108 97 103

按照1、2、3…的顺序递增偏移

加密后: 103 110 100 107
对应加密文本: gndk
1
2
3
4
5
6
7
8
9
string = input('请输入待解密的字符串: ')

decodes = ''
i = 1
for k in string:
k = chr(ord(k)-i)
decodes+=k
i+=1
print(decodes)

培根密码

加密时,明文中的每个字母都会转换成一组五个英文字母,转换后的五个字母由a、b或a和b组成

文本: hello

加密结果: AABBBAABAAABABBABABBABBBA

索引表:

希尔密码

每个字母当作26进制数字:A=0, B=1, C=2… 一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果MOD26

http://www.practicalcryptography.com/ciphers/hill-cipher/

摩斯密码

摩尔斯电码,过去发电报使用的一种加密方式

..-. .-.. .- --. ----.-- -----.-

摩尔斯电码由两种基本信号组成,点信号‘.’,读‘滴’, 和长信号‘-’,读‘嗒’

另外还有摩尔斯电码与ASCII对照表,因为ASCII字符对应二进制的01,而摩尔斯也是由两种字符.-组成,因此可有以下对应关系:

键盘中心加密

不知道叫什么加密,对照键盘,中心字符的即为解密

文本: r5yG lp9I BjM tFhBT6uh y7iJ QsZ bhM 

解密: tongyuan

银河加密

是一款游戏中使用的字体

仿射加密(affine)

首先了解了一下三等于号(模等于):

https://zhidao.baidu.com/question/30953893.html

加密过程:

1.将字母A-Z转化为对应的数字0-25
2.根据加密函数E(x)=(ax+b) mod 26,计算
3.数字对应的字符即为加密结果

解密过程:

1.求出解密函数D(x);a对应其逆元:

2.将求出的数字对应其字符得到原文本

例如:

E(x) = (5x + 8) mod 26 
则:
D(x) = 21(x - 8) mod 26

参考:

https://www.cnblogs.com/mq0036/p/6544055.html

一道例题及python脚本:

1
2
3
4
5
6
7
# question:y = 17x-8 flag{szzyfimhyzd}

# d = 23(x+8)
string = 'szzyfimhyzd'
for i in string:
i = chr(23*(ord(i)-97+8)%26+97) # 字符要转化为0-25,因此需减去97,转化为字符再加上
print(i,end='')

维吉尼亚密码

Vigenenre密码是最著名的多表代换密码

Vigenenre密码使用一个词组作为密钥,密钥中每一个字母用来确定一个代换表,每一个密钥字母被用来加密一个明文字母,第一个密钥字母加密第一个明文字母,第二个密钥字母加密第二个明文字母,等所有密钥字母使用完后,密钥再次循环使用,于是加解密前需先将明密文按照密钥长度进行分组。密码算法可表示如下:

设密钥K=(k1,k2,…,kd),明文M=(m1,m2,…,mn),密文C=(c1,c2,…,cn);

加密变换为:ci=Eki(mi)=mi+ki(mod 26)

解密变换为:mi=Dki(ci)=ci-ki(mod 26)

注:字母a-z对应0-25

例如:

文本: flag

秘钥: abcd

运算过程:

f - 5
l - 11
a - 0
g - 6

a - 0
b - 1
c - 2
d - 3

5+0 mod 26 = 5 - f
11+1 mod 26 = 12 - m
0+2 mod 26 = 2 - c
6+3 mod 26 = 9 - j

即加密后得到密文:fmcj

拼音九键加密

对照拼音九键的键盘,将字母用坐标表示出来,例如a表示为21