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