7
$\begingroup$

For RIPEMD hashing algorithm on hardware I am not exactly getting how padding works

So as per my understanding padding will work like explained below:

For ripemd 160 message should be multiple of 512 bits. So, along with message to make it 512 bits, after message we pad 1 following zeros. Last 64 bits of 512 block are reserved for length of the message.

Suppose message is a which I have to send it for hashing. So first it will go through padding. So for message a asci value 61 will be send for padding which is nothing but 61 hex.

So after value 61 there will be 1 and followed by zeros and last 64 bits will be length of message. So as per little endian conventions, byte wise representation of a after padding will looks like below right?

512'h08000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008061

(MSB side last byte 08 is nothing but length of message a LSB side 61 is actual message then followed by 1 and zeros) as ripemd is little endian based.

Please correct me if I am wrong. Is my description correct? If not, how does RIPEMD160 pad the message?

$\endgroup$
0

1 Answer 1

4
$\begingroup$

RIPEMD-160 uses precisely the same padding and endianess convention as MD5.

Everything is little-endian, with the exception of the order of bits in bytes, which is kept big-endian. If the message is $n$-bit, it is appended a single bit at 1 and $511-((n+64)\bmod512)$ bit(s) at 0 , then the representation of $n$ on 64 bits. The resulting padded message is an integral number of 512-bit blocks, which are each considered 16 words of 32 bits.

Note: It follows that the padding bit at 1 corresponds to a byte mask with value $2^{7-(n\bmod 8)}$. The $n\bmod 8$ last message bit(s) are in the high-order bit(s) of that byte, which $7-(n\bmod 8)$ low-order bit(s) are 0.


Suppose the message is the one-character string "a", and that is coded in ASCII as the single byte 61h = 01100001b = 97.

That's the bitstring 01100001. $n=8$, thus the padding is 1 followed by 439 0 (with the first eight bits of that padding 10000000 corresponding to byte 80h), followed by the length $n=8$ represented as the bitstring 00001000 00000000 00000000 00000000 0000000 00000000 00000000 0000000 (with the first eight bits 00001000 corresponding to the byte 08h).

Showing this as a string of 64 bytes with bytes and 32-bit boundaries shown (and individual bytes shown in big-endian hexadecimal), the padded block is

61 80 00 00   00 00 00 00   00 00 00 00   00 00 00 00
00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00
00 00 00 00   00 00 00 00   00 00 00 00   00 00 00 00
00 00 00 00   00 00 00 00   08 00 00 00   00 00 00 00

Packing that into 32-bit words using little-endian convention (and individual 32-bit words shown in big-endian hexadecimal), we get

00008061      00000000      00000000      00000000
00000000      00000000      00000000      00000000
00000000      00000000      00000000      00000000
00000000      00000000      00000008      00000000

or in decimal { 32865, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0 }.


Note: a former version of this answer did not take into account the exception to little-endianness in the conversion of bytes to/from bits, and used uppercase ASCII code in the example. I'm confident about the present revised version.


Simple demonstration and example output for the reference code rmd160

// Demonstration of rmd160 - public domain
// note: on machines with more than 32-bit unsigned long, rmd160.h requires a simple change
#include "rmd160.h" // at http://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.h
#define SIZEOFHASH  20      // size of the hash in bytes
#define SIZEOFBLOCK 64      // size of a block in bytes

// including the code simplifies compilation+linking into a tool
#include "rmd160.c" // at http://homes.esat.kuleuven.be/~bosselae/ripemd160/ps/AB-9601/rmd160.c

