日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA实现SHA256算法

發布時間:2023/12/10 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA实现SHA256算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?時間:2022年2月11日14:04:54

來源參考:SHA256算法原理詳解_隨煜而安的專欄-CSDN博客_sha256https://blog.csdn.net/u011583927/article/details/80905740

?代碼參考:

SHA256算法原理和代碼實現(java) - harara-小念 - 博客園 (cnblogs.com)https://www.cnblogs.com/kiko2014551511/p/15609112.htmlSHA256轉換工具:Generate a SHA-256 encrypted hash (online-convert.com)https://hash.online-convert.com/sha256-generator

下面是文檔的偽代碼說明,中文為我個人的理解,具體說明可以參考第一篇文章,那邊說得比較詳細,這里只是嚴格按照偽代碼進行JAVA語言的翻譯和實現。

// Note: All variables are unsigned 32 bits and wrap modulo 232 when calculating// 注:計算時,所有變量均為無符號32位,并以232模換行 // // // Initialize variables // (first 32 bits of the fractional parts of the square roots of the first 8 primes 2..19):// 前8個質數的平方根的小數部分,32位 // h0 := 0x6a09e667 // h1 := 0xbb67ae85 // h2 := 0x3c6ef372 // h3 := 0xa54ff53a // h4 := 0x510e527f // h5 := 0x9b05688c // h6 := 0x1f83d9ab // h7 := 0x5be0cd19 // // // Initialize table of round constants // (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311):// 前64個質數的立方根的小數部分,32位 // k[0..63] := // 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, // 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, // 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, // 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, // 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, // 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, // 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, // 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 // // // Pre-processing: 預處理 // append the bit '1' to the message 先添加 “1” // append k bits '0', where k is the minimum number >= 0 such that the resulting message // length (in bits) is congruent to 448(mod 512) 補0 到模512取余后長度為448 // append length of message (before pre-processing), in bits, as 64-bit big-endian integer 添加64位源數據的長度 // // // Process the message in successive 512-bit chunks: 將消息分為512位的塊(chunk) // break message into 512-bit chunks // for each chunk// 對于每一個塊 // break chunk into sixteen 32-bit big-endian words w[0..15]// 將每個塊分為16個,每個32位的字(word) // // Extend the sixteen 32-bit words into sixty-four 32-bit words: 將16個32位字擴展為64個32位字,前16個不變 // for i from 16 to 63// 從第16到63個轉換方式 // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor(w[i-15] rightshift 3) // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor(w[i-2] rightshift 10) // w[i] := w[i-16] + s0 + w[i-7] + s1 // // Initialize hash value for this chunk: // a := h0 // b := h1 // c := h2 // d := h3 // e := h4 // f := h5 // g := h6 // h := h7 // // Main loop: // for i from 0 to 63 // s0 := (a rightrotate 2) xor (a rightrotate 13) xor(a rightrotate 22) // maj := (a and b) xor (a and c) xor(b and c) // t2 := s0 + maj // s1 := (e rightrotate 6) xor (e rightrotate 11) xor(e rightrotate 25) // ch := (e and f) xor ((not e) and g) // t1 := h + s1 + ch + k[i] + w[i] // h := g // g := f // f := e // e := d + t1 // d := c // c := b // b := a // a := t1 + t2 // // Add this chunk's hash to result so far: // h0 := h0 + a // h1 := h1 + b // h2 := h2 + c // h3 := h3 + d // h4 := h4 + e // h5 := h5 + f // h6 := h6 + g // h7 := h7 + h // // Produce the final hash value (big-endian): // digest = hash = h0 append h1 append h2 append h3 append h4 append h5 append h6 append h7

?簡單總結一下流程:

1.將輸入的文本轉化為二進制(這里用了String,而且受到String長度的限制(2^16),所以不能代表所有的場景)

對應方法:toBinary(String in)

2. 規范化源數據。對應方法:addZeroTo512(StringBuilder binaryIn)

2.1 在二進制后面補一個“1”

2.2 在后面補0,直到整個長度按512取模余數為448,為什么是448呢?因為下面還有講

2.3 再加上64位的源數據長度

總之,最后得到的長度肯定是512的倍數

3. 計算。cycleCalculation(String binaryIn)

3.1 將整段數據按照512長度(二進制)分段(chunk),分成n段

3.2 將每一段(512位)分成16個“字(word)”,每個字為32位

3.3 將16個字擴充為64個字:

3.3.1 前16個字就是原有的

3.3.2 后面的字按照如下算法來計算:

//?? ??? ??? ?s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor(w[i-15] rightshift 3)
//?? ??? ??? ?s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor(w[i-2] rightshift 10)
//?? ??? ??? ?w[i] := w[i-16] + s0 + w[i-7] + s1

說明1:rightrotate:表示循環右移,在無符號32位數字的情況下,將二進制位右移,右邊溢出的數字補到開頭。簡單的例子(4位):1001-》1100-》0110

說明2:rightshift:表示右移,左邊補0,右邊溢出的數字則舍去。例子(4位):1001-》0100-》0010

3.4 以前面準備的數據,循環64次計算

3.5 將最終的h0到h7組合,為最終的值

代碼中使用long模擬32為無符號整數,也可以用int來直接模擬,但是需要忽略計算中的負數(顯示為負數,但是計算主要涉及到的是二進制的計算,不影響使用,在轉為二進制時,需要手動添加前導0而達到32位長度。)。

具體實現如下:

package sha;public class Sha256 {// 用long模擬32位無符號數據// 前32位0,后32位1的數字,控制數字在32位,4294967295final static long OVER = 0xFFFFFFFFL;// 前8個質數的平方根的小數 // long[] h = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};static long h0 = 0x6a09e667L;static long h1 = 0xbb67ae85L;static long h2 = 0x3c6ef372L;static long h3 = 0xa54ff53aL;static long h4 = 0x510e527fL;static long h5 = 0x9b05688cL;static long h6 = 0x1f83d9abL;static long h7 = 0x5be0cd19L;// 前64個質數的立方根的小數static long[] k = {0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 };public static String getSha256(String in) {StringBuilder stringBuilder = toBinary(in);String string = addZeroTo512(stringBuilder);return cycleCalculation(string);}// 1. 將輸入的字符串轉換為二進制in// string的長度限制在2^32private static StringBuilder toBinary(String in) {StringBuilder stringBuilder = new StringBuilder();char[] inArray = in.toCharArray();for (int i = 0; i < inArray.length; i++) {// 還有前導的0String binary = Integer.toBinaryString(inArray[i]);int count0 = 8 - binary.length();for (int j = 0; j < count0; j++) {stringBuilder.append("0");}stringBuilder.append(binary);}return stringBuilder;}// 2. 將輸入的二進制的長度補齊到512的倍數,原長度l + 1(默認1位1) + k(補齊的0) + 64(64為二進制表示的輸入字符串的長度) private static String addZeroTo512(StringBuilder binaryIn) {int l = binaryIn.length();int k = 959 - (l % 512);if (k > 512) {k = k - 512;}// 默認先添加1binaryIn.append("1");// 添加k個0for (int i = 0; i < k; i++) {binaryIn.append("0");}// 添加64位的源數據長度String lengthBinary = Integer.toBinaryString(l);int k2 = 64 - lengthBinary.length();for (int i = 0; i < k2; i++) {binaryIn.append("0");}binaryIn.append(lengthBinary);return binaryIn.toString();}// 核心:循環計算/*** * @param binaryIn 通過補位后的源數據* @return*/private static String cycleCalculation(String binaryIn) {// 1. 按照512的長度分成n個消息塊int n = binaryIn.length() / 512;for (int i = 0; i < n; i++) {// 對于每一個塊// 2. 每個消息塊分成16個32位的“字”String[] wString = new String[16];for (int j = 0; j < 16; j++) {wString[j] = binaryIn.substring(32 * j, 32 + 32 * j);}// 3. 將16個字擴充為64個字,轉換方法long[] w = new long[64];for (int j = 0; j < wString.length; j++) {// 將二進制的string轉為10進制的longw[j] = Long.parseLong(wString[j], 2);} // s0 := (w[i-15] rightrotate 7) xor (w[i-15] rightrotate 18) xor(w[i-15] rightshift 3) // s1 := (w[i-2] rightrotate 17) xor (w[i-2] rightrotate 19) xor(w[i-2] rightshift 10) // w[i] := w[i-16] + s0 + w[i-7] + s1for (int j = 16; j < 64; j++) {long s0 = ((rightRotate(w[j - 15], 7)) ^ rightRotate(w[j - 15], 18) ^ (rightShift(w[j - 15], 3))) & OVER;long s1 = ((rightRotate(w[j - 2], 17)) ^ (rightRotate(w[j - 2], 19)) ^ (rightShift(w[j - 2], 10))) & OVER;w[j] = (w[j - 16] + s0 + w[j - 7] + s1) & OVER;}// 4. hash初始化long a = h0;long b = h1;long c = h2;long d = h3;long e = h4;long f = h5;long g = h6;long h = h7;// 5. 64次循環for (int j = 0; j < 64; j++) { // s0 := (a rightrotate 2) xor (a rightrotate 13) xor(a rightrotate 22) // maj := (a and b) xor (a and c) xor(b and c) // t2 := s0 + maj // s1 := (e rightrotate 6) xor (e rightrotate 11) xor(e rightrotate 25) // ch := (e and f) xor ((not e) and g) // t1 := h + s1 + ch + k[i] + w[i] // h := g // g := f // f := e // e := d + t1 // d := c // c := b // b := a // a := t1 + t2long s0 = (rightRotate(a, 2) ^ (rightRotate(a, 13)) ^ (rightRotate(a, 22))) & OVER;long maj = ((a & b) ^ (a & c) ^ (b & c)) & OVER;long t2 = (s0 + maj) & OVER;long s1 = ((rightRotate(e, 6)) ^ (rightRotate(e, 11)) ^ (rightRotate(e, 25))) & OVER;long ch = ((e & f) ^ ((~e) & g)) & OVER;long t1 = (h + s1 + ch + k[j] + w[j]) & OVER;h = g;g = f;f = e;e = (d + t1) & OVER;d = c;c = b;b = a;a = (t1 + t2) & OVER;}h0 = (h0 + a) & OVER;h1 = (h1 + b) & OVER;h2 = (h2 + c) & OVER;h3 = (h3 + d) & OVER;h4 = (h4 + e) & OVER;h5 = (h5 + f) & OVER;h6 = (h6 + g) & OVER;h7 = (h7 + h) & OVER;}// 把h0到h7拼起來就是所需要的值了。return getHash(h0) + getHash(h1) + getHash(h2) + getHash(h3) + getHash(h4) + getHash(h5) + getHash(h6) + getHash(h7);}// 把long型的數字轉換為字符串,只取后32位的數字,不足則前補0,前面多余的則舍去private static String getHash(long h) {String hash = Long.toHexString(h);StringBuilder result = new StringBuilder();if (hash.length() > 8) {result.append(hash.substring(hash.length() - 8, hash.length()));} else {int count0 = 8 - hash.length();for (int i = 0; i < count0; i++) {result.append("0");}result.append(hash);}return result.toString();}/*** 右旋n位,循環右移n位,對于32位無符號數字而言,末尾的數字被移到開頭* 用long模擬32位無符號數字,末尾被移出的數字替換到開頭,相當于左移了* @param x* @param n* @return*/private static long rightRotate(long x, int n) {long wei = (0 << n) - 1; // 這個操作有點疑問x = ((wei & (x & OVER)) << (32 - n)) | (x & OVER) >> n;return x;}/*** 按位右移n位,末尾的數字舍去,前面補0,相當于>>>,無符號右移* @param x* @param n* @return*/private static long rightShift(long x, int n) { // return (x&0xFFFFFFFFL)>>n;return (x & OVER) >>> n;} }

測試:

public static void main(String[] args) {System.out.println(Sha256.getSha256("a"));}

輸出:

ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb

總結

以上是生活随笔為你收集整理的JAVA实现SHA256算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。