Hash,通常翻译作“散列”,也有直接音译为”哈希”的,就是把任意长度的输入(又叫作预映射,pre-image),经过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间一般远小于输入的空间,不一样的输入可能会散列成相同的输出,而不可能从散列值来惟一的肯定输入值。python
摘要算法又称为哈希算法,它是经过一个函数,把任意长度的数据转换为一个长度固定的数据串,这个数据串使用的十六进制表示。摘要算法是一个单向函数,计算容易,若是想要反推摘要算法那是很是喜困难的,并且 若是对原数据作了一个bit的修改,都会致使计算出的摘要彻底不一样,咱们常用摘要对比数据是否被修改过和密码的加密;git
简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。es6
HASH主要用于信息安全领域中加密算法,他把一些不一样长度的信息转化成杂乱的128位的编码里,叫作HASH值.也能够说,hash就是找到一种数据内容和数据存放地址之间的映射关系算法
2.1 什么是MD5算法数据库
MD5讯息摘要演算法(英语:MD5 Message-Digest Algorithm),一种被普遍使用的密码杂凑函数,能够产生出一个128位的散列值(hash value),用于确保信息传输完整一致。MD5的前身有MD二、MD3和MD4。编程
2.2 MD5功能缓存
输入任意长度的信息,通过处理,输出为128位的信息(数字指纹);
不一样的输入获得的不一样的结果(惟一性);安全
2.3 MD5算法的特色服务器
2.4 MD5算法是否可逆?网络
MD5不可逆的缘由是其是一种散列函数,使用的是hash算法,在计算过程当中原文的部分信息是丢失了的。
2.5 MD5用途
防止被篡改:
好比发送一个电子文档,发送前,我先获得MD5的输出结果a。而后在对方收到电子文档后,对方也获得一个MD5的输出结果b。若是a与b同样就表明中途未被篡改。
好比我提供文件下载,为了防止不法分子在安装程序中添加木马,我能够在网站上公布由安装文件获得的MD5输出结果。
SVN在检测文件是否在CheckOut后被修改过,也是用到了MD5.
防止直接看到明文:
防止抵赖(数字签名):
安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要能够用来验证数据的完整性。
SHA是美国国家安全局设计的,由美国国家标准和技术研究院发布的一系列密码散列函数。
因为MD5和SHA-1于2005年被山东大学的教授王小云破解了,科学家们又推出了SHA224, SHA256, SHA384, SHA512,固然位数越长,破解难度越大,但同时生成加密的消息摘要所耗时间也更长。目前最流行的是加密算法是SHA-256 .
因为MD5与SHA-1均是从MD4发展而来,它们的结构和强度等特性有不少类似之处,SHA-1与MD5的最大区别在于其摘要比MD5摘要长32 比特。对于强行攻击,产生任何一个报文使之摘要等于给定报文摘要的难度:MD5是2128数量级的操做,SHA-1是2160数量级的操做。产生具备相同摘要的两个报文的难度:MD5是264是数量级的操做,SHA-1 是280数量级的操做。于是,SHA-1对强行攻击的强度更大。但因为SHA-1的循环步骤比MD5多80:64且要处理的缓存大160比特:128比特,SHA-1的运行速度比MD5慢。
咱们平常生活中在各大网站上注册时填写的密码大部分都是使用MD5的方式储存在数据库中,还有一部分使用的是sha的方式,可是会有好多朋友在注册时填写的密码过于简单,简单的密码即使使用MD5方式加密了,黑客还能够事先计算出这些经常使用口令的MD5值,获得一个反推表,如今在网上随便搜索一下就能够看到MD5在线解密,这种网站都是事先将这些经常使用的口令使用MD5计算一下放在一个库中,咱们将这种状况称之为‘撞库’;
因为经常使用口令很容易被黑客计算出来,这时又出现了一种方法来避免被反推出来,这个方法就是俗称的“加盐”,就是在你加密时在前面添加一个固定的字符串;
#!/usr/bin/python # -*- encodeing:utf-8 -*- import hashlib md5 = hashlib.md5('盐'.encode('utf-8')) md5.update(b'123.com') print(md5.hexdigest()) #cbff36039c3d0212b3e34c23dcde1456 #69c974abecb370564b051094c820fc6a #此时获得的加密值与以前的比是不同的
还有一种更难破解的方式就是动态加盐
#!/usr/bin/python # -*- encodeing:utf-8 -*- import hashlib usr = 'Fang' md5 = hashlib.md5(usr[0:2].encode('utf-8')+ '盐'.encode('utf-8')) # 这种方法就是取用户名的前两个字符 再加上 一个固定的字符,而后在加上密码 md5.update(b'123.com') print(md5.hexdigest())
RSA加密算法是一种非对称加密算法。在公开密钥加密和电子商业中RSA被普遍使用。RSA是1977年由罗纳德·李维斯特(Ron Rivest)、阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一块儿提出的。当时他们三人都在麻省理工学院工做。RSA就是他们三人姓氏开头字母拼在一块儿组成的。
咱们经常使用的密码在密码学中叫作口令。在传统密码:加密算法是秘密的。在现代密码系统中:加密算法是公开的,秘钥是秘密的。
而现代密码系统分为对称加密和非对称加密。
那么RSA加密解密过程图解以下(来自百度百科):
RAS非对称加密系统中。公钥是用来加密的(是公开的),私钥是用来解密的(是私有的)。举个例子:
那它一般先生存一对RSA秘钥,其中之一是保密秘钥,由用户保存;另一个是公开密钥,可对外公开,甚至可在网络服务器上注册。为了提升保密强度,RSA密钥至少为500位长,通常推荐使用1024位。这就使加密的计算量很大。为减小计算量,在传送信息时,经常使用传统加密方法与公开密钥加密方法相结合的方法。即信息采用改进的DES或IDEA密钥加密,而后使用RSA密钥加密对话密钥和信息摘要。对方收到信息后,用不一样的密钥解密并可核对信息摘要。
RSA算法是第一个能同时用于加密和数字签名的算法,也易于理解和操做。RSA是被研究得最普遍的公钥算法,从提出到如今至今的三十多年里,经历了各类攻击的考验,逐渐为人们接受,截止2017年被广泛认为是最优秀的公钥方案之一。
详细解析以下:
RSA中的公钥和私钥须要结合在一块儿工做。公钥用来对数据块加密,以后 ,只有对应的私钥才能用来解密。生成密钥时,须要遵循几个步骤以确保公钥和私钥的这种关系可以正常工做。这些步骤也确保没有实际方法可以从一个密钥推出另外一个。
开始前,首先要选择两个大的素数,记为p和q。根据当今求解大数因子的技术水平,这两个数应该至少有200位,这们在实践中才能够认为是安全的。
而后,开始计算n:
n = pq
接下来,选择一个小的奇数e,它将成为公钥的一部分。选择e最须要考虑的重点是它与(p-1)(q-1)不能有相同的因子。换句话说,e与(p-1)(q-1)是互为素数关系的。好比,若是p=11而q=19,那么n=11 X 19=209。这里选择e=17,由于(p-1)(q-1)=10 X 18 =180,而17和180没有相同的因子。一般选择三、1七、6五、537做为e的值。使用这些值不会对RSA的安全性形成影响,由于解密数据还须要用到私钥。
一旦为e选择了一个值,接下来开始计算相对应的值d,d将成为私钥的一部分。d的值就是计算e的倒数对(p-1)(q-1)的取模结果,公式以下:
d = e-1 mod (p-1)(q-1)
这里d和e是模乘法逆元的关系。
思考一下这个问题:当d为多少时能够知足ed mod (p-1)(q-1) = 1 ?好比在等式 17d mod 180 = 1中,d的一个可能值是53。其余的可能值是23三、41三、593等。在实践中,能够利用欧几里德算法来计算模乘法逆元。这里就再也不展开。
如今有了e和d的值,将(e,n)做为公钥P,将(d,n)做为私钥S并保持其不可见。表示为:
P = (e,n) , S = (d,n)
加密方使用P来加密数据,解密方使用S来解密。为了防止就算有人知道了P也没法推算出S,必须保证p和q的值绝对不能暴露。
P和S结合在一块儿提供的安全性来自于一个事实,那就是乘法是一种很好的单向函数。
单向函数是加密技术的基础。简单的说,单向函数就是在一个方向上可以很容易算出结果,但反向推导则是不切实际的。好比,在RSA算法中,计算p和q的成绩是一种单向函数,由于尽管计算p和q的成绩很容易,但将n反向因子分解为p和q则是极其耗时的。这里,选择的p和q的值要足够大才能够。
计算P和S的步骤起源于欧拉函数中的一些有趣性质。特别是,这些性质容许对模幂运算作一些有用的操做。
欧拉函数记为φ(n),定义全部小于n的正整数里和n互素的整数的个数。
只有当两个整数的惟一公因子为1时,才说这两个整数是互素的。例如,φ(8)=4,由于一共只用4个比8小的整数是互素的,它们是1,3,5,7。
欧拉方程有两个性质对RSA算法来讲是特别重要的。
第一,当n是素数时,φ(n)=n-1。这是因为n的惟一因子是1和n,所以,n与以前的全部n-1个正整数都是互素的。
另外一个有趣的性质是对于任意小于n且与n互素的正整数a,都有aφ(n) mod n = 1。例如,14 mod 8 = 1, 34mod 8 = 1, 54 mod 8 = 1, 74 mod 8 = 1。对上述方程两边都乘以a,获得:
(a)(aφ(n) mod n)=a,或者aφ(n)+1 mod n = a
所以,能够获得15 mod 8 = 1, 35 mod 8 = 3, 55 mod 8 = 5, 75 mod 8 = 7。
调整以后获得的等式很是强大。由于对于某些等式c = me mod n,该等于可让咱们找出一个d的值,使得cdmod n = m。
这就是RSA算法中容许加密数据,以后再解密回原文的恒等式。能够按照以下方式表示:
cd mod n = (me)d mod n = med mod n = mφ(n)+1 mod n = m mod n
欧拉函数和指数间的关系保证了加密的任意数据都可以惟一地解密回来。为了找出d的值,解方程d = e-1 φ(n) +1。不巧的是,对于方程d = e-1φ(n)+1不必定老是有整数解。为了解决这种问题,转而计算d mod φ(n)的值。换句话说,d = (e-1 φ(n) + 1) mod φ(n),能够简化为:
d = e-1 mod φ(n)
咱们能够获得这样的简化形式,由于(φ(n)+1) mod φ(n) = (φ(n)+1) - φ(n) = 1。能够用任意的正整数替代φ(n)来证实等式成立。注意这个方程式同以前计算密钥的过程当中得出d的推导式之间的类似之处。这提供了一种经过e和n来计算d的方法。固然了,e和n是公开的,对于攻击者来讲是事先可知的,所以就有人问,这难道不是给了攻击者相同的机会来计算出私钥吗?讨论到这里,是时候来探讨一下RSA算法安全性保障的由来了。
RSA算法的安全性保障来自一个重要的事实,那就是欧拉函数是乘法性质的。这意味着若是p和q是互素的,那么有φ(pq)=φ(p)φ(q)。所以,若是有两个素数p和q,且n=p*q,则φ(n)=(p-1)(q-1),并且最重要的是:
d = e-1 mod (p-1)(q-1)
所以,尽管攻击者可能知道了e和n的值,为了计算出d必须知道φ(n),而这又必须同时获得p和q的值才能办到。因为p和q是不可知的,所以攻击者只能计算n的因子,只要给出的p和q的值足够大,这就是一个至关耗费时间的过程。
要使用RSA算法对数据进行加密和解密,首先要肯定分组的大小。为了实现这一步,必须确保该分组能够保存的最大数值要小于n的位数。好比,若是p和q都是200位数字的素数,则n的结果将小于400位。于是,所选择的分组所能保存的最大值应该要以是接近于400。在实践中,一般选择的位数都是比n小的2的整数次幂。好比,若是n是209,要选择的分组大小就是7位,由于27 = 128比209小,但28 = 256又大于209。
要从缓冲区M中加密第(i)组明文Mi ,使用公钥(e,n)来获取M的数值,对其求e次幂,而后再对n取模。这将产生一组密文Ci。对n的取模操做确保了Ci将和明文的分组大小保持一致。于是,要加密明文分组有:
Ci = Mie mod n
以前提到过,欧拉函数是采用幂模运算来加密数据的基础,根据欧拉函数及其推导式,可以将密文解密回原文。
要对缓冲区中C中的第(i)组密文进行解密,使用私钥(d,n)来获取Ci的数值部分,对其求d次幂,而后再对n取模。这将产生一组明文Mi。所以,要解密密文分组有:
Mi = Cid mod n
代码以下:
# 取两个质数 p = 53 q = 59 n = p * q # 3127 fai = (p - 1) * (q - 1) # fai = 3016 e = 3 # fai/3 = 1005.333 # 除不尽,这是质数 d = 2011 # d是惟一的(这个本身算) # 这里咱们反推一下d是否正确 # (e * d) % fai = 1 # (e, n)组成公钥 # (d, n)组成私钥 # 加密和解密的过程 # c = (m**e)%n # m = (c**d)%n
为何RSA加密算法破解不了,两个质数计算乘法很简单,可是打乱拆分为两个质数很难。没有一个算法能够破解,因此只能一个一个试,就是说大数拆分很难。
用于加密相关的操做,3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法
下面举例说明了SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5算法的运算:
#使用update生成MD5加密的值,注意update在pycharm中没有提示,须要自行手打
import hashlib m = hashlib.md5() print("m:",m) # m: <md5 HASH object @ 0x00000224BA2D0378> m1 = m.update(b"Hello") print("m1:",m1) print("m:",m) # m1: None # m: <md5 HASH object @ 0x00000224BA2D0378> m2 = m.update(b"It's me") print("m2:",m2) print("m:",m) # m2: None # m: <md5 HASH object @ 0x00000224BA2D0378> print(m.digest()) # b']\xde\xb4{/\x92Z\xd0\xbf$\x9cR\xe3Br\x8a' m3 = m.update(b"It's been a long time since last time we ...") print("m3:",m3) print("m:",m) # m3: None # m: <md5 HASH object @ 0x00000224BA2D0378> print(m.digest()) #2进制格式hash print(len(m.hexdigest())) #16进制格式hash # b'\xa0\xe9\x89E\x03\xcb\x9f\x1a\x14\xaa\x07?<\xae\xfa\xa5' # 32 ''' def digest(self, *args, **kwargs): # real signature unknown """ Return the digest value as a string of binary data. """ pass def hexdigest(self, *args, **kwargs): # real signature unknown """ Return the digest value as a string of hexadecimal digits. """ pass
import hashlib ######## md5 ######## res = hashlib.md5() print("md5",res) # md5 <md5 HASH object @ 0x00000203F6610378> res1 = res.update(b'admin') print("md5_update:",res1) print("md5",res) # md5_update: None # md5 <md5 HASH object @ 0x00000203F6610378> print(res.hexdigest()) # 21232f297a57a5a743894a0e4a801fc3 ######## sha1 ######## hash = hashlib.sha1() print("sha1",hash) # sha1 <sha1 HASH object @ 0x0000024CA2840378> hash1 = hash.update(b'admin') print("hash1:",hash1) print("hash:",hash) # hash1: None # hash: <sha1 HASH object @ 0x0000024CA2840378> print(hash.hexdigest()) # d033e22ae348aeb5660fc2140aec35850c4da997 ######## sha256 ######## hash = hashlib.sha256() print("hash",hash) # hash <sha256 HASH object @ 0x000001D462B20378> hash1 = hash.update(b'admin') print("sha256:",hash1) print("hash:",hash) # sha256: None # hash: <sha256 HASH object @ 0x000001D462B20378> print(hash.hexdigest()) # 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 ######## sha384 ######## hash = hashlib.sha384() print("hash:",hash) # hash: <sha384 HASH object @ 0x000001D82F940378> hash1 =hash.update(b'admin') print("sha384:",hash1) print("hash:",hash) # sha384: None # hash: <sha384 HASH object @ 0x000001D82F940378> print(hash.hexdigest()) # 9ca694a90285c034432c9550421b7b9dbd5c0f4b6673f05f6dbce58052ba20e4248041956ee8c9a2ec9f10290cdc0782
下面直接上代码,明白的快
import random res1 = random.randrange(1,10) #返回1-10之间的一个随机数,不包括10 print(res1) #4 res2 = random.randint(1,10) #返回1-10之间的一个随机数,包括10 print(res2) #6 res3 = random.randrange(0, 100, 2) #随机选取0到100间的偶数 print(res3) #12 res4 = random.random() #返回一个随机浮点数 print(res4) # 0.31929002952597907 res5 = random.choice('abce3#$@1') #返回一个给定数据集合中的随机字符 print(res5) # @ res6 = random.sample('abcdefghij',3) #从多个字符中选取特定数量的字符 print(res6) # ['j', 'h', 'a']
程序中有不少地方须要用到随机字符,好比登陆网站的随机验证码,经过random模块能够很容易生成随机字符串,举例以下:
#生成随机字符串 import string import random res = ''.join(random.sample(string.ascii_lowercase + string.digits, 6)) print(res) # 3l82uv #洗牌 num = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] res2 = random.shuffle(num) print(num) # [3, 9, 5, 8, 4, 6, 1, 0, 2, 7]
ascii_letters 获取全部ascii码中字母字符的字符串(包含大写和小写) ascii_uppercase 获取全部ascii码中的大写英文字母 ascii_lowercase 获取全部ascii码中的小写英文字母 digits 获取全部的10进制数字字符 octdigits 获取全部的8进制数字字符 hexdigits 获取全部16进制的数字字符 printable 获取全部能够打印的字符 whitespace 获取全部空白字符 punctuation 获取全部的标点符号
练习题:写一个6位随机验证码,要求至少包括一个数字,一个小写字母,一个大写字母
# 写一个6位随机验证码程序(使用random模块), # 要求验证码中至少包含一个数字、一个小写字母、一个大写字母. import random import string # ascii_letters:获取全部ascii码中字母字符的字符串(包含大写和小写) # digits:获取全部的10进制数字字符 res = ''.join(random.sample(string.digits+string.ascii_letters,6)) # res = ''.join(random.sample(string.ascii_lowercase + string.digits, 6)) print(res)
在数学之中,除了加减乘除四则运算以外——还有其它更多的运算,好比乘方、开方、对数运算等等,要实现这些运算,须要用到 Python 中的一个模块:Math
模块(module)是 Python 中很是重要的东西,你能够把它理解为 Python 的扩展工具。换言之,Python 默认状况下提供了一些可用的东西,可是这些默认状况下提供的还远远不能知足编程实践的须要,因而就有人专门制做了另一些工具。这些工具被称之为“模块”
任何一个 Pythoner 均可以编写模块,而且把这些模块放到网上供他人来使用。
当安装好 Python 以后,就有一些模块默认安装了,这个称之为“标准库”,“标准库”中的模块不须要安装,就能够直接使用。
若是没有归入标准库的模块,须要安装以后才能使用。模块的安装方法,我特别推荐使用 pip 来安装。这里仅仅提一下,后面会专门进行讲述,性急的看官能够本身 google。
math模块是标准库里面的,因此不用安装,能够直接调用
# _*_ coding: utf-8 _*_ #导入模块 import math #dir(module)是一个很是有用的指令,能够经过他来差任何模块所包含的工具 res = dir(math) print(res) # ['__doc__', '__loader__', '__name__', '__package__', '__spec__', # 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', # 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', # 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', # 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', # 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', # 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc'] ''' 上面列举了math的全部方法,若是不会使用, 请输入help(math.方法名) ''' # help(math.pow) # Help on built - in function pow in module math: # # pow(...) # pow(x, y) # # Return x ** y(x to the power of y). print(math.pi) # 3.141592653589793