// hash a byte buffer in memory
void hashmd160(
    const byte  *iData,             // input
    size_t      iDataLength,        // size of input in bytes
    byte        oHash[SIZEOFHASH]   // result (must be allocated by caller)
    )
    {
    dword       vHash32[SIZEOFHASH%4==0 ? SIZEOFHASH/4 : -1 ];      // the hash, as 32-bit words
    dword       vBlock32[SIZEOFBLOCK%4==0 ? SIZEOFBLOCK/4 : -1 ];   // a block, as 32-bit words
    size_t      vb;
    int         vj;
    // start hashing
    MDinit(vHash32);
    // hash full blocks; needed only when iDataLength>=SIZEOFBLOCK
    for (vb = iDataLength/SIZEOFBLOCK; vb!=0; --vb)
        { // make a little-endian copy of SIZEOFBLOCK bytes from iData to vBlock32
        for (vj = 0; vj<SIZEOFBLOCK/4; ++vj, iData += 4)
            vBlock32[vj] = iData[0] | iData[1]<<8 | (dword)(iData[2] | iData[3]<<8)<<16;
        compress(vHash32,vBlock32);
        }
    // hash remaining bytes
    MDfinish(vHash32, (byte *)iData, iDataLength, iDataLength>>16>>16);
    // make a little-endian copy of SIZEOFHASH bytes from vHash32 to oHash
    for (vj = 0; vj<SIZEOFHASH; ++vj)
        oHash[vj] = (byte)(vHash32[vj>>2]>>((vj&3)<<3));
    }

// hash each argument, print its hash and the (quoted) argument
int main(int argc, char *argv[])
    {
    byte    vHash[SIZEOFHASH];
    int     vj,va;
    for(va=1; va<argc; ++va) {
        hashmd160((const byte *)(argv[va]),strlen(argv[va]),vHash);
        for (vj = 0; vj<SIZEOFHASH; ++vj)
            printf("%02x",vHash[vj]);
        printf(" \"%s\"\n",argv[va]);
        }
    return EXIT_SUCCESS;
    }

/* Example output
9c1185a5c5e9fc54612808977ee8f548b2258d31 ""
0bdc9d2d256b3ee9daae347be6f4dc835a467ffe "a"
8eb208f7e05d987a9b044a8e98c6b087f15a0bfc "abc"
5d0689ef49d2fae572b881b123a85ffa21595f36 "message digest"
f71c27109c692c1b56bbdceb5b9d2865b3708dbc "abcdefghijklmnopqrstuvwxyz"
12a053384a9c0c88e405a06c27dcf49ada62eb2b "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
b0e20b6e3116640286ed3a87a5713079b21f5189 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
9b752e45573d4b39f4dbd3323cab82bf63326bfb "12345678901234567890123456789012345678901234567890123456789012345678901234567890"
*/
$\endgroup$
6
  • $\begingroup$ Thanks @fgrieu. Still i have bit confusion. If we considering big endianess, input message will be something like this 65800000...........0000000008 65 ="a" in hex 8000..... = 1 and zero pad 08= 8 bit length. Because it is little endian it will order like this. 08000000...........0000008065 As in little endian byte wise reverse will occur not all bit exact reverse as you have mentioned in your answer. please correct me $\endgroup$
    – seeker
    Commented Feb 3, 2016 at 5:08
  • $\begingroup$ thanks @fgrieu. This gave me clear idea. Now I am trying to test my RIPEMD 160. I am using some test vectors and online hash converters. My results are not matching. So must be my hashing functions has some functional bug. So is there any test suite which gives round wise output of all constants ???. Like for SHA1,2 there are sites which gives output for each rounds. which makes debugging bit easier. Thanks in advance that helped a lot to me $\endgroup$
    – seeker
    Commented Feb 3, 2016 at 9:21
  • $\begingroup$ @seeker: the page I link to links to a reference C implementation. It is easy to instrument to show intermediary results. I'm not aware of other source of intermediary results. $\endgroup$
    – fgrieu
    Commented Feb 3, 2016 at 11:54
  • $\begingroup$ I tried using c codes from link you have provided. But I am not sure that implementation is correct. Because i tried giving some inputs for c code. But final hash results are not matching with expected standard results. Like i have given "a" as input but for which c code giving hash value as 508a6ccc545b32641fe7311048defe7cf599ada3. but the expected ripemd hash value for "a" is 0bdc9d2d256b3ee9daae347be6f4dc835a467ffe. so is that c implementation is correct????? $\endgroup$
    – seeker
    Commented Feb 4, 2016 at 9:53
  • 1
    $\begingroup$ Thanks you very much sir. That help me a lot in doing software implementation. Actually problem was same which you have mentioned. Changing unsigned long to unsigned int and kudos it's working totally fine. As I am hdl coder didn't work much on C, I couldn't get it easily. Now I can easily go back to debugging verilog hardware implementation of ripemd. Thanks again for your valuable time. $\endgroup$
    – seeker
    Commented Feb 5, 2016 at 5:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.