SHA:安全散列算法簡析 附實(shí)例
前言
體能狀態(tài)先于精神狀態(tài),習(xí)慣先于決心,聚焦先于喜好。
SHA算法簡介
1.1 概述
SHA (Secure Hash Algorithm,譯作安全散列算法) 是美國國家安全局 (NSA) 設(shè)計(jì),美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST) 發(fā)布的一系列密碼散列函數(shù)。正式名稱為 SHA 的家族第一個(gè)成員發(fā)布于 1993年。然而人們給它取了一個(gè)非正式的名稱 SHA-0 以避免與它的后繼者混淆。兩年之后, SHA-1,第一個(gè) SHA 的后繼者發(fā)布了。 另外還有四種變體,曾經(jīng)發(fā)布以提升輸出的范圍和變更一些細(xì)微設(shè)計(jì): SHA-224, SHA-256, SHA-384 和 SHA-512 (這些有時(shí)候也被稱做 SHA-2)。
SHA家族的五個(gè)算法,分別是SHA-1、SHA-224、SHA-256、SHA-384,和SHA-512,由美國國家安全局(NSA)所設(shè)計(jì),并由美國國家標(biāo)準(zhǔn)與技術(shù)研究院(NIST)發(fā)布;是美國的政府標(biāo)準(zhǔn)。后四者有時(shí)并稱為SHA-2。SHA-1在許多安全協(xié)定中廣為使用,包括TLS和SSL、PGP、SSH、S/MIME和IPsec,曾被視為是MD5(更早之前被廣為使用的雜湊函數(shù))的后繼者。但SHA-1的安全性如今被密碼學(xué)家嚴(yán)重質(zhì)疑;雖然至今尚未出現(xiàn)對SHA-2有效的攻擊,它的算法跟SHA-1基本上仍然相似;因此有些人開始發(fā)展其他替代的雜湊算法。
1.2 SHA算法原理
SHA-1是一種數(shù)據(jù)加密算法,該算法的思想是接收一段明文,然后以一種不可逆的方式將它轉(zhuǎn)換成一段(通常更?。┟芪?,也可以簡單的理解為取一串輸入碼(稱為預(yù)映射或信息),并把它們轉(zhuǎn)化為長度較短、位數(shù)固定的輸出序列即散列值(也稱為信息摘要或信息認(rèn)證代碼)的過程。
單向散列函數(shù)的安全性在于其產(chǎn)生散列值的操作過程具有較強(qiáng)的單向性。如果在輸入序列中嵌入密碼,那么任何人在不知道密碼的情況下都不能產(chǎn)生正確的散列值,從而保證了其安全性。SHA將輸入流按照每塊512位(64個(gè)字節(jié))進(jìn)行分塊,并產(chǎn)生20個(gè)字節(jié)的被稱為信息認(rèn)證代碼或信息摘要的輸出。
該算法輸入報(bào)文的長度不限,產(chǎn)生的輸出是一個(gè)160位的報(bào)文摘要。輸入是按512 位的分組進(jìn)行處理的。SHA-1是不可逆的、防沖突,并具有良好的雪崩效應(yīng)。
通過散列算法可實(shí)現(xiàn)數(shù)字簽名實(shí)現(xiàn),數(shù)字簽名的原理是將要傳送的明文通過一種函數(shù)運(yùn)算(Hash)轉(zhuǎn)換成報(bào)文摘要(不同的明文對應(yīng)不同的報(bào)文摘要),報(bào)文摘要加密后與明文一起傳送給接受方,接受方將接受的明文產(chǎn)生新的報(bào)文摘要與發(fā)送方的發(fā)來報(bào)文摘要解密比較,比較結(jié)果一致表示明文未被改動(dòng),如果不一致表示明文已被篡改。
1.3 SHA算法應(yīng)用
SHA算法主要用于被政府部門和私營業(yè)主用來處理敏感的信息。例如,支付機(jī)構(gòu),銀行之間的數(shù)據(jù)傳輸,有的是使用SHA散列算計(jì)進(jìn)行加密。
SHA 安全散列算法
安全散列算法(英語:Secure Hash Algorithm,縮寫為SHA)是一個(gè)密碼散列函數(shù)家族.
和MD5類似,安全散列算法可以根據(jù)字符串生成一定長度的摘要信息,該摘要信息不可逆轉(zhuǎn),且不同的字符串的摘要信息相同的概率極低。
SHA家族
SHA 有多個(gè)算法,有一些已經(jīng)過時(shí)不再推薦使用,有一些是安全度很高的,但是會(huì)降低性能。
SHA1
對于長度小于2^64位的消息,SHA1會(huì)產(chǎn)生一個(gè)160位的消息摘要。
不可以從消息摘要中復(fù)原信息;兩個(gè)不同的消息不會(huì)產(chǎn)生同樣的消息摘要,(但會(huì)有1x10 ^ 48分之一的機(jī)率出現(xiàn)相同的消息摘要,一般使用時(shí)忽略)。
可以用于校驗(yàn)信息是否被篡改,比如數(shù)字證書的簽名
已經(jīng)不安全了,所以數(shù)字簽名證書多用SHA256
SHA256
SHA256 從功能上來說和 SHA1類似,一般也用于信息摘要,算法使用的哈希值長度是256位
用于數(shù)字證書的簽名,一般數(shù)據(jù)的簽名,目前流行的安全散列算法
SHA384、SHA512
內(nèi)容略,更安全,也更消耗性能,截止2019年8月20日,這兩種算法都還沒有大范圍推薦使用,市面上推薦的是 SHA256
安全性
目前而言,SHA1 不安全了,SHA256還是安全的
但是從兼容性來說,很多系統(tǒng)依舊支持SHA1,但是最新的則會(huì)要求是SHA256
Java 中的 SHA
使用 commons-codec
可以使用 Apache 提供的 jar 包 commons-codec
Maven 依賴如下
<dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>1.10</version> </dependency>
代碼舉例
結(jié)果是字節(jié)數(shù)組,轉(zhuǎn)化為 16進(jìn)制展示
Java
import org.apache.commons.codec.digest.DigestUtils; public class ShaTest { public static void main(String [] args){ String str="123"; String sha1HexStr=DigestUtils.sha1Hex(str.getBytes()); System.out.println("SHA1"+":"+sha1HexStr.length()+";"+sha1HexStr); String sha256HexStr=DigestUtils.sha256Hex(str.getBytes()); System.out.println("SHA256"+":"+sha256HexStr.length()+";"+sha256HexStr); String sha384HexStr=DigestUtils.sha384Hex(str.getBytes()); System.out.println("SHA384"+":"+sha384HexStr.length()+";"+sha384HexStr); String sha512HexStr=DigestUtils.sha512Hex(str.getBytes()); System.out.println("SHA512"+":"+sha512HexStr.length()+";"+sha512HexStr); } }
結(jié)果-使用16進(jìn)制展示
SHA1:40;40bd001563085fc35165329ea1ff5c5ecbdbbeef
SHA256:64;a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3
SHA384:96;9a0a82f0c0cf31470d7affede3406cc9aa8410671520b727044eda15b4c25532a9b5cd8aaf9cec4919d76255b6bfb00f
SHA512:128;3c9909afec25354d551dae21590bb26e38d53f2173b8d3dc3eee4c047e7ab1c1eb8b85103e3be7ba613b31bb5c9c36214dc9f14a42fd7a2fdb84856bca5c44c2
下面是其他網(wǎng)友的補(bǔ)充
java代碼實(shí)現(xiàn)SHA算法
package cn.mars.app.txn.wanglian; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class Sha1Util { /** * SHA1簽名 * @param paramStr 要加簽的字符串 * @return */ public static String SHA1(String paramStr) { MessageDigest alg; String result = ""; String tmp = ""; try { alg = MessageDigest.getInstance("SHA-1"); alg.update(paramStr.getBytes()); byte[] bts = alg.digest(); for (int i = 0; i < bts.length; i++) { tmp = (Integer.toHexString(bts[i] & 0xFF)); if (tmp.length() == 1) result += "0"; result += tmp; } } catch (NoSuchAlgorithmException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; } public static void main(String[] args) { String sha1 = SHA1("111"); System.out.println(sha1); } }
經(jīng)過加密后的字符串的個(gè)數(shù)是固定的:40
package com.enterise.test; public class SHA1 { private final int[] abcde = { 0x67452301,0xefcdab89,0x98badcfe, 0x10325476,0xc3d2e1f0 }; // 摘要數(shù)據(jù)存儲(chǔ)數(shù)組 private int[] digestInt = new int[5]; // 計(jì)算過程中的臨時(shí)數(shù)據(jù)存儲(chǔ)數(shù)組 private int[] tmpData = new int[80]; // 測試 public static void main(String[] args) { String param = ""; System.out.println("加密前:" + param); System.out.println("length-->"+param.length()); String digest = new SHA1().getDigestOfString(param.getBytes()); System.out.println("加密后:" + digest); System.out.println("length-->"+digest.length()); } // 計(jì)算sha-1摘要 private int process_input_bytes(byte[] bytedata) { // 初試化常量 System.arraycopy(abcde,0,digestInt,0,abcde.length); // 格式化輸入字節(jié)數(shù)組,補(bǔ)10及長度數(shù)據(jù) byte[] newbyte = byteArrayFormatData(bytedata); // 獲取數(shù)據(jù)摘要計(jì)算的數(shù)據(jù)單元個(gè)數(shù) int MCount = newbyte.length / 64; // 循環(huán)對每個(gè)數(shù)據(jù)單元進(jìn)行摘要計(jì)算 for (int pos = 0; pos < MCount; pos++) { // 將每個(gè)單元的數(shù)據(jù)轉(zhuǎn)換成16個(gè)整型數(shù)據(jù),并保存到tmpData的前16個(gè)數(shù)組元素中 for (int j = 0; j < 16; j++) { tmpData[j] = byteArrayToInt(newbyte,(pos * 64) + (j * 4)); } // 摘要計(jì)算函數(shù) encrypt(); } return 20; } // 格式化輸入字節(jié)數(shù)組格式 private byte[] byteArrayFormatData(byte[] bytedata) { // 補(bǔ)0數(shù)量 int zeros = 0; // 補(bǔ)位后總位數(shù) int size = 0; // 原始數(shù)據(jù)長度 int n = bytedata.length; // 模64后的剩余位數(shù) int m = n % 64; // 計(jì)算添加0的個(gè)數(shù)以及添加10后的總長度 if (m < 56) { zeros = 55 - m; size = n - m + 64; } else if (m == 56) { zeros = 63; size = n + 8 + 64; } else { zeros = 63 - m + 56; size = (n + 64) - m + 64; } // 補(bǔ)位后生成的新數(shù)組內(nèi)容 byte[] newbyte = new byte[size]; // 復(fù)制數(shù)組的前面部分 System.arraycopy(bytedata,0,newbyte,0,n); // 獲得數(shù)組Append數(shù)據(jù)元素的位置 int l = n; // 補(bǔ)1操作 newbyte[l++] = (byte) 0x80; // 補(bǔ)0操作 for (int i = 0; i < zeros; i++) { newbyte[l++] = (byte) 0x00; } // 計(jì)算數(shù)據(jù)長度,補(bǔ)數(shù)據(jù)長度位共8字節(jié),長整型 long N = (long) n * 8; byte h8 = (byte) (N & 0xFF); byte h7 = (byte) ((N >> 8) & 0xFF); byte h6 = (byte) ((N >> 16) & 0xFF); byte h5 = (byte) ((N >> 24) & 0xFF); byte h4 = (byte) ((N >> 32) & 0xFF); byte h3 = (byte) ((N >> 40) & 0xFF); byte h2 = (byte) ((N >> 48) & 0xFF); byte h1 = (byte) (N >> 56); newbyte[l++] = h1; newbyte[l++] = h2; newbyte[l++] = h3; newbyte[l++] = h4; newbyte[l++] = h5; newbyte[l++] = h6; newbyte[l++] = h7; newbyte[l++] = h8; return newbyte; } private int f1(int x,int y,int z) { return (x & y) | (~x & z); } private int f2(int x,int y,int z) { return x ^ y ^ z; } private int f3(int x,int y,int z) { return (x & y) | (x & z) | (y & z); } private int f4(int x,int y) { return (x << y) | x >>> (32 - y); } // // 單元摘要計(jì)算函數(shù) private void encrypt() { for (int i = 16; i <= 79; i++) { tmpData[i] = f4(tmpData[i - 3] ^ tmpData[i - 8] ^ tmpData[i - 14] ^ tmpData[i - 16],1); } int[] tmpabcde = new int[5]; for (int i1 = 0; i1 < tmpabcde.length; i1++) { tmpabcde[i1] = digestInt[i1]; } for (int j = 0; j <= 19; j++) { int tmp = f4(tmpabcde[0],5) + f1(tmpabcde[1],tmpabcde[2],tmpabcde[3]) + tmpabcde[4] + tmpData[j] + 0x5a827999; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1],30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int k = 20; k <= 39; k++) { int tmp = f4(tmpabcde[0],5) + f2(tmpabcde[1],tmpabcde[2],tmpabcde[3]) + tmpabcde[4] + tmpData[k] + 0x6ed9eba1; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1],30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int l = 40; l <= 59; l++) { int tmp = f4(tmpabcde[0],5) + f3(tmpabcde[1],tmpabcde[2],tmpabcde[3]) + tmpabcde[4] + tmpData[l] + 0x8f1bbcdc; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1],30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int m = 60; m <= 79; m++) { int tmp = f4(tmpabcde[0],5) + f2(tmpabcde[1],tmpabcde[2],tmpabcde[3]) + tmpabcde[4] + tmpData[m] + 0xca62c1d6; tmpabcde[4] = tmpabcde[3]; tmpabcde[3] = tmpabcde[2]; tmpabcde[2] = f4(tmpabcde[1],30); tmpabcde[1] = tmpabcde[0]; tmpabcde[0] = tmp; } for (int i2 = 0; i2 < tmpabcde.length; i2++) { digestInt[i2] = digestInt[i2] + tmpabcde[i2]; } for (int n = 0; n < tmpData.length; n++) { tmpData[n] = 0; } } // 4字節(jié)數(shù)組轉(zhuǎn)換為整數(shù) private int byteArrayToInt(byte[] bytedata,int i) { return ((bytedata[i] & 0xff) << 24) | ((bytedata[i + 1] & 0xff) << 16) | ((bytedata[i + 2] & 0xff) << 8) | (bytedata[i + 3] & 0xff); } // 整數(shù)轉(zhuǎn)換為4字節(jié)數(shù)組 private void intToByteArray(int intValue,byte[] byteData,int i) { byteData[i] = (byte) (intValue >>> 24); byteData[i + 1] = (byte) (intValue >>> 16); byteData[i + 2] = (byte) (intValue >>> 8); byteData[i + 3] = (byte) intValue; } // 將字節(jié)轉(zhuǎn)換為十六進(jìn)制字符串 private static String byteToHexString(byte ib) { char[] Digit = { '0','1','2','3','4','5','6','7','8','9','A', 'B','C','D','E','F' }; char[] ob = new char[2]; ob[0] = Digit[(ib >>> 4) & 0X0F]; ob[1] = Digit[ib & 0X0F]; String s = new String(ob); return s; } // 將字節(jié)數(shù)組轉(zhuǎn)換為十六進(jìn)制字符串 private static String byteArrayToHexString(byte[] bytearray) { String strDigest = ""; for (int i = 0; i < bytearray.length; i++) { strDigest += byteToHexString(bytearray[i]); } return strDigest; } // 計(jì)算sha-1摘要,返回相應(yīng)的字節(jié)數(shù)組 public byte[] getDigestOfBytes(byte[] byteData) { process_input_bytes(byteData); byte[] digest = new byte[20]; for (int i = 0; i < digestInt.length; i++) { intToByteArray(digestInt[i],digest,i * 4); } return digest; } // 計(jì)算sha-1摘要,返回相應(yīng)的十六進(jìn)制字符串 public String getDigestOfString(byte[] byteData) { return byteArrayToHexString(getDigestOfBytes(byteData)); } }
到此這篇關(guān)于SHA:安全散列算法的文章就介紹到這了,更多相關(guān)SHA安全散列算法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
微信應(yīng)用號(hào)(小程序)入門安裝教程及IDE(破解版)下載
這篇文章主要介紹了微信應(yīng)用號(hào)(小程序)入門安裝教程及IDE下載的相關(guān)資料,需要的朋友可以參考下2016-09-09matlab中乘法“*”和點(diǎn)乘“.*”;除法“/”和點(diǎn)除“./”的聯(lián)系和區(qū)別
這篇文章主要介紹了matlab中乘法“*”和點(diǎn)乘“.*”;除法“/”和點(diǎn)除“./”的聯(lián)系和區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12網(wǎng)站統(tǒng)計(jì)中的數(shù)據(jù)收集原理及實(shí)現(xiàn)
目前主流的數(shù)據(jù)收集方式基本都是基于javascript的。本文將簡要分析這種數(shù)據(jù)收集的原理,并一步一步實(shí)際搭建一個(gè)實(shí)際的數(shù)據(jù)收集系統(tǒng)2013-09-09淺談Visual?Studio和Visual?Studio?Code(VSCode)的區(qū)別及如何選擇
Visual Studio和VSCode兩者都是 Microsoft 制造的,它們有著相似的名稱,盡管它們的名字相似,但它們的功能卻大不相同,本文主要介紹了Visual?Studio和Visual?Studio?Code(VSCode)的區(qū)別,感興趣的可以了解一下2024-06-06Source?Insight?4.0.093?安裝破解詳細(xì)圖文教程
這篇文章主要介紹了Source?Insight?4.0.093?安裝破解詳細(xì)圖文教程,source?insight?4是一款非常強(qiáng)大的程序編輯器,如果你沒有一款合適的代碼編輯器,那么這款軟件不妨試試,可能你會(huì)喜歡2022-08-08GitHub 熱門:別再用 print 輸出來調(diào)試代碼了
本文給大家分享GitHub 熱門:別再用 print 輸出來調(diào)試代碼了的詳細(xì)解說,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-04-04阿里巴巴開源 Dragonwell JDK 最新版本 8.1.1-GA 發(fā)布
距離 Dragonwell JDK 第一個(gè)正式版本 8.0.0-GA 發(fā)布已經(jīng)過去 3 個(gè)月了,項(xiàng)目在 Github 上的 stars 繼續(xù)攀升達(dá)到了 1900。今天我們帶來了最新版本 8.1.1-GA 的發(fā)布,包含了全新的特性和更新,需要的朋友可以參考下2019-10-10