最近在项目中遇到sha256算法加密的需求,于是看了一些相关的资料,最后也整理出一些东西,并且参考文档自己实现了一遍:

#define S(a, b)     (((a) >> (b)) | ((a) << (32 - b)))  /* a循环右移b位 *//* sha256逻辑函数 */
#define CH(x, y, z) ((x & y) ^ ((~x) & z))
#define MA(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
#define Σ0(x)       (S(x, 2)^S(x, 13)^S(x, 22))
#define Σ1(x)       (S(x, 6)^S(x, 11)^S(x, 25))
#define σ0(x)       (S(x, 7)^S(x, 18)^(x >> 3))
#define σ1(x)       (S(x, 17)^S(x, 19)^(x >> 10))/*   功能:大小端判断返回: 1小端  0大端  */
int Endian()
{int a = 1;int *p = &a;return (*(char *)p == 1);
}
/*  功能:sha256编码入参:char *Src 源数据  int SrcLen 源数据长度返回值: sha256数据  */
char* MyShaA256Encode(const char *Src, long long SrcLen)
{unsigned long i = 0, T1 = 0, T2 = 0, A = 0, B = 0, C = 0, D = 0, E = 0, F = 0, G = 0, H = 0;unsigned long *p = NULL;unsigned long W[64] = {0};     /* 64个字 */static char shadata[256] = {0};  /* sha256数据缓存 */unsigned long Key[64] =    /* 秘钥表 */{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,};unsigned long Hash[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};    /* 初始哈希值 */long long reallen = (SrcLen * 8) % 512 >= 448 ? ((SrcLen * 8) / 512 + 2) * 64 : ((SrcLen * 8) / 512 + 1) * 64;   /* 补位后长度 */char * processsrc = (char *)calloc(reallen, sizeof(char));    /* 源数据补位后缓存 */if (NULL == processsrc) {return NULL;}/* 预处理 */if (Endian()) {for (i = 0; i < SrcLen; processsrc[i + 3 - 2 * (i % 4)] = Src[i], i++);  /* 小端存法 */processsrc[i + 3 - 2 * (i % 4)] = 1 << 7;  /* 补一个1 */} else {memcpy(processsrc, Src, SrcLen);    /* 大端存法 */*(processsrc + SrcLen) = 1 << 7;    /* 补一个1 */}*((long*)(processsrc + reallen - 4)) = SrcLen << 3;   /* 最后64位代表源数据长度 */*((long*)(processsrc + reallen - 8)) = SrcLen >> 29;for (p = (unsigned long *)processsrc; p < (unsigned long *)(processsrc + reallen); p += 16) {/* 初始化64个字(W) */for (i = 0; i < 16; ++i) {W[i] = *(p + i);}for (i = 16; i < 64; ++i) {W[i] = σ1(W[i - 2]) + W[i - 7] + σ0(W[i - 15]) + W[i - 16];}/* sha256摘要迭代 */A = Hash[0]; B = Hash[1]; C = Hash[2]; D = Hash[3]; E = Hash[4]; F = Hash[5]; G = Hash[6]; H = Hash[7]; for (i = 0; i < 64; ++i) {T1 = H + Σ1(E) + CH(E, F, G) + Key[i] + W[i];T2 = Σ0(A) + MA(A, B, C);H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;}Hash[0] += A, Hash[1] += B, Hash[2] += C, Hash[3] += D, Hash[4] += E, Hash[5] += F, Hash[6] += G, Hash[7] += H;}sprintf(shadata, "%08X%08X%08X%08X%08X%08X%08X%08X", Hash[0], Hash[1], Hash[2], Hash[3], Hash[4], Hash[5], Hash[6], Hash[7]);free(processsrc);printf("sha256: %s\r\n", shadata);return shadata;
}

源码详解:

1、sha256常数

sha256最终输出的是64位字符串,故需要一串64字符的初始哈希值,即源码中的Hash[8],刚好是8*8个字符,其次还需要64个4byte的秘钥,用于摘要迭代,即源码中的Key[64]:

    unsigned long Key[64] =    /* 秘钥表 */{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,};unsigned long Hash[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};    /* 初始哈希值 */
