PolarSSL SHA512 Wrapper - Differing hash lengths.

closed account (o3hC5Di1)
Hi everyone,

I'm trying to write a little C++ wrapper around the PolarSLL SHA-512 / 384 implementation, the source code of which you can view here:
https://polarssl.org/sha-512-source-code

The problem I'm having is that the length of the digest is not always 64 bytes (for sha512) or 49 bytes (for sha384) as it's supposed to be, it often is, but not always - which is kind of weird.

I have pretty much used the code as it is on PolarSSL's website, except for wrapping it in an "impl" namespace. I also ran the self_tests, which all passed.

Here's the code I'm using to wrap the PolarSSL implementation:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
namespace {


void sha4(const std::string& input, const sha_t& type, std::string& result)
{
	bool is_384 = (type == sha_t::SHA_384);

	const unsigned char* in = reinterpret_cast<const unsigned char*>(input.c_str());

	unsigned char result_buffer[64];

        //Actual call to the PolarSSL function:
	impl::sha4(in, input.size(), result_buffer, static_cast<int>(is_384));

	//If we don't null-terminate the buffers, the hash will be
	//different every time because of trailing garbage values.
	if (is_384)
		result_buffer[48] = '\0';
	else
		result_buffer[63] = '\0';

	std::ostringstream oss;
	oss << result_buffer;

	result = oss.str();
}




std::string to_hex(const std::string& input)
{
	std::ostringstream osstream;
	static char const hex_table[17] = "0123456789abcdef";
	
	for (const char& c : input)
	{
		if (c != '\0')
		{
			int current_char = static_cast<int>(c);
			//first hex character
			osstream << hex_table[(current_char >> 4) & 0xF] 
			//second hex character
				 << hex_table[current_char & 0xF];
		}
	}

	return osstream.str();
}

	
}//anonymous namespace




std::string sha512(const std::string& input)
{
	std::string result;
	sha4(input, sha_t::SHA_512, result);
	return result;
}




std::string sha512_hex(const std::string& input)
{
	return to_hex(sha512(input));
}



std::string sha384(const std::string& input)
{
	std::string result;
	sha4(input, sha_t::SHA_384, result);
	return result;
}



std::string sha384_hex(const std::string& input)
{
	return to_hex(sha384(input));
}


When I run a test for sha384 using single characters and hex output (so I expect (48*2=)96 total characters in the output), here's what I get:


a   / 54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31                                 / 96   
b   / 98a906182cdcfb1eb4eb471176                                                                                                       / 26   
c   / 40f98a05660bf871802ee59964de1945bd731a45cc7f48e4dadd92f34a7eeec089e149ad8c2434f11792e588b740d997                                 / 96   
d   / 8ac10705a78a2dcd15fa577bac70762708597a02e130d8a6192d73dababd2b14502dbeee29d0e22bc341a0c42af6a4fb                                 / 96   
e   / 8d182905e535537a32cc0c475403d1fe78ee541a40d61e0b306d7541ed8dbb63d550dab383d0fca0e23448af99bffe10                                 / 96   
f   / 3a31ca443b6cae3717b4a4f19972bc92413645380e4990e4fe4dc322386494fadaa2b63b4f62be6e2b7077e982bb7ada                                 / 96   
g   / 400351f8d278fdf7e765ccb2943e8a99548a68ae0235b96fa47cb758a354ddd1201d034199439c49ff22cfc0904bc2e2                                 / 96   
h   / a4eb0778c79fce94c02126543cba398d645b2fd4c6ff6a02eecc026bbe0cc0dd666279722b7615bc15b4c9126b941c04                                 / 96   
i   / 2051ff7a91bcc6245fe7c3c4bdfcb0538553f73c54100c686a6fc0279354d12ecb4b7589a60a516c4fabadbeb622f397                                 / 96   
j   / 417316736caf4fc0f2a09f5d6e4c90d78b768fe08add82c5db9f0a22809bd6a719e3ad367f149d92b5455e952b79613b                                 / 96   
k   / 81deaf76b8f3d7c9c58bb0ed5f83962c136ea4c5dd075272072843a8283a096a58e2b5199f32d4b2e37f0bbb953c7a09                                 / 96   
l   / 1ad0ee901a40bf4536640f4f0c8c2b9fca9f5fbac283fd6dc4d1fd7021f8ca66c69c399619921f6dec5a2d9d942bc7ac                                 / 96   
m   / 7857a47542aca03c22c39461231a919d9904a5915937278535a41291791b96c06717638cd6b0a2e5b8a20a53ec980f57                                 / 96   
n   / a87d8f7ff9267bad515057f7a7f772c469d2536b70f1e8e770f9a5581922b986520a3d71d952f30593bcfa2318bfeb0d                                 / 96   
o   / 1d587bbe50d4aef51f2ea3743f3c6f849a16e6c2cfe711029e5e202ab3484b0d6ed8de1e2c                                                       / 74   
p   / 049e7caf67d83409ea363e89c09d67c7f1fd1bd679016ad9f422830ef105435e12a4c2dcad5a9e5a9602924d479574dc                                 / 96   
q   / 081de7624429ffbb0cd03c81da55df6fc8e36d09406bc581aa78c84742fdf45f58d999adb87f89740d2a4f88aaf38209                                 / 96   
r   / 75d37880e899ba856e8504e8588796691b90dd93853e7e4507c68d9941dbddf430663b0ed30942f3d3d7f986e5989efe                                 / 96   
s   / 5335f048bddebe600ae6edb89b36da3a2d7c18bc53b83e2fa577cc9a4f262fc1c3741830955303a0158e7d48be7965f8                                 / 96   
t   / e7cdceeaff40fcf3eb07011b4facb47e6c06f82d243289ca9e598282f1e58ea4ee2378d5772c26e926ecbffba13f6d53                                 / 96   
u   / 8b                                                                                                                               / 2    
v   / 4c52ccee                                                                                                                         / 8    
w   / f99557d0ede293bde12229d548d97d77b548d3659852cb45672fbfdd4431397760b2fd6d23b04a08680ec9d030b83579                                 / 96   
x   / d752c2c51fba0e29aa190570a9d4253e44077a058d3297fa3a5630d5bd012622f97c28acaed313b5c83bb990caa7da85                                 / 96   
y   / 883c52bd6105dadf36411ccbc5b3b19f9926f3ffacbf0275b3b7ed6e1228aff6c5585a2e77f1e8fdef6a23e31b838cf6                                 / 96   
z   / c39c06ca383f11c2870c8ea1368e861cee29dde246368c17b6985f7a7d650d86a90aa8bbb176ddbd99f06d490f0495e5                                 / 96   
?   /                                                                                                                                  / 0    
!   / 1d0ec8c84ee9521e21f06774de232367b64de628474cb5b2e372b699a1f55ae335cc37193ef823e33324dfd9a70738a6                                 / 96   
{   / 95ed401953c1d4c284ee689b77a75356c6b92a4095bace5f611aace86c4dc41925fdcf                                                           / 70   
}   / 1f366c84945e30278b3f85a80ca9cfa193ed5adabe117789ee08eff673779cd4fb1f881ec98505672ead70b402190554                                 / 96   
[   / cf1e1cb005d298b1782c988946d3a2d3d08e4021bcc81669d1d22cb470f48e4282eb639f8fa4f7badb4f8ad93f556124                                 / 96   
]   / af03681360120cccd5c2c6050bcbe74806c6b5454b9ff1c946058c944638adfaa4652dadaafea6ad964c0c16a53deebe                                 / 96



