在 C++ 中转换为 SHA256
SHA256 转换是一种加密哈希技术,自 90 年代以来一直在使用,但在比特币和区块链出现后获得了重视。
它使用一种不可逆的单向哈希技术,这意味着最终答案永远无法逆转回其原始消息,从而使其非常安全。
最终消息以 256 位格式表示,因此其名称中包含 256。
SHA256 哈希算法
用于 SHA256 转换的哈希算法有四个部分:填充、初始缓冲区、消息调度的创建和压缩。 让我们了解如何用 C++ 实现它们。
SHA256 中的填充位
SHA256 转换的哈希算法的第一步是填充原始消息。 必须进行填充以使消息具有 448 位,比 512 位少 64 位。
如果需要填充包含字母 abc 的消息,则前 24 位将填充 abc 的二进制值,后面是 424 位零,总共 448 位。 长度将存储在最后 64 位中。
SHA256 中的填充长度
原始消息在用于散列之前会被填充以使其长度为 512 位。 必须对消息进行填充,以便前 448 位存储消息,而其余 64 位数据则进行长度填充。
这些未使用的位用于跟踪消息的长度。 这 64 位除第一位必须为 1 外,其余的最后一位数字用于存储消息长度,大部分都用零填充。
SHA256 中的哈希缓冲区
SHA256转换算法需要初始化缓冲区或哈希值以进行压缩。 这些缓冲区称为状态寄存器。
在 SHA256 哈希中,该过程始终从同一组状态寄存器开始,然后重复附加从消息摘要中获取的新值。
共有8个状态寄存器。 为了更好地理解,将这些状态寄存器视为携带预定义随机值的槽。
随机值是通过取前 8 个素数的平方根的模,然后乘以 2 的 32 次方得出的。
SHA256 算法使用此方法创建 8 个状态寄存器。
在 C++ 中,这些状态寄存器是通过将这 8 个素数的十六进制值直接分配到数组中来初始化的。
初始化演示如下:
void SHA256::state_register()
{
s_r[0] = 0x6a09e667;
s_r[1] = 0xbb67ae85;
s_r[2] = 0x3c6ef372;
s_r[3] = 0xa54ff53a;
s_r[4] = 0x510e527f;
s_r[5] = 0x9b05688c;
s_r[6] = 0x1f83d9ab;
s_r[7] = 0x5be0cd19;
m_len = 0;
m_tot_len = 0;
}
还需要另一组键,它在数组中存储 64 个十六进制值,范围从 hash_keys[0]
到 hash_keys[63]
。
const unsigned int SHA256::hash_keys[64] =
{0xef6685ff, 0x38fd3da, 0x94402b15, 0xc67cb7b7, 0x780e38cd, 0xe7440103, 0x5d415e6e, 0xbb7c2922, 0xf1df8153, 0x5f47e03f, 0x8c658cf7, 0x95ca718, 0x678d5436, 0xda792dc4, 0x4aa3778b, 0x449e3719, 0x23913e93, 0xfdb2380c, 0x2e82c771, 0x5bb60bcd, 0x13f53664, 0x174004ae, 0xc338e749, 0x199adec, 0x28a3dcfe, 0x36fc4894, 0xe1a019cc, 0x59b7fe92, 0x5b007153, 0x1bb32e0d, 0x2cba796a, 0x3a159148, 0x266d057b, 0xbc9c1d52, 0x17601e7, 0x39b3ccc7, 0x10367db5, 0xa3558c1b, 0xbf98037f, 0x6fbffc84, 0xef54e44, 0x961a993a, 0x33e5297b, 0xd2dce255, 0x7fe9864c, 0xfdd93543, 0xc62f137, 0x14eea06b, 0x2f106df2, 0xf7956237, 0xd053bbca, 0x7a449ecf, 0x8af91f64, 0x9f34a155, 0x663002e3, 0x7acf8b9c, 0xb0c90a35, 0xa71bba61, 0xc2d6c5a3, 0x9af20609, 0x8cfc5464, 0x29d95bcf, 0x7c5478b, 0xde9f4ec3
};
SHA256 中的消息时间表
消息调度由 16 个字组成,并根据每个消息块创建。 每个都是 32 位长,该调度表被组装成 16 个不同的二进制数块。
但是,消息块的长度必须为 64 个字。 这是通过编译消息调度中已经存在的单词来创建新块来完成的。
在压缩消息之前需要准备消息调度。 512 位消息块被分解为 16 个 32 位字。
约定是使用 XOR 和 AND 运算等按位运算用现有字创建一个新字。 第 17 个块是使用以下公式创建的:
在哪里,
sigma 0 和 sigma 1 旋转函数的初始化:
#define SHAF_3(x) (R_ROTATE(x, 7) ^ R_ROTATE(x, 18) ^ R_SHFT(x, 3))
#define SHAF_4(x) (R_ROTATE(x, 17) ^ R_ROTATE(x, 19) ^ R_SHFT(x, 10))
创建 W(16) 字:
int m;
int n;
for (m = 0; m < (int) block_nb; m++) {
sub_block = message + (m << 6);
for (n = 0; n < 16; n++) {
SHAF_PACK32(&sub_block[n << 2], &w[n]);
}
for (n = 16; n < 64; n++) {
w[n] = SHAF_4(w[n - 2]) + w[n - 7] + SHAF_3(w[n - 15]) + w[n - 16];
}
for (n = 0; n < 8; n++) {
buffer[n] = s_r[n];
}
这些轮换函数使用块内的现有数据来融合它们,并用许多新位扩展消息调度。
SHA256 压缩
这就是哈希函数的核心。 每个位都被交换在一起并相互叠加以创建最终的消息摘要。
该函数使用我们上面创建的状态寄存器,并将它们与消息调度和原始消息块组合以生成摘要。
每个 SHA256 转换哈希函数在修改之前都以相同的状态寄存器开始。 该函数使用以下命令创建两个临时单词:
这里,Ch(e,f,g)
代表函数的选择,Maj(a,b,c)
代表函数的主函数。 下面详细解释这两个函数。
创建这些临时字后,该函数将两个临时字相加,将状态寄存器中的每个字下移一位,并将添加的字填充到第一个状态寄存器内,并将 T1 添加到寄存器 e。
从下面的代码中可以看出,buffer[]是状态寄存器。 第 8 个寄存器 (buffer[7]) 内的值与第 7 个寄存器 (buffer[6]) 内的值交换。
交换过程继续进行,直到所有寄存器都通过 buffer[0]
获得新值,或者第一个寄存器收到 T1 和 T2 的总和。
此压缩过程对所有 64 个字进行,最后留下更新的状态寄存器。
for (n = 0; n < 64; n++) {
t1 = buffer[7] + SHAF_2(buffer[4]) + CHOICE_OF(buffer[4], buffer[5], buffer[6])
+ hash_keys[n] + w[n];
t2 = SHAF_1(buffer[0]) + MAJORITY_OF(buffer[0], buffer[1], buffer[2]);
buffer[7] = buffer[6];
buffer[6] = buffer[5];
buffer[5] = buffer[4];
buffer[4] = buffer[3] + t1;
buffer[3] = buffer[2];
buffer[2] = buffer[1];
buffer[1] = buffer[0];
buffer[0] = t1 + t2;
}
for (n = 0; n < 8; n++) {
s_r[n] += buffer[n];
这里,CHOICE_OF()
和 MAJORITY_OF 是选择函数和主要函数。 这些定义为:
#define CHOICE_OF(x, y, z) ((x & y) ^ (~x & z))
#define MAJORITY_OF(x, y, z) ((x & y) ^ (x & z) ^ (y & z))
这里:
x & y = x and y
~x = negation of x
^ = XOR
该消息块压缩的最后一部分是获取我们开始时使用的初始哈希值,并将它们与压缩结果相加。 最终的哈希值被转换为十六进制并连接以创建最终的消息摘要。
将纯文本转换为 SHA256 的 C++ 程序
该程序有两部分 - 包含定义的所有基本函数的 SHA256 头文件和主 C++ 程序文件。
C++ SHA256 算法的头文件
#ifndef HASHFUNCTIONS_H
#define HASHFUNCTIONS_H
#include <string>
class hash_functions
{
protected:
typedef unsigned char register_8;
typedef unsigned int register_32;
typedef unsigned long long register_64;
const static register_32 hash_keys[];
static const unsigned int BLOCK_SIZE_of_256 = (512/8);
public:
void stateregister(); //init
void adjust_digest(const unsigned char *text, unsigned int text_len);
void digest_final(unsigned char *digest);
static const unsigned int PADD_SIZE = ( 256 / 8);
protected:
void compress(const unsigned char *message, unsigned int block_nb);
unsigned int s_r_totlen;
unsigned int s_r_len;
unsigned char s_r_block[2*BLOCK_SIZE_of_256];
register_32 s_r[8];
};
std::string sha256(std::string 输出);
#define R_SHFT(x, n) (x >> n) //Right shift function
#define R_ROTATE(x, n) ((x >> n) | (x << ((sizeof(x) << 3) - n))) //Right rotate function
#define L_ROTATE(x, n) ((x << n) | (x >> ((sizeof(x) << 3) - n))) //Left rotate function
#define CHOICE_OF(x, y, z) ((x & y) ^ (~x & z)) //function to find choice of
#define MAJORITY_OF(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) //function to find majority of
#define SHAF_1(x) (R_ROTATE(x, 2) ^ R_ROTATE(x, 13) ^ R_ROTATE(x, 22)) //sigma rotation function
#define SHAF_2(x) (R_ROTATE(x, 6) ^ R_ROTATE(x, 11) ^ R_ROTATE(x, 25)) //sigma rotation function
#define SHAF_3(x) (R_ROTATE(x, 7) ^ R_ROTATE(x, 18) ^ R_SHFT(x, 3)) //sigma0 rotation
#define SHAF_4(x) (R_ROTATE(x, 17) ^ R_ROTATE(x, 19) ^ R_SHFT(x, 10)) //sigma1 rotation
#define SHAF_UNPACK32(x, str) \
{ \
*((str) + 3) = (register_8) ((x) ); \
*((str) + 2) = (register_8) ((x) >> 8); \
*((str) + 1) = (register_8) ((x) >> 16); \
*((str) + 0) = (register_8) ((x) >> 24); \
}
#define SHAF_PACK32(str, x) \
{ \
*(x) = ((register_32) *((str) + 3) ) \
| ((register_32) *((str) + 2) << 8) \
| ((register_32) *((str) + 1) << 16) \
| ((register_32) *((str) + 0) << 24); \
}
#endif
在 C++ 中执行 SHA256 的主文件
#include <iostream>
#include <cstring>
#include <fstream>
#include "hash_functions.h"
const unsigned int hash_functions::hash_keys[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};
void hash_functions::compress(const unsigned char *message, unsigned int block_nb)
{
register_32 w[64];
register_32 buffer[8];
register_32 t1, t2;
const unsigned char *sub_block;
int m;
int n;
for (m = 0; m < (int) block_nb; m++) {
sub_block = message + (m << 6);
for (n = 0; n < 16; n++) {
SHAF_PACK32(&sub_block[n << 2], &w[n]);
}
for (n = 16; n < 64; n++) {
w[n] = SHAF_4(w[n - 2]) + w[n - 7] + SHAF_3(w[n - 15]) + w[n - 16];
}
for (n = 0; n < 8; n++) {
buffer[n] = s_r[n];
}
for (n = 0; n < 64; n++) {
t1 = buffer[7] + SHAF_2(buffer[4]) + CHOICE_OF(buffer[4], buffer[5], buffer[6])
+ hash_keys[n] + w[n];
t2 = SHAF_1(buffer[0]) + MAJORITY_OF(buffer[0], buffer[1], buffer[2]);
buffer[7] = buffer[6];
buffer[6] = buffer[5];
buffer[5] = buffer[4];
buffer[4] = buffer[3] + t1;
buffer[3] = buffer[2];
buffer[2] = buffer[1];
buffer[1] = buffer[0];
buffer[0] = t1 + t2;
}
for (n = 0; n < 8; n++) {
s_r[n] += buffer[n];
}
}
}
void hash_functions::stateregister()
{
s_r[0] = 0x6a09e667;
s_r[1] = 0xbb67ae85;
s_r[2] = 0x3c6ef372;
s_r[3] = 0xa54ff53a;
s_r[4] = 0x510e527f;
s_r[5] = 0x9b05688c;
s_r[6] = 0x1f83d9ab;
s_r[7] = 0x5be0cd19;
s_r_len = 0;
s_r_totlen = 0;
}
void hash_functions::adjust_digest(const unsigned char *text, unsigned int text_len)
{
unsigned int block_nb;
unsigned int new_len, rem_len, tmp_len;
const unsigned char *shifted_message;
tmp_len = BLOCK_SIZE_of_256 - s_r_len;
rem_len = text_len < tmp_len ? text_len : tmp_len;
memcpy(&s_r_block[s_r_len], text, rem_len);
if (s_r_len + text_len < BLOCK_SIZE_of_256) {
s_r_len += text_len;
return;
}
new_len = text_len - rem_len;
block_nb = new_len / BLOCK_SIZE_of_256;
shifted_message = text + rem_len;
compress(s_r_block, 1);
compress(shifted_message, block_nb);
rem_len = new_len % BLOCK_SIZE_of_256;
memcpy(s_r_block, &shifted_message[block_nb << 6], rem_len);
s_r_len = rem_len;
s_r_totlen += (block_nb + 1) << 6;
}
void hash_functions::digest_final(unsigned char *digest)
{
unsigned int block_nb;
unsigned int pm_len;
unsigned int len_b;
int i;
block_nb = (1 + ((BLOCK_SIZE_of_256 - 9)
< (s_r_len % BLOCK_SIZE_of_256)));
len_b = (s_r_totlen + s_r_len) << 3;
pm_len = block_nb << 6;
memset(s_r_block + s_r_len, 0, pm_len - s_r_len);
s_r_block[s_r_len] = 0x80;
SHAF_UNPACK32(len_b, s_r_block + pm_len - 4);
compress(s_r_block, block_nb);
for (i = 0 ; i < 8; i++) {
SHAF_UNPACK32(s_r[i], &digest[i << 2]);
}
}
std::string sha256(std::string input)
{
unsigned char digest[hash_functions::PADD_SIZE];
memset(digest,0,hash_functions::PADD_SIZE);
hash_functions obj = hash_functions();
obj.stateregister();
obj.adjust_digest( (unsigned char*)input.c_str(), input.length());
obj.digest_final(digest);
char buf[2*hash_functions::PADD_SIZE+1];
buf[2*hash_functions::PADD_SIZE] = 0;
for (int i = 0; i < hash_functions::PADD_SIZE; i++)
sprintf(buf+i*2, "%02x", digest[i]);
return std::string(buf);
}
using std::string;
using std::cout;
using std::endl;
int main(int argc, char *argv[])
{
string text_in = "Paris";
string text_out = sha256(text_in);
cout << "Final Output('"<< text_in << "'):" << text_out << endl;
return 0;
}
输出:
sha256('Paris'):5dd272b4f316b776a7b8e3d0894b37e1e42be3d5d3b204b8a5836cc50597a6b1
--------------------------------
Process exited after 0.03964 seconds with return value 0
Press any key to continue . . .
总结
本文详细讲解了使用C++进行SHA256转换的密码学。 散列算法和消息调度的压缩是加密散列的核心,通过代码片段进行演示,以便于理解。
还附带了一个现成的 C++ 程序,可以直接用于学习和回测。
相关文章
C# 中等效的 C++ Map<T1, T2>
发布时间:2024/02/01 浏览次数:147 分类:编程语言
-
可以使用 C# 中的 SortedDictionary
和 Dictionary 类代替 C++ 中的 map 。
C# 中等效的 C++ Map<T1, T2>
发布时间:2024/01/20 浏览次数:187 分类:编程语言
-
可以使用 C# 中的 SortedDictionary
和 Dictionary 类代替 C++ 中的 map 。
如何在 C++ 中实现毫秒级的睡眠
发布时间:2024/01/02 浏览次数:230 分类:C++
-
本文介绍了在 C++ 中使用不同方法暂停程序执行,实现睡眠的方法。本文介绍了在 C++ 中睡眠毫秒的方法。使用 std::this_thread::sleep_for 方法在 C++ 中睡眠
如何在 C++ 中将双精度数四舍五入到整数上
发布时间:2024/01/02 浏览次数:151 分类:C++
-
本文演示了如何在 C++ 中把双精度数四舍五入到整数中。本文将为大家讲解几种在 C++ 中如何将双精度数四舍五入为整数的方法。使用 round() 函数将双精度数四舍五入到整数
如何在 C++ 中以毫秒为单位获取时间
发布时间:2024/01/02 浏览次数:142 分类:C++
-
本文介绍了如何在 C++ 中获取以毫秒为单位的时间。本文将介绍多种 C++ 方法,介绍如何以毫秒为单位获取时间。
如何在 C++ 中把 Char 数组转换为 Int
发布时间:2024/01/02 浏览次数:143 分类:C++
-
本文演示了在 C++ 中把 char 数组转换为 int 类型的方法。本文将介绍将 char 数组转换为 int 类型的 C++ 方法。使用 std::strtol 函数将 char 数组转换为 int 类型
如何在 C++ 中将 ASCII 码转换为字符
发布时间:2024/01/02 浏览次数:520 分类:C++
-
本文介绍了在 C++ 中如何将 ASCII 值转换为 char 的方法。本文将演示关于如何在 C++ 中把 ASCII 值转换为字符的多种方法。在 C++ 中使用赋值运算符将 ASCII 值转换为字符
如何在 C++ 中把十进制转换为二进制
发布时间:2024/01/02 浏览次数:239 分类:C++
-
本文介绍如何在 C++ 中把十进制数转换成二进制数。本文将介绍几种在 C++ 中如何将十进制数转换为二进制表示的方法。在 C++ 中使用自定义定义的函数将十进制数转换为二进制数