sha512 实现 c++(用于学习目的)不生成 temp1 值,但给出了一个非常相似的答案
sha512 implementation c++ (made for learning purposes) doesn't generate temp1 value but gives a wierdly similar answer
如果您查看迭代 0 中的 temp1 值。您会看到我得到的是 0xb37b0cfa1b96e8a0,而我应该得到的是 0x1b37b0cfa1b96e8a0。为什么 0x1 没有出现在我的?这是与数据类型相关的问题吗?它会溢出还是我对 temp1 的实现有误?
顺便说一下,我对“abc”进行了哈希运算。
对消息进行哈希处理:SHA512 hash("abc");
代码:
/*
* github: kibnakamoto
* Created on: Dec. 5, 2021
* Author: Taha Canturk
* More Info: github.com/kibnakamoto/sha512.cpp/blob/main/README.md
*/
#include <iostream>
#include <string>
#include <cstring>
#include <stdint.h>
// choice = (x ∧ y) ⊕ (¯x ∧ z)
inline uint64_t Ch(uint64_t e, uint64_t f, uint64_t g) {
return ((e bitand f)xor(~e bitand g));
}
// #define Ch(x,y,z) ((x bitand y)xor(~x bitand z))
// // majority = (x ∧ y) ⊕ (x ∧ z) ⊕ (y ∧ z)
inline uint64_t Maj(uint64_t a, uint64_t b, uint64_t c) {
return ((a & b)^(a & c)^(b & c));
}
// // binary operators
inline uint64_t Shr(uint64_t x, unsigned int n) {
return (x >> n);
}
inline uint64_t Rotr(uint64_t x, unsigned int n) {
return ( (x >> n)|(x << (sizeof(x)<<3)-n) );
}
// length which is __uint128_t in 2 uint64_t integers
inline std::pair<uint64_t,uint64_t> to2_uint64(__uint128_t source) {
constexpr const __uint128_t bottom_mask = (__uint128_t{1} << 64) - 1;
constexpr const __uint128_t top_mask = ~bottom_mask;
return {source bitand bottom_mask, Shr((source bitand top_mask), 64)};
}
class SHA512
{
protected:
uint64_t W[80];
// 80 64 bit unsigned constants for sha512 algorithm
const uint64_t K[80] =
{
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
uint64_t H[8] = {
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb42bd6bULL, 0x5be0cd19137e2179ULL
};
public:
/* default class constructor */
SHA512(std::string msg)
{
// length in bytes.
__uint128_t len = msg.length();
// length is represented by a 128 bit unsigned integer
__uint128_t bitlen = len << 3;
// padding with zeros
unsigned int padding = ((1024-(bitlen+1)-128) % 1024)-7;
padding /= 8; // in bytes.
unsigned int blockBytesLen = padding+len+17;
uint8_t WordArray[blockBytesLen];
memset(WordArray, 0, blockBytesLen);
for (__uint128_t c=0;c<len;c++) {
WordArray[c] = msg.c_str()[c];
}
WordArray[len] = (uint8_t)0x80ULL; // append 10000000.
// pad W with zeros
for (int c=0; c<80; c++) {
W[c] = 0x00ULL;
}
// add WordArray to W array
// 8 bit array values to 64 bit array using 64 bit integer pointer.
for (__uint128_t i=0; i<len/8+1; i++) {
W[i] = (uint64_t)WordArray[i*8]<<56;
for (int j=1; j<=6; j++)
W[i] = W[i]|( (uint64_t)WordArray[i*8+j]<<(7-j)*8);
W[i] = W[i]|( (uint64_t)WordArray[i*8+7] );
}
// append 128 bit length as 2 uint64_t's as a big endian
auto [fst, snd] = to2_uint64(bitlen);
W[Shr(padding+len+1,3)+1] = fst;
W[Shr(padding+len+1,3)+2] = snd;
// create message schedule
for (int c=16;c<80;c++)
{
// σ0 = (w[c−15] ≫≫ 1) ⊕ (w[c−15] ≫≫ 8) ⊕ (w[c−15] ≫ 7)
uint64_t s0 = Rotr(W[c-15],1) xor Rotr(W[c-15],8) xor Shr(W[c-15],7);
// σ1 = (w[c−2] ≫≫ 19) ⊕ (w[c−2] ≫≫ 61) ⊕ (w[c−2] ≫ 6)
uint64_t s1 = Rotr(W[c-2],19) xor Rotr(W[c-2],61) xor Shr(W[c-2],6);
// uint64_t does binary addition 2^64.
// w[c] = w[c−16] [+] σ0 [+] w[c−7] [+] σ1
W[c] = W[c-16] + s0 + W[c-7] + s1;
}
uint64_t V[8]; // initialize hash values
memcpy(V, H, sizeof(uint64_t)*8);
// transform
for (int c=0;c<80;c++)
{
// Σ0 = (a ≫≫ 28) ⊕ (a ≫≫ 34) ⊕ (a ≫≫ 39)
uint64_t S0 = Rotr(V[0], 28) xor Rotr(V[0], 34) xor Rotr(V[0], 39);
// T2 = Σ0 + Maj
uint64_t temp2 = S0 + Maj(V[0], V[1], V[2]);
// Σ1 = (e ≫≫ 14) ⊕ (e ≫≫ 18) ⊕ (e ≫≫ 41)
uint64_t S1 = Rotr(V[4], 14) xor Rotr(V[4], 18) xor Rotr(V[4], 41);
// T1 = h + Σ1 + Ch[e,f,g] + K[c] + W[c]
uint64_t temp1 = V[7] + S1 + Ch(V[4], V[5], V[6]) + K[c] + W[c];
// modify hash values
V[7] = V[6];
V[6] = V[5];
V[5] = V[4];
V[4] = V[3] + temp1;
V[3] = V[2];
V[2] = V[1];
V[1] = V[0];
V[0] = temp1 + temp2;
/* ================== per-iteration values ================== */
std::cout << "iteration round: " << std::dec << c << std::endl;
std::cout << "a: " << std::hex << V[0] << std::endl;
std::cout << "b: " << std::hex << V[1] << std::endl;
std::cout << "c: " << std::hex << V[2] << std::endl;
std::cout << "d: " << std::hex << V[3] << std::endl;
std::cout << "e: " << std::hex << V[4] << std::endl;
std::cout << "f: " << std::hex << V[5] << std::endl;
std::cout << "g: " << std::hex << V[6] << std::endl;
std::cout << "h: " << std::hex << V[7] << std::endl;
std::cout << "S0:\t" << std::hex << S0 << std::endl;
std::cout << "S1:\t" << std::hex << S1 << std::endl;
std::cout << "t0:\t" << std::hex << temp2 << std::endl;
std::cout << "t1:\t" << std::hex << temp1 << std::endl;
}
// final values
std::cout << std::endl << std::endl << std::endl << std::endl;
for (int c=0;c<8;c++)
{
H[c] += V[c];
std::cout << std::hex << H[c];
}
}
};
int main()
{
std::string msg;
msg = "abc";
// std::cout << "input:\t";
// getline(std::cin, msg);
SHA512 hash(msg);
std::cout << std::endl
<< "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9ee"
<<"ee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d442364"
<< "3ce80e2a9ac94fa54ca49f\n\t\t\t\t\t\t\t^ correct value ^";
return 0;
}
实施的其余部分似乎是正确的,但 temp1 值不正确。我认为 temp1 可能需要是 128 位 int,但正确值的大小仍然是 64 位,所以我真的很困惑我是如何得到 0xb37b0cfa1b96e8a0 而不是 0x1b37b0cfa1b96e8a0 的。唯一的区别是正确的值以额外的 1(十六进制)开头。
编辑:我使用了测试向量和其他示例代码,这些代码可以看到我所做的一切都是正确的,包括消息计划,但没有得到 temp1 的正确答案。其余代码似乎有效(至少对于单个块)。
运行不正常的代码:
// transform
for (int c=0;c<80;c++)
{
// Σ0 = (a ≫≫ 28) ⊕ (a ≫≫ 34) ⊕ (a ≫≫ 39)
uint64_t S0 = Rotr(V[0], 28) xor Rotr(V[0], 34) xor Rotr(V[0], 39);
// T2 = Σ0 + Maj
uint64_t temp2 = S0 + Maj(V[0], V[1], V[2]);
// Σ1 = (e ≫≫ 14) ⊕ (e ≫≫ 18) ⊕ (e ≫≫ 41)
uint64_t S1 = Rotr(V[4], 14) xor Rotr(V[4], 18) xor Rotr(V[4], 41);
// T1 = h + Σ1 + Ch[e,f,g] + K[c] + W[c]
uint64_t temp1 = V[7] + S1 + Ch(V[4], V[5], V[6]) + K[c] + W[c];
// modify hash values
V[7] = V[6];
V[6] = V[5];
V[5] = V[4];
V[4] = V[3] + temp1;
V[3] = V[2];
V[2] = V[1];
V[1] = V[0];
V[0] = temp1 + temp2;
/* ================== per-iteration values ================== */
std::cout << "iteration round: " << std::dec << c << std::endl;
std::cout << "a: " << std::hex << V[0] << std::endl;
std::cout << "b: " << std::hex << V[1] << std::endl;
std::cout << "c: " << std::hex << V[2] << std::endl;
std::cout << "d: " << std::hex << V[3] << std::endl;
std::cout << "e: " << std::hex << V[4] << std::endl;
std::cout << "f: " << std::hex << V[5] << std::endl;
std::cout << "g: " << std::hex << V[6] << std::endl;
std::cout << "h: " << std::hex << V[7] << std::endl;
std::cout << "S0:\t" << std::hex << S0 << std::endl;
std::cout << "S1:\t" << std::hex << S1 << std::endl;
std::cout << "t0:\t" << std::hex << temp2 << std::endl;
我发现您的代码有两个错误。第一个是在 G 的初始值中。您提供了 0x1f83d9abfb42bd6b,但是 0x1f83d9abfb41bd6b 是正确的(即 41
,而不是 42
)。因为 SHA-512 与所有加密安全哈希函数一样,表现出 avalanche effect,即使将初始常量更改一位也会导致完全不同的输出。此更改可能不会影响算法的安全性,但当然它不是 SHA-512 并且不会产生兼容的结果。
在这种情况下,我的建议是从 PDF 或其他信誉良好的来源复制并粘贴常量,或者使用 bc
或 dc
在命令行中生成它们,因为这种错误很容易制作。这些常量无论如何都不受版权保护,因此从某处复制和粘贴它们的列表不会影响您的代码的许可。
另一个,一旦修复,std::hex
不会格式化为两个位置,因此当其中一个输出字节 ix 0x0a 时,它只打印“a”而不是“0a”。我知道有一些方法可以使用 C++ 中的标准格式化流来解决这个问题,但我实际上已经放弃了 C++ 转而使用 Rust,所以我将修复它作为 reader 的练习。您也可以只使用(喘息!)printf
,其中 %02x
格式说明符将执行您想要的操作。
我通过使用 NIST intermediate values PDF 中的输出发现问题,然后比较常量以查看不同之处。
如果您查看迭代 0 中的 temp1 值。您会看到我得到的是 0xb37b0cfa1b96e8a0,而我应该得到的是 0x1b37b0cfa1b96e8a0。为什么 0x1 没有出现在我的?这是与数据类型相关的问题吗?它会溢出还是我对 temp1 的实现有误?
顺便说一下,我对“abc”进行了哈希运算。
对消息进行哈希处理:SHA512 hash("abc");
代码:
/*
* github: kibnakamoto
* Created on: Dec. 5, 2021
* Author: Taha Canturk
* More Info: github.com/kibnakamoto/sha512.cpp/blob/main/README.md
*/
#include <iostream>
#include <string>
#include <cstring>
#include <stdint.h>
// choice = (x ∧ y) ⊕ (¯x ∧ z)
inline uint64_t Ch(uint64_t e, uint64_t f, uint64_t g) {
return ((e bitand f)xor(~e bitand g));
}
// #define Ch(x,y,z) ((x bitand y)xor(~x bitand z))
// // majority = (x ∧ y) ⊕ (x ∧ z) ⊕ (y ∧ z)
inline uint64_t Maj(uint64_t a, uint64_t b, uint64_t c) {
return ((a & b)^(a & c)^(b & c));
}
// // binary operators
inline uint64_t Shr(uint64_t x, unsigned int n) {
return (x >> n);
}
inline uint64_t Rotr(uint64_t x, unsigned int n) {
return ( (x >> n)|(x << (sizeof(x)<<3)-n) );
}
// length which is __uint128_t in 2 uint64_t integers
inline std::pair<uint64_t,uint64_t> to2_uint64(__uint128_t source) {
constexpr const __uint128_t bottom_mask = (__uint128_t{1} << 64) - 1;
constexpr const __uint128_t top_mask = ~bottom_mask;
return {source bitand bottom_mask, Shr((source bitand top_mask), 64)};
}
class SHA512
{
protected:
uint64_t W[80];
// 80 64 bit unsigned constants for sha512 algorithm
const uint64_t K[80] =
{
0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL,
0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL,
0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL,
0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL,
0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL,
0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL,
0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL,
0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL,
0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL,
0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL,
0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL,
0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL,
0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL,
0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL,
0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL,
0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL,
0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL,
0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL,
0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL,
0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL,
0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL,
0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL};
uint64_t H[8] = {
0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
0x1f83d9abfb42bd6bULL, 0x5be0cd19137e2179ULL
};
public:
/* default class constructor */
SHA512(std::string msg)
{
// length in bytes.
__uint128_t len = msg.length();
// length is represented by a 128 bit unsigned integer
__uint128_t bitlen = len << 3;
// padding with zeros
unsigned int padding = ((1024-(bitlen+1)-128) % 1024)-7;
padding /= 8; // in bytes.
unsigned int blockBytesLen = padding+len+17;
uint8_t WordArray[blockBytesLen];
memset(WordArray, 0, blockBytesLen);
for (__uint128_t c=0;c<len;c++) {
WordArray[c] = msg.c_str()[c];
}
WordArray[len] = (uint8_t)0x80ULL; // append 10000000.
// pad W with zeros
for (int c=0; c<80; c++) {
W[c] = 0x00ULL;
}
// add WordArray to W array
// 8 bit array values to 64 bit array using 64 bit integer pointer.
for (__uint128_t i=0; i<len/8+1; i++) {
W[i] = (uint64_t)WordArray[i*8]<<56;
for (int j=1; j<=6; j++)
W[i] = W[i]|( (uint64_t)WordArray[i*8+j]<<(7-j)*8);
W[i] = W[i]|( (uint64_t)WordArray[i*8+7] );
}
// append 128 bit length as 2 uint64_t's as a big endian
auto [fst, snd] = to2_uint64(bitlen);
W[Shr(padding+len+1,3)+1] = fst;
W[Shr(padding+len+1,3)+2] = snd;
// create message schedule
for (int c=16;c<80;c++)
{
// σ0 = (w[c−15] ≫≫ 1) ⊕ (w[c−15] ≫≫ 8) ⊕ (w[c−15] ≫ 7)
uint64_t s0 = Rotr(W[c-15],1) xor Rotr(W[c-15],8) xor Shr(W[c-15],7);
// σ1 = (w[c−2] ≫≫ 19) ⊕ (w[c−2] ≫≫ 61) ⊕ (w[c−2] ≫ 6)
uint64_t s1 = Rotr(W[c-2],19) xor Rotr(W[c-2],61) xor Shr(W[c-2],6);
// uint64_t does binary addition 2^64.
// w[c] = w[c−16] [+] σ0 [+] w[c−7] [+] σ1
W[c] = W[c-16] + s0 + W[c-7] + s1;
}
uint64_t V[8]; // initialize hash values
memcpy(V, H, sizeof(uint64_t)*8);
// transform
for (int c=0;c<80;c++)
{
// Σ0 = (a ≫≫ 28) ⊕ (a ≫≫ 34) ⊕ (a ≫≫ 39)
uint64_t S0 = Rotr(V[0], 28) xor Rotr(V[0], 34) xor Rotr(V[0], 39);
// T2 = Σ0 + Maj
uint64_t temp2 = S0 + Maj(V[0], V[1], V[2]);
// Σ1 = (e ≫≫ 14) ⊕ (e ≫≫ 18) ⊕ (e ≫≫ 41)
uint64_t S1 = Rotr(V[4], 14) xor Rotr(V[4], 18) xor Rotr(V[4], 41);
// T1 = h + Σ1 + Ch[e,f,g] + K[c] + W[c]
uint64_t temp1 = V[7] + S1 + Ch(V[4], V[5], V[6]) + K[c] + W[c];
// modify hash values
V[7] = V[6];
V[6] = V[5];
V[5] = V[4];
V[4] = V[3] + temp1;
V[3] = V[2];
V[2] = V[1];
V[1] = V[0];
V[0] = temp1 + temp2;
/* ================== per-iteration values ================== */
std::cout << "iteration round: " << std::dec << c << std::endl;
std::cout << "a: " << std::hex << V[0] << std::endl;
std::cout << "b: " << std::hex << V[1] << std::endl;
std::cout << "c: " << std::hex << V[2] << std::endl;
std::cout << "d: " << std::hex << V[3] << std::endl;
std::cout << "e: " << std::hex << V[4] << std::endl;
std::cout << "f: " << std::hex << V[5] << std::endl;
std::cout << "g: " << std::hex << V[6] << std::endl;
std::cout << "h: " << std::hex << V[7] << std::endl;
std::cout << "S0:\t" << std::hex << S0 << std::endl;
std::cout << "S1:\t" << std::hex << S1 << std::endl;
std::cout << "t0:\t" << std::hex << temp2 << std::endl;
std::cout << "t1:\t" << std::hex << temp1 << std::endl;
}
// final values
std::cout << std::endl << std::endl << std::endl << std::endl;
for (int c=0;c<8;c++)
{
H[c] += V[c];
std::cout << std::hex << H[c];
}
}
};
int main()
{
std::string msg;
msg = "abc";
// std::cout << "input:\t";
// getline(std::cin, msg);
SHA512 hash(msg);
std::cout << std::endl
<< "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9ee"
<<"ee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d442364"
<< "3ce80e2a9ac94fa54ca49f\n\t\t\t\t\t\t\t^ correct value ^";
return 0;
}
实施的其余部分似乎是正确的,但 temp1 值不正确。我认为 temp1 可能需要是 128 位 int,但正确值的大小仍然是 64 位,所以我真的很困惑我是如何得到 0xb37b0cfa1b96e8a0 而不是 0x1b37b0cfa1b96e8a0 的。唯一的区别是正确的值以额外的 1(十六进制)开头。
编辑:我使用了测试向量和其他示例代码,这些代码可以看到我所做的一切都是正确的,包括消息计划,但没有得到 temp1 的正确答案。其余代码似乎有效(至少对于单个块)。
运行不正常的代码:
// transform
for (int c=0;c<80;c++)
{
// Σ0 = (a ≫≫ 28) ⊕ (a ≫≫ 34) ⊕ (a ≫≫ 39)
uint64_t S0 = Rotr(V[0], 28) xor Rotr(V[0], 34) xor Rotr(V[0], 39);
// T2 = Σ0 + Maj
uint64_t temp2 = S0 + Maj(V[0], V[1], V[2]);
// Σ1 = (e ≫≫ 14) ⊕ (e ≫≫ 18) ⊕ (e ≫≫ 41)
uint64_t S1 = Rotr(V[4], 14) xor Rotr(V[4], 18) xor Rotr(V[4], 41);
// T1 = h + Σ1 + Ch[e,f,g] + K[c] + W[c]
uint64_t temp1 = V[7] + S1 + Ch(V[4], V[5], V[6]) + K[c] + W[c];
// modify hash values
V[7] = V[6];
V[6] = V[5];
V[5] = V[4];
V[4] = V[3] + temp1;
V[3] = V[2];
V[2] = V[1];
V[1] = V[0];
V[0] = temp1 + temp2;
/* ================== per-iteration values ================== */
std::cout << "iteration round: " << std::dec << c << std::endl;
std::cout << "a: " << std::hex << V[0] << std::endl;
std::cout << "b: " << std::hex << V[1] << std::endl;
std::cout << "c: " << std::hex << V[2] << std::endl;
std::cout << "d: " << std::hex << V[3] << std::endl;
std::cout << "e: " << std::hex << V[4] << std::endl;
std::cout << "f: " << std::hex << V[5] << std::endl;
std::cout << "g: " << std::hex << V[6] << std::endl;
std::cout << "h: " << std::hex << V[7] << std::endl;
std::cout << "S0:\t" << std::hex << S0 << std::endl;
std::cout << "S1:\t" << std::hex << S1 << std::endl;
std::cout << "t0:\t" << std::hex << temp2 << std::endl;
我发现您的代码有两个错误。第一个是在 G 的初始值中。您提供了 0x1f83d9abfb42bd6b,但是 0x1f83d9abfb41bd6b 是正确的(即 41
,而不是 42
)。因为 SHA-512 与所有加密安全哈希函数一样,表现出 avalanche effect,即使将初始常量更改一位也会导致完全不同的输出。此更改可能不会影响算法的安全性,但当然它不是 SHA-512 并且不会产生兼容的结果。
在这种情况下,我的建议是从 PDF 或其他信誉良好的来源复制并粘贴常量,或者使用 bc
或 dc
在命令行中生成它们,因为这种错误很容易制作。这些常量无论如何都不受版权保护,因此从某处复制和粘贴它们的列表不会影响您的代码的许可。
另一个,一旦修复,std::hex
不会格式化为两个位置,因此当其中一个输出字节 ix 0x0a 时,它只打印“a”而不是“0a”。我知道有一些方法可以使用 C++ 中的标准格式化流来解决这个问题,但我实际上已经放弃了 C++ 转而使用 Rust,所以我将修复它作为 reader 的练习。您也可以只使用(喘息!)printf
,其中 %02x
格式说明符将执行您想要的操作。
我通过使用 NIST intermediate values PDF 中的输出发现问题,然后比较常量以查看不同之处。