When I do a strchr() for '\0' on the original (non-hex) values, the pointer position returned is the same as the checksums length, so I'm wondering if perhaps the sha4 implementation would shift bits around and one of them happens to become a '\0', null terminating the hash early?

I'm not too strong on C, nor cryptography, nor C++ for that matter, so any help at all would be greatly appreciated. Please let me know if you require any additional information.

All the best,
NwN
Hi,

You are assuming you can use the result as a string.. You cannot :)..

If the 2nd byte of the has is a '\0' (0x00), then your string gets terminated, so you see a 1 byte result.. You should treat it at as a 64 byte memory buffer, not a string buffer. Just assume it's 64 bytes when you hexify it!

Regards,
Paul
Lead PolarSSL Maintainer
closed account (o3hC5Di1)
Hi Paul,

Thanks very much for your fast reply.
That makes sense, I'm having one of those "off course, why didn't I think of that" moments.

Thanks again for replying, very much appreciated.

All the best,
NwN
closed account (o3hC5Di1)
Hi,

Thanks to Paul's input I managed to solve the issue, I include the code for anyone who might be interested:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//cpp file:
//include 
#include <sstream>


namespace {

const unsigned short SHA512_CHECKSUM_LENGTH = 64;
const unsigned short SHA384_CHECKSUM_LENGTH = 48;

void sha4(const std::string& input, const sha_t& type, unsigned char buffer[64])
{
	bool is_384 = (type == sha_t::SHA_384);

	const unsigned char* in = reinterpret_cast<const unsigned char*>(input.c_str());
	//Calls the PolarSSL function.
	impl::sha4(in, input.size(), buffer, static_cast<int>(is_384));
}




std::string to_hex(const unsigned char* input, size_t input_length)
{
	std::ostringstream osstream;
	static char const hex_table[17] = "0123456789abcdef";

	for (size_t i=0; i<input_length; i++)
	{
		unsigned int current_char = static_cast<int>(input[i]);
		//first hex character
		osstream << hex_table[(current_char >> 4) & 0xF] 
		//second hex character
			 << hex_table[current_char & 0xF];
	}

	return osstream.str();
}

	
}//anonymous namespace




std::string sha512(const std::string& input)
{
	unsigned char buffer[SHA512_CHECKSUM_LENGTH];
	sha4(input, sha_t::SHA_512, buffer);
	return std::string(reinterpret_cast<char*>(buffer), SHA512_CHECKSUM_LENGTH);
}




std::string sha512_hex(const std::string& input)
{
	unsigned char buffer[SHA512_CHECKSUM_LENGTH];
	sha4(input, sha_t::SHA_512, buffer);
	return to_hex(buffer, SHA512_CHECKSUM_LENGTH);
}



std::string sha384(const std::string& input)
{
	unsigned char buffer[SHA384_CHECKSUM_LENGTH];
	sha4(input, sha_t::SHA_384, buffer);
	return std::string(reinterpret_cast<char*>(buffer), SHA384_CHECKSUM_LENGTH);
}



std::string sha384_hex(const std::string& input)
{
	unsigned char buffer[SHA384_CHECKSUM_LENGTH];
	sha4(input, sha_t::SHA_384, buffer);
	return to_hex(buffer, SHA384_CHECKSUM_LENGTH);
}


Big thanks to Paul for pointing the error out - great project you have and neatly written.

All the best,
NwN
Last edited on
Topic archived. No new replies allowed.