SHA-1 in C on little-endian environment












1














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?










share|improve this question
























  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
    – xornoz
    Nov 23 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 at 4:55












  • Okay, I hope to have cleared it up the main body now.
    – xornoz
    Nov 23 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 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 at 6:19
















1














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?










share|improve this question
























  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
    – xornoz
    Nov 23 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 at 4:55












  • Okay, I hope to have cleared it up the main body now.
    – xornoz
    Nov 23 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 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 at 6:19














1












1








1







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?










share|improve this question















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 23 at 7:01









chux

80.2k870147




80.2k870147










asked Nov 23 at 4:34









xornoz

83




83












  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
    – xornoz
    Nov 23 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 at 4:55












  • Okay, I hope to have cleared it up the main body now.
    – xornoz
    Nov 23 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 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 at 6:19


















  • My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
    – xornoz
    Nov 23 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 at 4:55












  • Okay, I hope to have cleared it up the main body now.
    – xornoz
    Nov 23 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 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 at 6:19
















My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 at 4:47






My output is incorrect. To me, it seems everything is correct, but clearly there is a mistake somewhere.
– xornoz
Nov 23 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 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 at 4:55














Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 at 5:00




Okay, I hope to have cleared it up the main body now.
– xornoz
Nov 23 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 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 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 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 at 6:19












1 Answer
1






active

oldest

votes


















1















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;





share|improve this answer























  • Are you compiling on a big-endian machine?
    – xornoz
    Nov 23 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 at 6:20










  • The constants h0 = 0x67452301;...
    – xornoz
    Nov 23 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 at 6:24






  • 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 at 4:35













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
});


}
});














draft saved

draft discarded


















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









1















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;





share|improve this answer























  • Are you compiling on a big-endian machine?
    – xornoz
    Nov 23 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 at 6:20










  • The constants h0 = 0x67452301;...
    – xornoz
    Nov 23 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 at 6:24






  • 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 at 4:35


















1















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;





share|improve this answer























  • Are you compiling on a big-endian machine?
    – xornoz
    Nov 23 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 at 6:20










  • The constants h0 = 0x67452301;...
    – xornoz
    Nov 23 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 at 6:24






  • 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 at 4:35
















1












1








1







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;





share|improve this answer















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;






share|improve this answer














share|improve this answer



share|improve this answer








edited Nov 23 at 6:38

























answered Nov 23 at 6:05









chux

80.2k870147




80.2k870147












  • Are you compiling on a big-endian machine?
    – xornoz
    Nov 23 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 at 6:20










  • The constants h0 = 0x67452301;...
    – xornoz
    Nov 23 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 at 6:24






  • 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 at 4:35




















  • Are you compiling on a big-endian machine?
    – xornoz
    Nov 23 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 at 6:20










  • The constants h0 = 0x67452301;...
    – xornoz
    Nov 23 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 at 6:24






  • 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 at 4:35


















Are you compiling on a big-endian machine?
– xornoz
Nov 23 at 6:16




Are you compiling on a big-endian machine?
– xornoz
Nov 23 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 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 at 6:20












The constants h0 = 0x67452301;...
– xornoz
Nov 23 at 6:22




The constants h0 = 0x67452301;...
– xornoz
Nov 23 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 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 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 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 at 4:35




















draft saved

draft discarded




















































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.





Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


Please pay close attention to the following guidance:


  • 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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Contact image not getting when fetch all contact list from iPhone by CNContact

count number of partitions of a set with n elements into k subsets

A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks