'Matlab SHA-1 custom implementation doesn't give the right result
I trying to have a sha1 algorithm in Matlab.
I know I can use System.Security.Cryptography.HashAlgorithm.Create('SHA1');, but that relies on .NET, which I'd like to avoid.
I also found this thread, which suggest to use MessageDigest.getInstance("SHA-1"), but the output is not good.
I haven't found any other portable way.
Here's my code based on Wikipedia pseudo code, the result is also off. The only solution that gives result similar to online SHA1 is the .Net function.
Can somebody see the error in my function?
function [hh] = sha1(bytes_in)
% Note 1: All variables are unsigned 32-bit quantities and wrap modulo 232 when calculating, except for
% ml, the message length, which is a 64-bit quantity, and
% hh, the message digest, which is a 160-bit quantity.
% Note 2: All constants in this pseudo code are in big endian.
% Within each word, the most significant byte is stored in the leftmost byte position
%
% Initialize variables:
bytes_in = squeeze(uint8(bytes_in));
bytes_in = reshape(bytes_in, length(bytes_in), 1);
h0 = uint32(0x67452301);
h1 = uint32(0xEFCDAB89);
h2 = uint32(0x98BADCFE);
h3 = uint32(0x10325476);
h4 = uint32(0xC3D2E1F0);
% Pre-processing:
% append the bit '1' to the message e.g. by adding 0x80 if message length is a multiple of 8 bits.
% append 0 ? k < 512 bits '0', such that the resulting message length in bits
% is congruent to ?64 ? 448 (mod 512)
% append ml, the original message length in bits, as a 64-bit big-endian integer.
% Thus, the total length is a multiple of 512 bits.
%
message_len64 = uint64(length(bytes_in));
messages_len_bytes = zeros(8, 1);
for i=1:8
messages_len_bytes(i) = uint8(bitshift(message_len64, -64+i*8));
end
bytes_in = [bytes_in; 0x80];
padlen = 64-8 - mod(length(bytes_in), 64);
bytes_in = [bytes_in; zeros(padlen,1);messages_len_bytes];
assert(mod(length(bytes_in), 64) == 0);
chunk_count = length(bytes_in)/64;
% Process the message in successive 512-bit chunks:
% break message into 512-bit chunks
for i=1:chunk_count
chunk = bytes_in( ((i-1)*64+1):(i*64));
assert(length(chunk) == 64);
% Break chunk into sixteen 32-bit big-endian words w[i], 0 ? i ? 15
w = uint32(zeros(80,1));
for j=0:15
p1 = bitshift(uint32(chunk(j*4+1)),24);
p2 = bitshift(uint32(chunk(j*4+2)),16);
p3 = bitshift(uint32(chunk(j*4+3)),8);
p4 = bitshift(uint32(chunk(j*4+4)),0);
w(j+1) = p1 + p2 + p3 + p4;
end
% Message schedule: extend the sixteen 32-bit words into eighty 32-bit words:
for j=17:80
temp = bitxor(bitxor(bitxor(w(j-3),w(j-8)), w(j-14)), w(j-16));
w(j) = leftrotate32(temp, 1);
end
% Initialize hash value for this chunk:
a = h0;
b = h1;
c = h2;
d = h3;
e = h4;
for j=1:80
if j >= 1 && j <= 20
f = bitor(bitand(b,c), bitand(bitcmp(b), d));
k = 0x5A827999;
elseif j >= 21 && j <= 40
f = bitxor(bitxor(b,c), d);
k = 0x6ED9EBA1;
elseif j >= 41 && j <= 60
f = bitor(bitor(bitand(b, c),bitand(b, d)), bitand(c, d)) ;
k = 0x8F1BBCDC;
elseif j >= 61 && j <= 80
f = bitxor(bitxor(b,c), d);
k = 0xCA62C1D6;
end
temp = uint64(leftrotate32(a,5)) + uint64(f) + uint64(e) + uint64(k) + uint64(w(j));
temp = uint32(bitand(temp, uint64(0xFFFFFFFF)));
e = d;
d = c;
c = leftrotate32(b, 30);
b = a;
a = temp;
end
% Add this chunk's hash to result so far:
h0 = uint32(bitand(uint64(h0) + uint64(a), uint64(0xFFFFFFFF)));
h1 = uint32(bitand(uint64(h1) + uint64(b), uint64(0xFFFFFFFF)));
h2 = uint32(bitand(uint64(h2) + uint64(c), uint64(0xFFFFFFFF)));
h3 = uint32(bitand(uint64(h3) + uint64(d), uint64(0xFFFFFFFF)));
h4 = uint32(bitand(uint64(h4) + uint64(e), uint64(0xFFFFFFFF)));
% Produce the final hash value (big-endian) as a 160-bit number:
hh = [dec2hex(h0, 8), dec2hex(h1, 8), dec2hex(h2, 8), dec2hex(h3, 8), dec2hex(h4, 8)];
assert(length(hh) == 160/8*2)
end
end
function vout = leftrotate32(v32, v)
vout = uint32(bin2dec(circshift(dec2bin(v32, 32), -v)));
end
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
