SHA-1 in C on little-endian environment
Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).
I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))
unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}
void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;
h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;
unsigned char * str;
str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);
int current_length = strlen((const char *)str);
int original_length = current_length;
str[current_length] = 0x80;
str[current_length + 1] = '';
char ic = str[current_length];
current_length++;
int ib = current_length % 64;
int i, j;
if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;
for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}
str[current_length + 1]='';
for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}
str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';
int number_of_chunks = current_length/64;
unsigned long int word[80];
for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;
}
h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;
}
h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);
printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}
int main()
{
SHA1((unsigned char *)"abc");
return 0;
}
SHA-1 ("abc"):
Resulting
Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6
Correct (actual)
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Am I doing my endianness conversion correctly or in the correct spot?
c endianness sha
|
show 5 more comments
Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).
I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))
unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}
void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;
h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;
unsigned char * str;
str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);
int current_length = strlen((const char *)str);
int original_length = current_length;
str[current_length] = 0x80;
str[current_length + 1] = '';
char ic = str[current_length];
current_length++;
int ib = current_length % 64;
int i, j;
if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;
for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}
str[current_length + 1]='';
for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}
str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';
int number_of_chunks = current_length/64;
unsigned long int word[80];
for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;
}
h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;
}
h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);
printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}
int main()
{
SHA1((unsigned char *)"abc");
return 0;
}
SHA-1 ("abc"):
Resulting
Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6
Correct (actual)
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Am I doing my endianness conversion correctly or in the correct spot?
c endianness sha
My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 '18 at 4:47
I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"
– xornoz
Nov 23 '18 at 4:55
Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 '18 at 5:00
Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master
– Barmak Shemirani
Nov 23 '18 at 5:00
1
By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.
– harold
Nov 23 '18 at 6:19
|
show 5 more comments
Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).
I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))
unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}
void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;
h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;
unsigned char * str;
str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);
int current_length = strlen((const char *)str);
int original_length = current_length;
str[current_length] = 0x80;
str[current_length + 1] = '';
char ic = str[current_length];
current_length++;
int ib = current_length % 64;
int i, j;
if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;
for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}
str[current_length + 1]='';
for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}
str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';
int number_of_chunks = current_length/64;
unsigned long int word[80];
for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;
}
h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;
}
h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);
printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}
int main()
{
SHA1((unsigned char *)"abc");
return 0;
}
SHA-1 ("abc"):
Resulting
Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6
Correct (actual)
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Am I doing my endianness conversion correctly or in the correct spot?
c endianness sha
Most implementations of SHA-1 (even on Wikipedia) I came across are coded for big-endian runtimes. So I'm trying to implement my own version for my machine (little-endian).
I've followed the pseudo-code form Wikipedia and have the following code. I found a function that converts the byte ordering but still not getting the correct output.
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#define rotateleft(x,n) ((x<<n) | (x>>(32-n)))
unsigned int endian_reverse(unsigned int n)
{
unsigned int m = 0;
m |= n << 24;
m |= ((n >> 8) << 24) >> 8;
m |= ((n << 8) >> 24) << 8;
m |= n >> 24;
return m;
}
void SHA1(unsigned char * str1)
{
unsigned long int h0,h1,h2,h3,h4,a,b,c,d,e,f,k,temp;
h0 = 0x67452301;
h1 = 0xEFCDAB89;
h2 = 0x98BADCFE;
h3 = 0x10325476;
h4 = 0xC3D2E1F0;
unsigned char * str;
str = (unsigned char *)malloc(strlen((const char *)str1)+100);
strcpy((char *)str,(const char *)str1);
int current_length = strlen((const char *)str);
int original_length = current_length;
str[current_length] = 0x80;
str[current_length + 1] = '';
char ic = str[current_length];
current_length++;
int ib = current_length % 64;
int i, j;
if(ib<56)
ib = 56-ib;
else
ib = 120 - ib;
for(i=0;i < ib;i++)
{
str[current_length]=0x00;
current_length++;
}
str[current_length + 1]='';
for(i=0;i<6;i++)
{
str[current_length]=0x0;
current_length++;
}
str[current_length] = (original_length * 8) / 0x100 ;
current_length++;
str[current_length] = (original_length * 8) % 0x100;
current_length++;
str[current_length+i]='';
int number_of_chunks = current_length/64;
unsigned long int word[80];
for(i=0;i<number_of_chunks;i++)
{
for(j=0;j<16;j++)
{
word[j] =
str[i*64 + j*4 + 0] * 0x1000000 + str[i*64 + j*4 + 1] * 0x10000 +
str[i*64 + j*4 + 2] * 0x100 + str[i*64 + j*4 + 3];
}
for(j=16;j<80;j++)
{
word[j] = rotateleft((word[j-3] ^ word[j-8] ^ word[j-14] ^ word[j-16]),1);
}
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for(int m=0;m<80;m++)
{
if(m<=19)
{
f = (b & c) | ((~b) & d);
k = 0x5A827999;
}
else if(m<=39)
{
f = b ^ c ^ d;
k = 0x6ED9EBA1;
}
else if(m<=59)
{
f = (b & c) | (b & d) | (c & d);
k = 0x8F1BBCDC;
}
else
{
f = b ^ c ^ d;
k = 0xCA62C1D6;
}
temp = (rotateleft(a,5) + f + e + k + word[m]) & 0xFFFFFFFF;
e = d;
d = c;
c = rotateleft(b,30);
b = a;
a = temp;
}
h0 = h0 + a;
h1 = h1 + b;
h2 = h2 + c;
h3 = h3 + d;
h4 = h4 + e;
}
h0 = endian_reverse(h0);
h1 = endian_reverse(h1);
h2 = endian_reverse(h2);
h3 = endian_reverse(h3);
h4 = endian_reverse(h4);
printf("nn");
printf("Hash: %x %x %x %x %x",h0, h1, h2, h3, h4);
printf("nn");
}
int main()
{
SHA1((unsigned char *)"abc");
return 0;
}
SHA-1 ("abc"):
Resulting
Hash: f7370736 e388302f 15815610 1ccacd49 e7649bb6
Correct (actual)
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Am I doing my endianness conversion correctly or in the correct spot?
c endianness sha
c endianness sha
edited Nov 23 '18 at 7:01
chux
82.8k872149
82.8k872149
asked Nov 23 '18 at 4:34
xornozxornoz
83
83
My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 '18 at 4:47
I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"
– xornoz
Nov 23 '18 at 4:55
Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 '18 at 5:00
Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master
– Barmak Shemirani
Nov 23 '18 at 5:00
1
By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.
– harold
Nov 23 '18 at 6:19
|
show 5 more comments
My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 '18 at 4:47
I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"
– xornoz
Nov 23 '18 at 4:55
Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 '18 at 5:00
Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master
– Barmak Shemirani
Nov 23 '18 at 5:00
1
By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.
– harold
Nov 23 '18 at 6:19
My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 '18 at 4:47
My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 '18 at 4:47
I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"
– xornoz
Nov 23 '18 at 4:55
I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"
– xornoz
Nov 23 '18 at 4:55
Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 '18 at 5:00
Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 '18 at 5:00
Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master
– Barmak Shemirani
Nov 23 '18 at 5:00
Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master
– Barmak Shemirani
Nov 23 '18 at 5:00
1
1
By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.
– harold
Nov 23 '18 at 6:19
By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.
– harold
Nov 23 '18 at 6:19
|
show 5 more comments
1 Answer
1
active
oldest
votes
Am I doing my endianness conversion correctly or in the correct spot?
Endianness conversion endian_reverse(()
is incorrect when unsigned
is not 32-bit.
Endianness conversion not used in correct spot. Endian conversion not needed.
Other issues exists.
Code is assuming unsigned long int
is 32-bit. When unsigned long int
is 64-bit, I can get the same answer as OP.
Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t
. For array sizing and string lengths use size_t
. Avoid signed types and constants.
By changing unsigned long
--> uint32_t
and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7);
I came up with
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Other suggestions.
Multiple of 64
size
in str = malloc(size)
should be a multiple of 64
Stay within multiples of 64
str[current_length+i]='';
can write outside allocation.
Alternate size storing
Works for all size_t
values up to 264-3 - 1.
size_t current_length = ...
// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;
Are you compiling on a big-endian machine?
– xornoz
Nov 23 '18 at 6:16
@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?
– chux
Nov 23 '18 at 6:20
The constantsh0 = 0x67452301;
...
– xornoz
Nov 23 '18 at 6:22
@xornoz How do you see endian ofh0
as important here? The constant needs to have the value of0x67452301
regardless of machine endian.
– chux
Nov 23 '18 at 6:24
1
Actually I was wrong. You can writeh0, h1...
in to buffer by using>>
operator. This doesn't require endian check. Some implementations usememcpy, fwrite
etc. to write the memory in&h0
in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.
– Barmak Shemirani
Nov 24 '18 at 4:35
|
show 6 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440696%2fsha-1-in-c-on-little-endian-environment%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
Am I doing my endianness conversion correctly or in the correct spot?
Endianness conversion endian_reverse(()
is incorrect when unsigned
is not 32-bit.
Endianness conversion not used in correct spot. Endian conversion not needed.
Other issues exists.
Code is assuming unsigned long int
is 32-bit. When unsigned long int
is 64-bit, I can get the same answer as OP.
Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t
. For array sizing and string lengths use size_t
. Avoid signed types and constants.
By changing unsigned long
--> uint32_t
and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7);
I came up with
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Other suggestions.
Multiple of 64
size
in str = malloc(size)
should be a multiple of 64
Stay within multiples of 64
str[current_length+i]='';
can write outside allocation.
Alternate size storing
Works for all size_t
values up to 264-3 - 1.
size_t current_length = ...
// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;
Are you compiling on a big-endian machine?
– xornoz
Nov 23 '18 at 6:16
@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?
– chux
Nov 23 '18 at 6:20
The constantsh0 = 0x67452301;
...
– xornoz
Nov 23 '18 at 6:22
@xornoz How do you see endian ofh0
as important here? The constant needs to have the value of0x67452301
regardless of machine endian.
– chux
Nov 23 '18 at 6:24
1
Actually I was wrong. You can writeh0, h1...
in to buffer by using>>
operator. This doesn't require endian check. Some implementations usememcpy, fwrite
etc. to write the memory in&h0
in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.
– Barmak Shemirani
Nov 24 '18 at 4:35
|
show 6 more comments
Am I doing my endianness conversion correctly or in the correct spot?
Endianness conversion endian_reverse(()
is incorrect when unsigned
is not 32-bit.
Endianness conversion not used in correct spot. Endian conversion not needed.
Other issues exists.
Code is assuming unsigned long int
is 32-bit. When unsigned long int
is 64-bit, I can get the same answer as OP.
Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t
. For array sizing and string lengths use size_t
. Avoid signed types and constants.
By changing unsigned long
--> uint32_t
and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7);
I came up with
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Other suggestions.
Multiple of 64
size
in str = malloc(size)
should be a multiple of 64
Stay within multiples of 64
str[current_length+i]='';
can write outside allocation.
Alternate size storing
Works for all size_t
values up to 264-3 - 1.
size_t current_length = ...
// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;
Are you compiling on a big-endian machine?
– xornoz
Nov 23 '18 at 6:16
@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?
– chux
Nov 23 '18 at 6:20
The constantsh0 = 0x67452301;
...
– xornoz
Nov 23 '18 at 6:22
@xornoz How do you see endian ofh0
as important here? The constant needs to have the value of0x67452301
regardless of machine endian.
– chux
Nov 23 '18 at 6:24
1
Actually I was wrong. You can writeh0, h1...
in to buffer by using>>
operator. This doesn't require endian check. Some implementations usememcpy, fwrite
etc. to write the memory in&h0
in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.
– Barmak Shemirani
Nov 24 '18 at 4:35
|
show 6 more comments
Am I doing my endianness conversion correctly or in the correct spot?
Endianness conversion endian_reverse(()
is incorrect when unsigned
is not 32-bit.
Endianness conversion not used in correct spot. Endian conversion not needed.
Other issues exists.
Code is assuming unsigned long int
is 32-bit. When unsigned long int
is 64-bit, I can get the same answer as OP.
Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t
. For array sizing and string lengths use size_t
. Avoid signed types and constants.
By changing unsigned long
--> uint32_t
and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7);
I came up with
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Other suggestions.
Multiple of 64
size
in str = malloc(size)
should be a multiple of 64
Stay within multiples of 64
str[current_length+i]='';
can write outside allocation.
Alternate size storing
Works for all size_t
values up to 264-3 - 1.
size_t current_length = ...
// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;
Am I doing my endianness conversion correctly or in the correct spot?
Endianness conversion endian_reverse(()
is incorrect when unsigned
is not 32-bit.
Endianness conversion not used in correct spot. Endian conversion not needed.
Other issues exists.
Code is assuming unsigned long int
is 32-bit. When unsigned long int
is 64-bit, I can get the same answer as OP.
Save yourself time: There is no reason to use loose types here. Use uint32_t, uint8_t
. For array sizing and string lengths use size_t
. Avoid signed types and constants.
By changing unsigned long
--> uint32_t
and dropping h0 = endian_reverse(h0); ... h7 = endian_reverse(h7);
I came up with
Hash: a9993e36 4706816a ba3e2571 7850c26c 9cd0d89d
Other suggestions.
Multiple of 64
size
in str = malloc(size)
should be a multiple of 64
Stay within multiples of 64
str[current_length+i]='';
can write outside allocation.
Alternate size storing
Works for all size_t
values up to 264-3 - 1.
size_t current_length = ...
// append length in bits
uint64_t current_length_bits = current_length;
current_length_bits *= 8;
for (i = 8; i > 0; ) {
i--;
str[current_length + i] = (unsigned char) current_length_bits;
current_length_bits >>= 8;
}
current_length += 8;
edited Nov 23 '18 at 6:38
answered Nov 23 '18 at 6:05
chuxchux
82.8k872149
82.8k872149
Are you compiling on a big-endian machine?
– xornoz
Nov 23 '18 at 6:16
@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?
– chux
Nov 23 '18 at 6:20
The constantsh0 = 0x67452301;
...
– xornoz
Nov 23 '18 at 6:22
@xornoz How do you see endian ofh0
as important here? The constant needs to have the value of0x67452301
regardless of machine endian.
– chux
Nov 23 '18 at 6:24
1
Actually I was wrong. You can writeh0, h1...
in to buffer by using>>
operator. This doesn't require endian check. Some implementations usememcpy, fwrite
etc. to write the memory in&h0
in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.
– Barmak Shemirani
Nov 24 '18 at 4:35
|
show 6 more comments
Are you compiling on a big-endian machine?
– xornoz
Nov 23 '18 at 6:16
@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?
– chux
Nov 23 '18 at 6:20
The constantsh0 = 0x67452301;
...
– xornoz
Nov 23 '18 at 6:22
@xornoz How do you see endian ofh0
as important here? The constant needs to have the value of0x67452301
regardless of machine endian.
– chux
Nov 23 '18 at 6:24
1
Actually I was wrong. You can writeh0, h1...
in to buffer by using>>
operator. This doesn't require endian check. Some implementations usememcpy, fwrite
etc. to write the memory in&h0
in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.
– Barmak Shemirani
Nov 24 '18 at 4:35
Are you compiling on a big-endian machine?
– xornoz
Nov 23 '18 at 6:16
Are you compiling on a big-endian machine?
– xornoz
Nov 23 '18 at 6:16
@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?
– chux
Nov 23 '18 at 6:20
@xornoz As I see it - machine endian makes no difference in this code. It is the wrong size of the various types that is messing the code. What lines of code do you think make a difference because of machine endian?
– chux
Nov 23 '18 at 6:20
The constants
h0 = 0x67452301;
...– xornoz
Nov 23 '18 at 6:22
The constants
h0 = 0x67452301;
...– xornoz
Nov 23 '18 at 6:22
@xornoz How do you see endian of
h0
as important here? The constant needs to have the value of 0x67452301
regardless of machine endian.– chux
Nov 23 '18 at 6:24
@xornoz How do you see endian of
h0
as important here? The constant needs to have the value of 0x67452301
regardless of machine endian.– chux
Nov 23 '18 at 6:24
1
1
Actually I was wrong. You can write
h0, h1...
in to buffer by using >>
operator. This doesn't require endian check. Some implementations use memcpy, fwrite
etc. to write the memory in &h0
in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.– Barmak Shemirani
Nov 24 '18 at 4:35
Actually I was wrong. You can write
h0, h1...
in to buffer by using >>
operator. This doesn't require endian check. Some implementations use memcpy, fwrite
etc. to write the memory in &h0
in to a buffer, this needs flipping the byte order for little-endian. The latter method is pointlessly complicated and is also used in many places.– Barmak Shemirani
Nov 24 '18 at 4:35
|
show 6 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53440696%2fsha-1-in-c-on-little-endian-environment%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 '18 at 4:47
I've clarified the question at the end. But I guess to narrow it down: "Am I doing my endianness conversion correctly?"
– xornoz
Nov 23 '18 at 4:55
Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 '18 at 5:00
Most implementations I have seen are for both big-endian and little endian. Try this link, it's for little endian github.com/B-Con/crypto-algorithms/blob/master
– Barmak Shemirani
Nov 23 '18 at 5:00
1
By the way endianness comes into play when reinterpreting memory, not for just general arithmetic (including bitwise operations). There is no reinterpretation in this code so it should not matter.
– harold
Nov 23 '18 at 6:19