2、补位后长度计算

补位后长度计算遵循这样的原则:在源数据后先添加一位1,再在1后面添加若干个0,知道数据总位数对512求余为512-64=448,最后64位需要填写源数据长度,用于入参SrcLen表示的是原字符串长度(单位是byte),1byte=8bit,所以在计算时需要有*8的操作,具体如下:

long long reallen = (SrcLen * 8) % 512 >= 448 ? ((SrcLen * 8) / 512 + 2) * 64 : ((SrcLen * 8) / 512 + 1) * 64;   /* 补位后长度 */
3、预处理(补位)

将原始数据Src扩展成512位对齐的processsrc数据,此处需要关注的是Src数据默认是低地址->高地址排列传入的,假设需要加密的数据是字符串"12345",传入的是字符串首地址,长度为5byte,这个方法内部看到的是0x31,0x32,0x33,0x34,0x35这些数据,接着以4字节为单位进行加工,首先是0x31323334,将这个数据看成是一个4byte的整体,从低地址到高地址依次存入processsrc,小端机器按0x34,0x33,0x32,0x31存入,大端机器按0x31,0x32,0x33,0x34存入(此步其他数文章里没有提出,本人也不确定是不是这样??),小端最后就是这行代码:

for (i = 0; i < SrcLen; processsrc[i + 3 - 2 * (i % 4)] = Src[i], i++);

大端是这行代码:

memcpy(processsrc, Src, SrcLen);

将源数据存入后,再进行1+n个0的补齐,calloc初始值就是0,所以只需要补齐一个1:,小端补1:

processsrc[i + 3 - 2 * (i % 4)] = 1 << 7;

大端补1:

*(processsrc + SrcLen) = 1 << 7;

最后64位代表源数据长度,继续补齐:

*((long*)(processsrc + reallen - 4)) = SrcLen << 3;
*((long*)(processsrc + reallen - 8)) = SrcLen >> 29;
4、初始化64个字

将每个512位的数据块扩充成64byte,前16个byte将512位数据完全拷贝即可,后面48byte参考文档里面这个公式扩充:

相应的代码是这段:

     for (i = 0; i < 16; ++i) {W[i] = *(p + i);}for (i = 16; i < 64; ++i) {W[i] = σ1(W[i - 2]) + W[i - 7] + σ0(W[i - 15]) + W[i - 16];}
5、摘要迭代

根据官方手册上提供的逻辑图进行操作即可:

代码是这一段:

     A = Hash[0]; B = Hash[1]; C = Hash[2]; D = Hash[3]; E = Hash[4]; F = Hash[5]; G = Hash[6]; H = Hash[7]; for (i = 0; i < 64; ++i) {T1 = H + Σ1(E) + CH(E, F, G) + Key[i] + W[i];T2 = Σ0(A) + MA(A, B, C);H = G, G = F, F = E, E = D + T1, D = C, C = B, B = A, A = T1 + T2;}Hash[0] += A, Hash[1] += B, Hash[2] += C, Hash[3] += D, Hash[4] += E, Hash[5] += F, Hash[6] += G, Hash[7] += H;

接下来就是重复4、5步操作,直到将processsrc 的数据完全处理完,得到一串Hash即sha256的加密数据。

