密碼學是研究編制密碼和破譯密碼的技術科學。研究密碼變化的客觀規律,應用於編制密碼以保守通訊祕密的,稱爲編碼學;應用於破譯密碼以獲取通訊情報的,稱爲破譯學,總稱密碼學。html
密碼學的歷史大體能夠追溯到兩千年前,相傳古羅馬名將凱撒大帝爲了防止敵方截獲情報,用密碼傳送情報。凱撒的作法很簡單,就是對二十幾個羅馬字母創建一張對應表。這樣,若是不知道密碼本,即便截獲一段信息也看不懂。git
從凱撒大帝時代到上世紀70年代這段很長的時間裏,密碼學的發展很是的緩慢,由於設計者基本上靠經驗。沒有運用數學原理。程序員
在1976年之前,全部的加密方法都是同一種模式:加密、解密使用同一種算法。在交互數據的時候,彼此通訊的雙方就必須將規則告訴對方,不然無法解密。那麼加密和解密的規則(簡稱密鑰),它保護就顯得尤爲重要。傳遞密鑰就成爲了最大的隱患。這種加密方式被成爲對稱加密算法(symmetric encryption algorithm)github
1976年,兩位美國計算機學家 迪菲(W.Diffie)、赫爾曼( M.Hellman ) 提出了一種嶄新構思,能夠在不直接傳遞密鑰的狀況下,完成密鑰交換。這被稱爲「迪菲赫爾曼密鑰交換」算法。開創了密碼學研究的新方向,非對稱加密算法(asymmetric cryptographic algorithm)算法
1977年三位麻省理工學院的數學家 羅納德·李維斯特(Ron Rivest)、阿迪·薩莫爾(Adi Shamir)和倫納德·阿德曼(Leonard Adleman)一塊兒設計了一種算法,能夠實現非對稱加密。這個算法用他們三我的的名字命名,叫作RSA算法。vim
若是讓你設計一個加密容易,破解很難的算法,會想到什麼呢? 方案: ,問x是多少? x可能的值爲x=16k + 13,k爲正整數,這樣的x有多個,根本無法肯定是哪一個安全
對正整數n,在小於n的正整數之中,與n構成互質關係的數有多少個? 對這個問題的首位研究者叫做歐拉,是一個神同樣的厲害人物,因此把對這個問題的解答稱做歐拉函數,用φ(n)來表示服務器
如φ(8)表示計算8的歐拉函數,和8互質的數有,1,3,5,7因此φ(8) = 4; 如φ(7)表示計算7的歐拉函數,有1,2,3,4,5,6因此φ(7) = 6;微信
歐拉對這個問題進行研究以後,獲得了歐拉函數的兩個性質:markdown
結合以上兩條性質可得,若A,B都是質數,則φ(A * B) = φ(A) * φ(B) = (A - 1) * (B - 1)
若是兩個正整數m和n互質,那麼m的φ(n)次方減去1,能夠被n整除
針對上面的歐拉定理,費馬又來了個小定理若是兩個正整數m和n互質,並且n爲質數,那麼m的n-1次方減去1,能夠被n整除
若是兩個正整數e和x互質,那麼必定能夠找到整數d,使e * d - 1被x整除,那麼d就是e相對於x的模反元素
把歐拉定理和模反元素結合起來推導
由於1 ^ k = 1,因此 兩邊同時k次方後獲得
由於1 * m = m,因此上式兩邊同時乘上m後獲得
將模反元素 變形後獲得
再結合上述兩個式子就能夠獲得
其中m,n互質,e與φ(n)互質,知足條件的d必定能夠找到,咱們能夠舉幾個例子驗證一下
令m = 3,n = 17,e = 5,m,n互質,e和φ(17)互質,根據模反元素求的可能的d = ,k取4的時候,d爲13,代入上式中驗證 結果肯定等於3
多試幾個m,n以後會發現,只要m < n,上面的等式就一直成立,再也不須要互質了...至於爲何,俺也搞不明白,知道就行了,若是有大神知道的,還請不吝賜教
此時,m<n,e與φ(n)互質,d =
其實獲得 以後,離咱們實際使用RSA算法很是接近了,實際使用中 ,這個過程叫做加密,再求 會發現結果仍是m,這個過程叫做解密,其中公鑰就是n和e,私鑰就是n和d,m表明明文,c表明密文
說明:
總共生成6個數字:p一、p二、n、φ(n)、e、d,除了公鑰用到了n和e其他的4個數字是不公開的,目前皮傑RSA獲得d的方式以下:
Mac電腦的終端能夠直接使用OpenSSL進行RSA的命令運行。因爲Mac系統內置OpenSSL(開源加密庫),因此咱們能夠直接在終端上使用命令來玩RSA. OpenSSL中RSA算法經常使用指令主要有三個:
生成RSA私鑰,密鑰長度爲1024bit:openssl genrsa -out private.pem 1024
從私鑰中提取公鑰:openssl rsa -in private.pem -pubout -out public.pem
能夠查看一下公鑰和私鑰的內容
還可使用命令openssl rsa -in private.pem -text -out private.txt
將私鑰轉成文本,並查看裏面的內容
接下來咱們使用公鑰對一段文本進行加密:openssl rsautl -encrypt -in message.txt -inkey public.pem -pubin -out enc.txt
能夠看到message.txt的內容由密碼123456已經變成了一堆亂碼,(沒使用過vim編輯器的同窗也能夠直接建立一個txt文件)
使用私鑰進行解密:openssl rsautl -decrypt -in enc.txt -inkey private.pem -out dec.txt
在macOS中咱們是不能直接使用pem文件的,須要使用的der格式和p12格式的文件
首先須要一個證書請求文件,這個作過iOS開發的同窗應該都很熟悉了openssl req -new -key private.pem -out rsacert.csr
通常咱們配置證書的時候,是使用上面生成的證書請求文件去蘋果服務器簽名後獲得證書,可是如今咱們只是演示,就本身簽名了:openssl x509 -req -days 3650 -in rsacert.csr -signkey private.pem -out rsacert.crt
經過crt文件生成p12文件:openssl pkcs12 -export -out p.p12 -inkey private.pem -in rsacert.crt
設置密碼並再次確認以後獲得p12文件
其實在平時平常開發中,證書這些東西,咱們iOS開發者直接使用就好了,基本是不會須要咱們iOS開發來生成配置
在iOS系統中,crt文件也不能直接使用,須要轉成der文件,命令以下:
openssl x509 -outform der -in rsacert.crt -out rsacert.der
加載公鑰和私鑰其中
RSACryptor
是已經封裝好的RSA工具類,有須要的能夠本身去下載
加密hello world
並輸出加密結果
解密過程
Hash,通常翻譯作「散列」,也有直接音譯爲「哈希」的,就是把任意長度的輸入經過散列算法變換成固定長度的輸出,該輸出就是散列值。這種轉換是一種壓縮映射,也就是,散列值的空間一般遠小於輸入的空間,不一樣的輸入可能會散列成相同的輸出,因此不可能從散列值來肯定惟一的輸入值。簡單的說就是一種將任意長度的消息壓縮到某一固定長度的消息摘要的函數
網絡上通常是不會傳輸用戶的密碼明文數據的,不然當用戶的帳號密碼泄露以後,是會被追究法律責任的;如今市面上爲何沒有找回密碼的功能,就是由於用戶的密碼並非以明文的形式保存在服務器上的;
咱們先使用最簡單方式,來對用戶的密碼進行加密處理:(本文基於iOS平臺,使用到的第三方能夠在這下載)
直接對密碼進行MD5可使用終端來驗證一下上面加密的結果是否正確,終端命令以下:
md5 -s "123456"
能夠看到加密的結果是一致的;可是有一些網站,它專門記錄了經常使用的密碼對應的md5值,好比:www.cmd5.com;這樣咱們經常使用的密碼,即便使用了md5加密,要破解出來也是太簡單了...有什麼更好的加密辦法呢?
MD5 + 鹽(一段任意的字符串)這樣加密出來的結果,會比上面單純的使用MD5會好一點,可是這個鹽一旦泄露以後,要破解出密碼來也是垂手可得,上面的那個網站依然能夠很好的查詢出來
HMAC加密方案
以用戶註冊爲例,當用戶把輸入完帳號的時候,如今不少APP或者網站都會讓用戶去檢測帳號的合法性,服務器驗證合法就會生成這個帳號對應的key,併發送給客戶端;客戶端將服務器返回的key記錄在本地,並跟用戶輸入的密碼進行一次hmac加密,將加密的結果發送給服務器記錄並保存;這樣就算是註冊成功了!當用戶下次登陸的時候,客戶端查找本地的帳號對應的key,和用戶輸入的密碼進行hmac運算以後,發送給服務器驗證;這樣相比較於上面的僅僅加鹽的方式,安全性又高了一些;
在用戶更換設備進行登陸的時候,此時客戶端沒有帳號對應的key了,那就須要在輸入完帳號密碼登陸的時候,先去請求服務器獲取key值;服務器收到這個請求以後,能夠查詢當前帳號是否開啓了設備鎖,若是開了設備鎖,那麼就去詢問有key值的設備是否容許當前設備登陸,不一樣意那麼新設備就天然登陸失敗;贊成的話,就將帳號對應的key值返回給請求的設備,這樣用戶在新設備上進行登陸所需的key也有了,再與密碼進行hmac後發送給服務器驗證登陸;是否是在QQ,微信之類有設備鎖的APP上見過
HMAC + 時間戳
使用上述的hmac加密方案以後,密碼的安全性確實高了很多;可是還能夠在安全一點,那就是再加上時間戳;在用戶輸入帳號密碼,點擊登陸以後,用生成的hmac密碼,再拼接上一個到分鐘的當前時間,好比202106120112,再進行一次MD5加密獲得的結果發送給服務器;此時服務器也會用已經存起來的hmac密碼拼接當前分鐘的時間戳,進行一次MD5,和客戶端發送過來的結果進行匹配,若是一致則登陸成功;若是不一致,那麼就使用上一分鐘的時間戳,再進行一次MD5,再匹配客戶端發送過來的結果(爲何再試一次上一分鐘,由於有可能在發送的過程當中,時間加了一分鐘);這樣用戶登陸的時候,密碼的時效最多隻有2分鐘,過了這2分鐘,密碼又不同了...黑客會很懵逼
主要是用於拆詞搜索,每一個詞語進行hash運算後的結果都是同樣的,好比上海,iOS,程序員在百度上搜索,不論怎麼樣排列這三個詞語,可能都會搜到同一條新聞,就是由於這三個詞對應的hash值相加以後的結果,不論這三個詞怎麼排列,都是同樣的;
百度雲上傳電影的時候,有些電影會有秒傳的功能;就是比對hash值是同樣的,再比對一些額外的信息,就能夠肯定是同一部電影了,就不須要重複上傳了; 視頻網站YouTube之類的,會對用戶上傳的視頻文件進行hash並記錄,這樣用戶上傳每一個視頻都有了一個身份證相似的id了
什麼是數字簽名?老外喜歡用簽名,刷信用卡消費以後有一個帳單,須要信用卡持卡人簽名確認;簽名的目的就是表示被簽名的東西是屬於簽名人的;數字簽名的意思就是對一串二進制數據進行簽名,用於確認是誰的二進制數據
舉個例子:你在網上購買了一件100元的商品,你的消費信息發送給服務器,服務器收到了你的消費信息後,在你的帳戶下面扣除100元,而後把扣款結果返回給用戶,這個世界原本是這麼簡單的;可是中間若是有不懷好意的黑客,他篡改了你發送給服務器的消費信息,改成你消費了1000元,而後服務器收到這條消息後,在你的帳戶里扣除了1000元,並將扣款結果返回,這個時候黑客再將服務器返回給你的扣款信息篡改,告訴你成功消費100元,你們都沒察覺出什麼問題,回過頭你發現你不知去向了900元...因此服務器須要確認消費信息是由你發出的並且是沒有通過第三方篡改的消費信息,怎麼作到呢?
首先使用hash將消費信息進行加密獲得一個128位的結果,而後使用RSA的公鑰對結果進行加密,而後將消費信息,RSA公鑰加密的消費信息hash值全發送給服務器,服務器收到結果後,使用RSA的私鑰解密獲得一個消費信息的hash值,再使用收到的消費信息進行一次hash加密,比較兩個hash值是都相同,相同就表明消費信息沒有被第三方修改,不相同就表明消費信息被修改過了;這裏面被RSA加密的消費信息的hash值就叫做數字簽名
對稱加密(也叫私鑰加密)指加密和解密使用相同密鑰的加密算法。有時又叫傳統密碼算法,就是加密密鑰可以從解密密鑰中推算出來,同時解密密鑰也能夠從加密密鑰中推算出來。而在大多數的對稱算法中,加密密鑰和解密密鑰是相同的,因此也稱這種加密算法爲祕密密鑰算法或單密鑰算法。它要求發送方和接收方在安全通訊以前,商定一個密鑰。對稱算法的安全性依賴於密鑰,泄漏密鑰就意味着任何人均可以對他們發送或接收的消息解密,因此密鑰的保密性對通訊的安全性相當重要。
對稱加密算法的特色是算法公開、計算量小、加密速度快、加密效率高。
數據加密標準,如今用的少,由於強度低
使用3個密鑰,對相同的數據執行三次加密
高級加密標準,包括蘋果的鑰匙串訪問,美國國家安全局都在使用的加密方式
ECB:(Electronic Code Book),電子密碼本模式,每一塊數據獨立加密;最基本的加密模式,也就是一般理解的加密,相同的明文將永遠加密成相同的密文,無初始向量,容易受到密碼本重放攻擊,通常狀況下不多用。
CBC:(Cipher Block Chainning),密碼分組連接模式;明文被加密前要與前面的密文進行異或運算後再加密,所以只要選擇不一樣的初始向量,相同的密文加密後會造成不一樣的密文,這是目前應用最普遍的模式。CBC加密後的密文是上下文相關的,但明文的錯誤不會傳遞到後續分組,但若是一個分組丟失,後面的分組將所有做廢(同步錯誤)。CBC能夠有效的保證祕聞的完整性,若是一個數據塊在傳遞時丟失或者改變,後面的數據將沒法正常解密。
還有一些模式,但不是很常見,好比Cipher Feedback Mode(CFB)加密反饋模式,Output Feedback Mode(OFB)輸出反饋模式
明文message.txt內容以下:
使用DES算法ECB模式加密,key爲abc:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg1.bin
將明文中的某個數字修改一下
再使用一樣的加密方式,生成第二份密文msg2.bin:openssl enc -des-ecb -K 616263 -nosalt -in message.txt -out msg2.bin
對比一下生成的兩份密文msg1.bin和msg2.bin,發現明文就只是改動了一個數字,對應的密文是一整塊都修改了,這也形象的表示了ECB模式的原理
而後咱們試一下CBC模式:
openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg3.bin
將明文內容修改回最初的樣子後再使用CBC模式生成msg4.bin文件
openssl enc -des-cbc -iv 0102030405060708 -K 616263 -nosalt -in message.txt -out msg4.bin
對比msg3.bin和msg4.bin發現,CBC模式下改動了一處後,後面的總體都發生了改變,兩次對比很形象的說明了ECB模式和CBC模式的區別
使用AES算法,ECB模式進行加密(EncryptionTools下載) 再用終端來驗證一下結果:
echo -n hello | openssl enc -aes-128-ecb -K 616263 -nosalt | base64
使用AES算法,CBC模式進行加密 終端驗證結果:
echo -n hello | openssl enc -aes-128-cbc -K 616263 -nosalt -iv 0102030405060708 | base64
終端驗證解密結果:
echo -n u3W/N816uzFpcg6pZ+kbdg== | base64 -D | openssl enc -aes-128-cbc -K 616263 -iv 0102030405060708 -nosalt -d
[EncryptionTools sharedEncryptionTools]
單例默認使用的就是AES算法,若是想使用其餘的算法,能夠自行指定[EncryptionTools sharedEncryptionTools].algorithm = <#CCAlgorithm#>
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
self.algorithm,
option,
cKey,
self.keySize,
cIv,
[data bytes],
[data length],
buffer,
bufferSize,
&encryptedSize);
複製代碼
參數1: kCCEncrypt 表明加密,kCCDecrypt 表明解密
參數2: 加密算法,AES,DES...
參數3: 加密模式:ECB,CBC...
參數4: 加密所需的密鑰
參數5: 密鑰的長度
參數6: iv 初始化向量(若是是CBC模式須要傳入,ECB不須要)
參數7: 加密的數據,也就是明文
參數8: 加密的數據的長度,明文的長度
參數9: 密文的內存地址
參數10: 密文緩衝區的大小
參數11: 加密結果的大小
在iOS中,使用了對稱加密的最終都會走到這個函數,若是有人對你開發的APP有些想法,就會調試你的應用,對這個CCCrypt下一個符號斷點,就能夠拿到這個函數的全部參數信息了,那用戶的明文密碼就泄露無疑了... 寄存器讀這個函數的第七個參數就是
register read x6
(x0是第一個)明文數據