1. 什麼叫密碼
生活中我們經常要用到密碼,尤其是在這個信息爆炸的時代,例如銀行卡的密碼由六位數字組成,支付寶的密碼也是由若干字元組成,然而這些所謂的密碼是否就是「真正」的密碼呢?或者說它們的本質究竟是什麼?其實這些數字和字母符號等只是作為個人取款的一個憑證,它本質上是一種身份驗證機制,只有你輸對了密碼才能取錢,輸錯了就不能取錢,對錯僅僅是這一串字元的差別,所以,它們並不是真正意義的密碼,嚴格的叫法應該叫做「口令」,對應的英文單詞為Password、Passcode和Pin等。
所謂口令,就是一些過關的證據,由它來決定個人能否通過某個檢測,例如過去抗戰時期的暗語和暗號等等。口令並不真正具有機密性,除了你之外,銀行本身也知道你卡的密碼。還有就是,口令是可以在不知道口令的情況下繞過的,比如某個黑客或者電腦高手可以侵入一個企業的內部,獲取一些有價值有機密的信息等,理論上是完全可行的;或者我們可以把口令比作一把寶庫的鑰匙,只有拿到了鑰匙,你才能打開寶庫的門,然而就算我們沒有鑰匙,我們也能夠利用工具把門撬開或切開,也照樣能拿到裡面的珠寶。現在看來,口令其實只是通往目的地的一道門。
現在來說一下密碼。密碼究竟是什麼呢?密碼對應的英文為「cryptography」,意思是一種復雜而又龐大的信息處理系統。通俗地講,密碼就是傳遞信息的方法。現在讓我們舉一些簡單的例子來說明什麼是密碼。
首先看下面這些密碼:
1.Windows系統登錄密碼,
2.WinRAR壓縮密碼,
3.路由器管理登錄密碼,
4.無線網路密碼,
5.Word文檔打開許可權密碼,
6.網站郵箱密碼,
7.QQ密碼。
對於以上這些密碼,哪些是密碼(cryptography)?哪些是口令(password)?正確答案為:1367是口令,245是密碼。首先看Windows登錄密碼,它是一種進入系統的驗證方式,它雖然是經過加密存放的,但是卻受win系統登錄進程的控制,當你輸入密碼時,lsass和winlogon進程會負責將你輸入的密碼和解密後的原系統密碼作對比,如果相同則允許進入系統,否則便不允許進入系統。在這個環節,系統進程是知道用戶所設的密碼的,它知道如何加密以及如何解密或還原。
同樣的,這個密碼也是可以繞過的,比如用U盤進入PE系統,在另一個操作系統下來清除原系統的密碼文件(SAM)的數據。所以,Windows系統登錄密碼其實是口令。
再看RAR密碼,當你要解壓一個帶有密碼的RAR或ZIP文件時,WinRAR會提示你輸入密碼,這時如果你輸入了一個錯誤的密碼,RAR接下來會做些什麼呢?它會不會判斷你輸入的密碼是正確的還是錯誤的呢?答案是不會,因為WinRAR根本不知道你輸入的密碼的正確的還是錯誤的,因為世界上除了設置密碼的人之外,理論上沒有任何人知道此文件的密碼。RAR收到密碼以後根本不管它,它會一如繼往地解壓,直到解壓後還原了明文,它才開始檢驗明文的CRC32,如果和解壓前WinRAR所保存的原文件的CRC不同,說明有可能是密碼錯誤引起的,這時它會提示一個「校驗失敗,文件損壞或密碼錯誤」的消息,因為解壓失敗不一定是密碼錯誤導致的,也有可能是數據本身不完整或丟失部分內容導致的。
這么說來,就算你採用了跟蹤的方法繞過了RAR的密碼驗證機制,比如將不相等跳轉指令改為相等跳轉指令,欺騙WinRAR讓它認為你輸入的密碼是正確的,這樣的結果不過是WinRAR不再提示密碼錯誤的消息,然而解壓出來的數據已經完全不是原來的數據,而是一堆垃圾字元,文件里是沒有任何有意義的信息的。WinRAR的密碼相當於一種編碼方式,它將原文按照某種方式編碼,這種方式由演算法和密碼共同決定,從而轉換成一種人們看不懂的沒有意義的信息,所以你密碼輸錯的話,還原的方式就會是錯的,自然還原的數據就必錯無疑了。
這就是密碼和口令的區別,密碼並不是一扇門,而是珠寶本身,只有當密碼正確時,珠寶才是珠寶,密碼錯誤的話,珠寶便不是珠寶,而是破銅爛鐵。口令可以移去,而密碼只能暴力破解,暴力破解需要的是時間,理論上任何密碼總有一天會被破解,除了一次性密碼本之外,這個下面會提到。
由此,我們對接下來的密碼應該就清晰可見了,例如路由器登錄密碼,密碼輸錯它就會提示錯誤,這是口令的特徵,口令輸錯一般都會提示,而密碼一般不提示,當然也不絕對,例如前面的WinRAR就會提示,或者我自己設計的密碼鑰匙工具(KeyManager),密碼輸錯同樣會提示,這並不代表它是口令,之所以提示是因為還原後的明文的單向散列值和原明文的散列值不一致,所以才會提示密碼錯誤,事實上不一定是密碼錯誤,也可能是文件損壞,而且密碼鑰匙這個工具用的加密方法是所謂的一次性密碼本技術,理論上永遠無法破解,因為即使有人聲稱破解了該文件,但是他怎麼知道他破解出來的就是最初的數據呢?或者是完全錯亂的數據?他永遠不知道他破解成功了還是破解失敗了?這是個悖論。一次性密碼技術使用的方法是Xor(異或)運算,原理很簡單,卻永遠不能被破解,不過由於該方法安全性雖強但不靈活,所以沒有被廣泛使用。
而無線網密碼和路由器登錄密碼完全不同,你在輸無線網密碼時即使輸錯了也照樣能聯上路由器,但是卻上不了網。因為無線網加密的是信號,無論你輸對輸錯它都還原,只不過倘若你輸錯了它就無法還原到真實的網路數據,所以你聯接的其實是一條死胡同。
Office密碼我們遇到的比較多,網有有一些移除office密碼的軟體,幾秒鍾快速去除密碼,試了下還真可以,這是什麼原理呢?其實「移除」這個詞用得不確切,應該用破解這個詞更加貼切,Word默認加密方式的密碼范圍是256^5,也就是5個位元組。有人將5個位元組的數據全部遍歷,生成共幾個TB大小的文件,放在伺服器上,然後破解時程序先從本地獲取doc或xls等文件的幾個位元組數據,然後發送到伺服器上查找密鑰,找到後返回用該密鑰解開文件。
注意這個找到的密鑰並非一定是文件原來的密碼,然而它同樣可以打開加密的文件,因為密碼有可能是重復的,兩個密碼可能指向同一個密鑰。無論你密碼設置得再長,密碼的密鑰總會在這256^5中找出來。最後兩個郵箱密碼和QQ密碼就不用多說了,它們都是口令。
2. 初始密碼英文
初始密碼的英文是”password”,簡寫為”pw”。
3. password是鎖屏密碼嗎
password一詞在中文中被誤譯為密碼,實際上它代表的是口令。
人們往往將口令與密碼混為一談,認為二者無異。然而,事實並非如此。口令是一種只有你知曉而他人未知的秘密信息,它本身並未經過加密處理。例如,你設置的銀行卡口令,如123456,僅是你個人知悉的信息,他人無法得知。相比之下,密碼則不同,它需要經過加密處理。如果你的銀行卡僅限於你自己使用,那麼僅依賴口令就足夠了。但如果你還希望使用網上銀行服務,銀行則需要對你的口令進行加密,以保證數據安全。
4. 密碼學系列之:bcrypt加密演算法詳解
簡介今天要給大家介紹的一種加密演算法叫做bcrypt,bcrypt是由NielsProvos和DavidMazières設計的密碼哈希函數,他是基於Blowfish密碼而來的,並於1999年在USENIX上提出。
除了加鹽來抵禦rainbowtable攻擊之外,bcrypt的一個非常重要的特徵就是自適應性,可以保證加密的速度在一個特定的范圍內,即使計算機的運算能力非常高,可以通過增加迭代次數的方式,使得加密速度變慢,從而可以抵禦暴力搜索攻擊。
bcrypt函數是OpenBSD和其他系統包括一些Linux發行版(如SUSELinux)的默認密碼哈希演算法。
bcrypt的工作原理我們先回顧一下Blowfish的加密原理。blowfish首先需要生成用於加密使用的K數組和S-box,blowfish在生成最終的K數組和S-box需要耗費一定的時間,每個新的密鑰都需要進行大概4KB文本的預處理,和其他分組密碼演算法相比,這個會很慢。但是一旦生成完畢,或者說密鑰不變的情況下,blowfish還是很快速的一種分組加密方法。
那麼慢有沒有好處呢?
當然有,因為對於一個正常應用來說,是不會經常更換密鑰的。所以預處理只會生成一次。在後面使用的時候就會很快了。
而對於惡意攻擊者來說,每次嘗試新的密鑰都需要進行漫長的預處理,所以對攻擊者來說要破解blowfish演算法是非常不劃算的。所以blowfish是可以抵禦字典攻擊的。
Provos和Mazières利用了這一點,並將其進一步發展。他們為Blowfish開發了一種新的密鑰設置演算法,將由此產生的密碼稱為"Eksblowfish"("expensivekeyscheleBlowfish")。這是對Blowfish的改進演算法,在bcrypt的初始密鑰設置中,salt和password都被用來設置子密鑰。然後經過一輪輪的標准Blowfish演算法,通過交替使用salt和password作為key,每一輪都依賴上一輪子密鑰的狀態。雖然從理論上來說,bcrypt演算法的強度並不比blowfish更好,但是因為在bcrpyt中重置key的輪數是可以配置的,所以可以通過增加輪數來更好的抵禦暴力攻擊。
bcrypt演算法實現簡單點說bcrypt演算法就是對字元串OrpheanBeholderScryDoubt進行64次blowfish加密得到的結果。有朋友會問了,bcrypt不是用來對密碼進行加密的嗎?怎麼加密的是一個字元串?
別急,bcrpyt是將密碼作為對該字元串加密的因子,同樣也得到了加密的效果。我們看下bcrypt的基本演算法實現:
FunctionbcryptInput:cost:Number(4..31)log2(Iterations).e.g.12==>212=4,096iterationssalt:arrayofBytes(16bytes)randomsaltpassword:arrayofBytes(1..72bytes)UTF-8encodedpasswordOutput:hash:arrayofBytes(24bytes)////P:arrayof18subkeys(UInt32[18])//S:Foursubstitutionboxes(S-boxes),S0...S3.EachS-boxis1,024bytes(UInt32[256])P,S<-EksBlowfishSetup(cost,salt,password)//Repeatedlyencryptthetext"OrpheanBeholderScryDoubt"64timesctext<-"OrpheanBeholderScryDoubt"//24bytes==>three64-bitblocksrepeat(64)ctext<-EncryptECB(P,S,ctext)////24-(cost,salt,ctext)上述函數bcrypt有3個輸入和1個輸出。
在輸入部分,cost表示的是輪循的次數,這個我們可以自己指定,輪循次數多加密就慢。
salt是加密用鹽,用來混淆密碼使用。
password就是我們要加密的密碼了。
最後的輸出是加密後的結果hash。
有了3個輸入,我們會調用EksBlowfishSetup函數去初始化18個subkeys和4個1K大小的S-boxes,從而達到最終的P和S。
然後使用P和S對"OrpheanBeholderScryDoubt"進行64次blowfish運算,最終得到結果。
接下來看下EksBlowfishSetup方法的演算法實現:
FunctionEksBlowfishSetupInput:password:arrayofBytes(1..72bytes)UTF-8encodedpasswordsalt:arrayofBytes(16bytes)randomsaltcost:Number(4..31)log2(Iterations).e.g.12==>212=4,096iterationsOutput:P:arrayofUInt32arrayof18per-roundsubkeysS1..S4:;eachSBoxis256UInt32(i.e.1024KB)//InitializeP(Subkeys),andS(Substitutionboxes)withthehexdigitsofpiP,S<-InitialState()//,S<-ExpandKey(P,S,salt,password)//Thisisthe"Expensive"partofthe"ExpensiveKeySetup".//.repeat(2cost)P,S<-ExpandKey(P,S,0,password)P,S<-ExpandKey(P,S,0,salt)returnP,S代碼很簡單,EksBlowfishSetup接收上面我們的3個參數,返回最終的包含18個子key的P和4個1k大小的Sbox。
首先初始化,得到最初的P和S。
然後調用ExpandKey,傳入salt和password,生成第一輪的P和S。
然後循環2的cost方次,輪流使用password和salt作為參數去生成P和S,最後返回。
最後看一下ExpandKey的實現:
FunctionExpandKeyInput:password:arrayofBytes(1..72bytes)UTF-8encodedpasswordsalt:Byte[16]randomsaltP:..S4:UInt32[1024]Four1KBSBoxesOutput:P:arrayofUInt32Arrayof18per-roundsubkeysS1..S4:UInt32[1024]Four1KBSBoxes//<-1to18doPn<-Pnxorpassword[32(n-1)..32n-1]//treatthepasswordascyclic//Treatthe128-bitsaltastwo64-bithalves(theBlowfishblocksize).saltHalf[0]<-salt[0..63]//Lower64-bitsofsaltsaltHalf[1]<-salt[64..127]//Upper64-bitsofsalt//Initializean8-byte(64-bit)bufferwithallzeros.block<-0//MixinternalstateintoP-boxesforn<-1to9do//xor64-bitblockwitha64-bitsalthalfblock<-blockxorsaltHalf[(n-1)mod2]//[0],andsaltHalf[1]//<-Encrypt(P,S,block)P2n<-block[0..31]//lower32-bitsofblockP2n+1<-block[32..63]//upper32-bitsblock//-boxesofstatefori<-1to4doforn<-0to127doblock<-Encrypt(state,blockxorsalt[64(n-1)..64n-1])//asaboveSi[2n]<-block[0..31]//lower32-bitsSi[2n+1]<-block[32..63]//upper32-bitsreturnstateExpandKey主要用來生成P和S,演算法的生成比較復雜,大家感興趣的可以詳細研究一下。
bcrypthash的結構我們可以使用bcrypt來加密密碼,最終以bcrypthash的形式保存到系統中,一個bcrypthash的格式如下:
$2b$[cost]$[22charactersalt][31characterhash]比如:
$2a$10$\__//\____________________/\_____________________________/AlgCostSaltHash上面例子中,$2a$表示的hash演算法的唯一標志。這里表示的是bcrypt演算法。
10表示的是代價因子,這里是2的10次方,也就是1024輪。
N9qo8uLOickgx2ZMRZoMye是16個位元組(128bits)的salt經過base64編碼得到的22長度的字元。
最後的是24個位元組(192bits)的hash,經過bash64的編碼得到的31長度的字元。
hash的歷史這種hash格式是遵循的是OpenBSD密碼文件中存儲密碼時使用的MolarCryptFormat格式。最開始的時候格式定義是下面的:
$1$:MD5-basedcrypt('md5crypt')
$2$:Blowfish-basedcrypt('bcrypt')
$sha1$:SHA-1-basedcrypt('sha1crypt')
$5$:SHA-256-basedcrypt('sha256crypt')
$6$:SHA-512-basedcrypt('sha512crypt')
但是最初的規范沒有定義如何處理非ASCII字元,也沒有定義如何處理null終止符。修訂後的規范規定,在hash字元串時:
String必須是UTF-8編碼
必須包含null終止符
因為包含了這些改動,所以bcrypt的版本號被修改成了$2a$。
但是在2011年6月,因為PHP對bcypt的實現crypt_blowfish中的一個bug,他們建議系統管理員更新他們現有的密碼資料庫,用$2x$代替$2a$,以表明這些哈希值是壞的(需要使用舊的演算法)。他們還建議讓crypt_blowfish對新演算法生成的哈希值使用頭$2y$。當然這個改動只限於PHP的crypt_blowfish。
然後在2014年2月,在OpenBSD的bcrypt實現中也發現了一個bug,他們將字元串的長度存儲在無符號char中(即8位Byte)。如果密碼的長度超過255個字元,就會溢出來。
因為bcrypt是為OpenBSD創建的。所以當他們的庫中出現了一個bug時,他們決定將版本號升級到$2b$。
最通俗的解讀,最深刻的干貨,最簡潔的教程,眾多你不知道的小技巧等你來發現!
歡迎關注我的公眾號:「程序那些事」,懂技術,更懂你!