sha256算法细节详解相关推荐

  1. Paxos算法细节详解(一)--通过现实世界描述算法

    Paxos算法细节详解(一)--通过现实世界描述算法 Paxos分析 最近研究paxos算法,看了许多相关的文章,概念还是很模糊,觉得还是没有掌握paxos算法的精髓,所以花了3天时间分析了libpa ...

  2. GNN教程:GraghSAGE算法细节详解!

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:秦州,算法工程师,Datawhale成员 引言 本文为GNN教程的 ...

  3. GNN教程:第六篇Spectral算法细节详解!

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:秦州,算法工程师,Datawhale成员 引言 图神经网络的逐层S ...

  4. 15种区块链共识算法全面详解

    1,摘要 本文尽可能列出所有主要的共识算法,评估各自的优劣之处.共识算法是区块链的核心技术,本文会跟随作者的理解,持续更新.如果读者发现有所遗漏,或是存在错误,希望能通过评论指出. 2,区块链共识算法 ...

  5. html的细节优化,网站页面优化细节详解

    原标题:网站页面优化细节详解 SEO页面优化是继SEO结构优化之后,另一个重要优化地方; 页面标题 在每个页面中的关键位置,出现目标关键词,这是我们做页面优化的基础思路,关键词位置,都有哪些呢? 第一 ...

  6. CRF(条件随机场)与Viterbi(维特比)算法原理详解

    摘自:https://mp.weixin.qq.com/s/GXbFxlExDtjtQe-OPwfokA https://www.cnblogs.com/zhibei/p/9391014.html C ...

  7. 算法:详解布隆过滤器的原理、使用场景和注意事项@知乎.Young Chen

    算法:详解布隆过滤器的原理.使用场景和注意事项@知乎.Young Chen 什么是布隆过滤器 本质上布隆过滤器是一种数据结构,比较巧妙的概率型数据结构(probabilistic data struc ...

  8. JavaScript 面试中常见算法问题详解

    JavaScript 面试中常见算法问题详解,翻译自 https://github.com/kennymkchan/interview-questions-in-javascript.下文提到的很多问 ...

  9. TOPSIS(逼近理想解)算法原理详解与代码实现

    写在前面: 个人理解:针对存在多项指标,多个方案的方案评价分析方法,也就是根据已存在的一份数据,判断数据中各个方案的优劣.中心思想是首先确定各项指标的最优理想值(正理想值)和最劣理想值(负理想解),所 ...

  10. JavaScript数据结构与算法——链表详解(下)

    在JavaScript数据结构与算法--链表详解(上)中,我们探讨了一下链表的定义.实现原理以及单链表的实现.接下来我们进一步了解一下链表的其他内容. 1.双向链表 双向链表实现原理图: 与单向链表不 ...

最新文章

  1. 进程 线程 协程_进程,线程,协程那些事
  2. SQL Server里的 ISNULL 与 Oracle 中的 NULLIF
  3. Servlet请求和响应总结
  4. HDOJ 4253 Two Famous Companies 二分+MST
  5. dataframe 筛选_Spark.DataFrame与Spark.ML简介
  6. Request的getHeader()和getParameter()的区别
  7. c语言数组两个值交换,如可交换两个数组中的元素?
  8. fatal error: Eigen3/Core: 没有那个文件或目录
  9. ES6新特性_ES6语法糖-子类对父类方法的重写---JavaScript_ECMAScript_ES6-ES11新特性工作笔记037
  10. [js]DOM 篇
  11. bootstrap-table初始数据,页面一直显示“正在努力加载数据中,请稍后“
  12. 2022爱分析·营销服务一体化实践报告
  13. php+分割文本文件,python实现:将文本文件分割成多个小文本文件(php也可实现)...
  14. 超全的概率公式和线性代数公式
  15. C#中解决PC端程序多开的问题
  16. JSP——(图片验证码)
  17. Linux阅码场原创精华文章汇总
  18. KIngcms 5.1版本增加站内链接功能自动给指定关键词加上链接
  19. kirin710f是什么处理器_HUAWEIKirin710F处理器是什么机型?
  20. 批改网中的作文不能粘贴怎么办?

热门文章

  1. 汇编语言程序设计-钱晓捷(第五版)学习笔记目录
  2. java struts2 验证码,struts2中验证码的生成和使用
  3. 黑暗欺骗恐怖游戏c++代码完整
  4. linux 批量ping ip脚本,Linux下批量ping某个网段ip的脚本
  5. SpringBoot配置文件application.yml属性解读及使用学习记录
  6. 网络专家预测未来互联网发展十大趋势
  7. 迅雷极速版禁止自动升级的方法
  8. HTML5 汉字上方添加拼音标注 ruby、rp、rt
  9. 有效的数独 python_LeetCode 36. 有效的数独 | Python
  10. webstorm破解之jar包破解(2018)