一、概念
密码学的英语单词是 Cryptograghy,是由希腊单词 Kryptos(隐藏)和 Graphin(写)派生出来的,最初代表的意思是用来隐秘的传递信息。隐藏和写就是隐写,在古典密码学的发展中就有一门称为隐写术的技术,比如说藏头诗就是一种隐写术。隐写术发展到今天演变为数字水印技术,一般在文件中加一个标识信息(即数字水印),可以起到追踪溯源,防伪和版权保护的作用。
密码学一开始的功能是在有恶意攻击者存在的环境下,保护双方通信安全,现在是用来保护信息安全的核心技术。
现代信息安全的基本要求:
- 信息的保密性 Confidentiality:防止信息泄漏给未经授权的人(加密解密技术)
- 信息的完整性 Integrity:防止信息被未经授权的篡改(消息认证码,数字签名)
- 认证性 Authentication:保证信息来自正确的发送者(消息认证码,数字签名)
- 不可否认性 Non-repudiation:保证发送者不能否认他们已发送的消息(数字签名)
加密方法可以分为两大类。一类是单钥加密(private key cryptography),还有一类叫做双钥加密(public key cryptography)。前者的加密和解密过程都用同一套密码,后者的加密和解密过程用的是两套密码。在文章剩下的部分中,我们将带大家了解部分大部分常见的加密方法。
2、密码学常见概念
Hash函数简介
单向散列算法,有时也称为(密码学)哈希算法,其作用主要是能将任意长度的数据给转换成固定长度的无规律散列值,也称为消息摘要或“指纹”,用于验证数据在传输过程中是否发生了篡改,常见的散列算法有MD5、SHA1、SHA256等等。
虽然像CRC32、CRC64这样的哈希算法,也能生成32位或64位的数据摘要,但由于它们不是为密码学领域而设计的,所以它们生成的数据散列值非常容易冲突碰撞,即不同数据生成的散列值相同。
单向散列算法有如下特点:
- 强抗碰撞性,哪怕原数据只改一bit,散列值也会发生很大的变化,要想找到两个散列值一样的对于人类有意义的数据,是非常困难的。
- 单向性,通过数据可以计算出散列值,但通过散列值无法反算出数据。
单向散列算法的用途:
-
由于原数据修改之后,散列值会发生改变,所以MD5等密码学散列算法可用来检测数据是否被篡改。
-
由于像SHA-23等密码学散列算法,它们通常都具有非常强的抗碰撞性,对于人类产生的有意义的不同数据,几乎不可能生成相同的散列值,所以MD5等算法有时也会用来生成数据的唯一标识。
补充
哈希函数的算法中具有代表性的是MD5、SHA-1和SHA-2 等。其中SHA-2 是现在应用较为广泛的一个,而MD5和 SHA-1 因此存在安全隐患,目前不推荐使用。
对称加密
对称加密是加密和解密都使用相同密钥的一种加密方式。由于使用的密钥相同,所以这种算法也被称为“共享密钥加密”。 在对称秘钥加密的体系中,加密和解密使用同一个秘钥,这种方式存在一个显而易见的严重弊端,那就是秘钥的分发和管理,一旦秘钥在分发过程中被人窃取,加密形同虚设。秘钥的管理也相当繁琐,如下图,如果我们要同时与n个人通信,那么每个人都将保存n-1个秘钥。
非对称加密
非对称的存在的意义就是为了克服这些问题,在非对称加密体系中,通信双方各有一个公钥和私钥,加密者使用私钥进行加密,然后传递解密者,解密者使用对方的公钥直接就可以解开,不存在秘钥秘钥传递的问题。由于使用的密钥不同,所以这种算法也被称为“非对称加密”。加密用的密钥叫作“公开密钥”,解密用的叫作“私有密钥”。
消息认证码
消息认证码可以实现“认证”和“检测篡改”这两个功能。密文的内容在传输过程中可能会被篡改,这会导致解密后的内容发生变化,从而产生误会。消息认证码就是可以预防这种情况发生的机制。
数字签名
数字签名不仅可以实现消息认证码的认证和检测篡改功能,还可以预防事后否认问题的发生。由于在消息认证码中使用的是堆成加密,所以持有密钥的收信人也有可能是消息的发送者,这样是无法预防事后否认行为的。而数字签名是只有发信人才能生成的,因此使用它就可以确定谁是消息的发送者了。
数字证书
“对称密钥”和“数字签名”无法保证公开密钥确实来自信息的发送者。因此,就算公开密钥被第三者恶意替换,接收方也不会注意到。所以目前的主流方法主要是使用数字证书技术来确保公开密钥的正确性。
数字证书的基本架构是公开密钥PKI,即利用一对公钥和私钥实施加密和解密。私钥主要用于签名和解密,由用户自定义,只有用户自己知道;公钥用于签名验证和加密,可被多个用户共享。
数字证书的基本工作原理主要体现在:
发送方在发送信息前,需先与接收方联系接受来自接收方的公钥,这时如果公钥是被恶意攻击者串改过的,则发送方发送的数据则有可能被窃取甚至串改,这就需要用到数字证书的技术来证明接收方所发送的公钥是没有被串改过的。
3、加密算法介绍
凯撒移位密码
在密码学中,恺撒密码(英语:Caesar cipher),或称恺撒加密、恺撒变换、变换加密,是一种最简单且最广为人知的加密技术。它是一种替换加密的技术,明文中的所有字母都在字母表上向后(或向前)按照一个固定数目进行偏移后被替换成密文。例如,当偏移量是3的时候,所有的字母A将被替换成D,B变成E,以此类推。这个加密方法是以罗马共和时期恺撒的名字命名的,当年恺撒曾用此方法与其将军们进行联系。
仿射密码
仿射密码为单表加密的一种,字母系统中所有字母都藉一简单数学方程加密,对应至数值,或转回字母。
原理:
- 该密码运用了乘法逆元和模运算
- a~z对应于0~25, 将明文的每个字符转为对应的数字
- 加密函数:D(x) = (a*x+b) (mod 26),这里a,b变量就是密钥,注意 a必须和26互质
- 通过加密函数得到密文的数字,在查表,组合在一起就构成了密文。
- 解密过程与加密类似
- 解密函数: E(x) = a-1(x-b) (mod 26), 这里a-1是a关于26的乘法逆元。
代码实现:
# 列印仿射密码的字母表。# a必须与m互质
def affine(a, b):
for i in range(26):
print chr(i+65) + ": " + chr(((a*i+b)%26)+65)# 调用函数的例子
affine(5, 8)
因为仿射密码仍为单字母表密码, 其依旧保留了该类别加密之弱处。当a=1,仿射加密为凯撒密码,因该加密方程可简化为线性移动。 考虑加密英文。(即:m=26),不计26与凯撒密码,总共有286非易仿射密码。此数值是由于小于26之数中有12数与26互质。a 的每个值可有26互异之加法移动(b之值);因此,共有 12*26 或 312 可能之关键值。 因为密码缺少复杂性,根据柯克霍夫原则,这套系统是不安全的。 此密码之首要弱处为,如果密码学家可发现(如频率分析, 暴力破解, 臆测或任何其他方法) 加密文件两字元之原文,则关键值可透过解一方程组得到。 由于我们知道a及m互质,这个事实可被用于快速破解密码。 仿射密码中同种的转换使用于线性虚拟随机产生器, 为虚拟随机数产生器其中一种。 此产生器不为安全加密虚拟随机数产生器,因仿射密码不安全。
希尔密码
希尔密码是一种运用基本矩阵论原理的有向图密码,由Lester S. Hill在1929年发明。
希尔首先将字母转换为数字(A=0, B=1, C=2...),一串字母当成n维向量,跟一个n×n的矩阵相乘,再将得出的结果模26。
需要注意的是用来加密的密钥矩阵必须是可逆的。
代码实现:
import numpy as np
m = 'YOURPINNOISFOURONETWOSIX' #明文
a = np.matrix([[11,2,19],[5,23,25],[20,7,17]]) #密钥LCTFXZUHR
num_m = []
temp = []
count = 1
for i in m: #将明文分为三个一组
temp.append(ord(i)-ord('A'))
if count % 3 == 0:
num_m.append(temp)
temp = []
count += 1
mat_m = [np.matrix(i).T for i in num_m] #将明文分组转换为向量形式
mat_c = [a * i % 26 for i in mat_m] #得到密文分组的向量形式
num_c = []
temp = []
for i in mat_c: #将密文向量转换为列表形式,且合并到一个列表
temp = i.tolist()
for j in range(3):
num_c.append(temp[j][0])
c = [chr(i+ord('A')) for i in num_c]
print(''.join(c)) #连接成字符串,输出密文
MD5算法
MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由美国密码学家罗纳德·李维斯特(Ronald Linn Rivest)设计,于1992年公开,用以取代MD4算法。这套算法的程序在 RFC 1321 标准中被加以规范。 1996年后该算法被证实存在弱点,可以被加以破解,对于需要高度安全性的数据,专家一般建议改用其他算法,如SHA-2。2004年,证实MD5算法无法防止碰撞(collision),因此不适用于安全性认证,如SSL公开密钥认证或是数字签名等用途。
算法流程:
1、按位补充数据
在MD5算法中,首先需要对信息进行填充,这个数据按位(bit)补充,要求最终的位数对512求模的结果为448。也就是说数据补位后,其位数长度只差64位(bit)就是512的整数倍。即便是这个数据的位数对512求模的结果正好是448也必须进行补位。补位的实现过程:首先在数据后补一个1 bit; 接着在后面补上一堆0 bit, 直到整个数据的位数对512求模的结果正好为448。总之,至少补1位,而最多可能补512位 。
2、扩展长度
在完成补位工作后,又将一个表示数据原始长度的64 bit数(这是对原始数据没有补位前长度的描述,用二进制来表示)补在最后。当完成补位及补充数据的描述后,得到的结果数据长度正好是512的整数倍。也就是说长度正好是16个(32bit) 字的整数倍 。
3、初始化MD缓存器
MD5运算要用到一个128位的MD5缓存器,用来保存中间变量和最终结果。该缓存器又可看成是4个32位的寄存器A、B、C、D,初始化为 : A : 01 23 45 67 B: 89 ab cd ef C: fe dc ba 98 D: 76 54 32 10
4、处理数据段
首先定义4个非线性函数F、G、H、I,对输入的报文运算以512位数据段为单位进行处理。对每个数据段都要进行4轮的逻辑处理,在4轮中分别使用4个不同的函数F、G、H、I。每一轮以ABCD和当前的512位的块为输入,处理后送入ABCD(128位) 。
5、输出
信息摘要最终处理成以A, B, C, D 的形式输出。也就是开始于A的低位在前的顺序字节,结束于D的高位在前的顺序字节。
关于MD5的安全性问题
关于MD5算法不安全的讨论主要源自于王小云院士在2004年发表的一篇论文,而实际上王小云院士在论文中只是否定了MD5的抗碰撞性。
王小云院士的研究成果如下: 即给定消息M1,能够计算获取M2,使得M2产生的散列值与M1产生的散列值相同。并不是说扔给王小云一个MD5散列值,然后她马上就能算出一个原明文M来。
如此,MD5的抗碰撞性就已经不满足了,使得MD5不再是安全的散列算法。这样一来,MD5用于数字签名将存在严重问题,因为可以篡改原始消息,而生成相同的Hash值。
其次,关于MD5破解网站的问题。
由于存储密码的表很容易被窃取,所以以纯文本形式储存密码是非常危险的。因此大多数数据库会储存用户密码的加密摘要。在这种系统内,即使是认证系统本身都无法简单地通过查表来获得用户密码,这就是MD5的常见用途,即敏感信息加密。
黑客在盗取到散列后的密码表时,并不能仅凭借输入散列后的用户的加密摘要来获取权限(使用加密摘要作为输入密码并不可行,因为认证系统会把加密摘要再次进行散列,产生一个与储存的加密摘要不匹配的消息摘要)。为了获取用户的密码,黑客必须找到一个能产生相同加密摘要的密码。
理论上来讲,MD5的明文M是无穷的,但实际而言,用户的可能输入字符组合相对于随机的字符组合来说非常集中,例如,集中在自己的生日,身份证,银行卡号,姓名缩写/大小写等一些信息,换句话说,也就是信息熵其实是很低的。
因此,暴力破解法和字典攻击法是一种破解MD5最为直观且简单的方法,也就是遍历所有可能性尝试,或者通过包含“明文->密文”对应关系的一个大型数据库对其进行攻击。
但是,存储所有的明文密码对需要的空间过大,替代方法是使用预先计算的哈希链表,因此便提出了彩虹表,其比暴力破解使用的时间更少,空间更多;但与储存密码空间中的每一个密码及其对应的哈希值实现的查找表相比,其花费的时间更多,空间更少。
因此,MD5一些的破解网站只是通过查表来确定而已,并不是多么强大的破解技术,只是一个正向破解密码散列值的过程,做不到已知一个MD5值,寻找具有这个值明文字符串。
RSA算法
RSA是使用最广泛的公钥算法,在1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的。当时他们三人都在麻省理工学院工作。RSA就是他们三人姓氏开头字母拼在一起组成。
RAS实际加解密过程很简单,都是对数据进行乘方运算后取模,如下:加密:密文 = 明文 ^ E % N,其中E、N就是两个数字解密:明文 = 密文 ^ D % N,其中D、N就是两个数字其中(E,N)组合在一起为公钥,(D,N)组合在一起为私钥,如下,假设E=5,N=323,D=29,可以发现234经过RSA加密后变成81、RSA解密后还原成了234。
当然E、N、D不是随便得来的数字,它们是根据一系列数学过程计算而来的,有着隐含的数学关系,因此RSA还设计了一套密钥对生成算法,用以生成E、N、D这3个数字。
SHA1哈希算法
SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计,并由美国国家标准技术研究所(NIST)发布为联邦数据处理标准(FIPS)。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。