RIPEMD-160 představuje otevřenou standardizovanou hash funkci postavenou na standardu MD4. Dosud nebyla nalezena kolize a je obecně považována za bezpečnou.

Hash funkce RIPEMD

Hash RIPEMD byla představena v roce 1996 jako výsledek výzkumného projektu univerzity v Leuvenu v Belgii. Konstrukce hash funkcí z rodiny RIPEMD vychází z funkce MD4. Nejčastěji používanou variantou je RIPEMD-160 se 160 bitovým výstupem (digest size). Existují také varianty se 128, 256 a 320 bitovým výstupem.

Princip

Princip hash funkce RIPEMD-160

Hash funkce (varianta RIPMD-160) je svoji vnitřní strukturou velmi podobná hash funkci MD4. Stejně jako MD4 využívá i RIPEMD zápis proměnných v little-endian endianitě.

Programování

Jedna z možností, jak implementovat RIPEMD-160 hash funkci následuje (zdroj ZDE):

#! /usr/bin/python
#coding: UTF-8
import argparse


def writeFile(fname, code):
    try:
        with open(fname, 'wb') as f:
		    f.write(''.join(code))
    except IOError:
        exit('No such file or directory ' + fname)


def readFile(fname):
    try:
        with open(fname, 'rb') as f:
            text = f.read()
    except IOError:
        exit('No such file or directory ' + fname)
    return text		

	
def getArgs():
    parser = argparse.ArgumentParser()
    parser.add_argument('inFile')
    parser.add_argument('outFile')
    return parser.parse_args()	

	

def alignment(msg):
    msg_len = len(msg) * 8
    msg.append(0x80)
    while len(msg)% 64 != 56:
	    msg += [0]  
    for i in range(8):
        msg.append(msg_len >> i * 8)
    return msg	
	
	

def F(j, x, y, z):
    if j < 16:	
        return (x ^ y ^ z)
    if j < 32: 
        return(x & y) | (~x & z)
    if j < 48:	
        return ((x | ~y) ^ z)
    if j < 64:
        return (x & z) | (y & ~z)
    if j < 80:
        return (x ^ (y | ~z))		


def K(j):
    if j < 16:
        return 0x00000000	
    if j < 32:
        return 0x5A827999		
    if j < 48:
        return 0x6ED9EBA1
    if j < 64:
        return 0x8F1BBCDC
    if j < 80:
        return 0xA953FD4E
		
def K1(j):
    if j < 16:
        return 0x50A28BE6
    if j < 32:
        return 0x5C4DD124
    if j < 48:
        return 0x6D703EF3
    if j < 64:
        return 0x7A6D76E9
    if j < 80:
        return 0x00000000
		
		
def rotateLeft(x, n):
    x = x & 0xFFFFFFFF   
    return ((x << n) | (x >> (32-n))) & 0xFFFFFFFF	
	
	
def toLittleEndian(word):
    res = 0
    res |= ((word >> 0) & 0xFF) << 24
    res |= ((word >> 8) & 0xFF) << 16
    res |= ((word >> 16) & 0xFF) << 8
    res |= ((word >> 24) & 0xFF) << 0
    return res
	
		
def rounds(buf, x):
    A = buf[0]
    B = buf[1]
    C = buf[2]
    D = buf[3]
    E = buf[4]
	
    A1 = buf[0]
    B1 = buf[1]
    C1 = buf[2]
    D1 = buf[3]
    E1 = buf[4]
	
    R = [
        0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
        7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
        3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
        1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
        4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13
        ]

    R1 = [
        5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
        6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
        15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
        8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
        12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11
        ]

    S = [
        11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
        7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
        11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
        11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
        9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6
        ]    

    S1 = [
        8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
        9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
        9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
        15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
        8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11
        ]

    for j in range(80):
        T = A + F(j, B, C, D) + x[R[j]] + K(j)
        T = rotateLeft(T, S[j]) + E 
        A = E
        E = D
        D = rotateLeft(C, 10)
        C = B
        B = T
		
        T = A1 + F(79 - j, B1, C1, D1) + x[R1[j]] + K1(j)
        T = rotateLeft(T, S1[j]) + E1 	
        A1 = E1
        E1 = D1
        D1 = rotateLeft(C1, 10)
        C1 = B1
        B1 = T
		
    T = (buf[1] + C + D1) 
    buf[1] = (buf[2] + D + E1)  
    buf[2] = (buf[3] + E + A1) 
    buf[3] = (buf[4] + A + B1)  
    buf[4] = (buf[0] + B + C1) 
    buf[0] = T	
	
    return buf
   
def calc_ripemd160(data):
    data = [ord(i) for i in data]
	
    data = alignment(data)

    buf = [0] * 5
    buf[0] = 0x67452301
    buf[1] = 0xefcdab89
    buf[2] = 0x98badcfe
    buf[3] = 0x10325476
    buf[4] = 0xc3d2e1f0
	
    data_words = []
    for i in range(len(data) / 4): 
        q = 0
        for j in range(4):
            q |= data[i * 4 + j] << j * 8
        data_words.append(q)
	
    for i in range(0, len(data_words), 16):
        x = data_words[i:i+16]
        buf = rounds(buf, x)
			
    res = ""
    for i in buf:
        res += "{:08x}".format(toLittleEndian(i))
		
    return res		
	
def main():
    print "ripemd-160"
    data = ""
    args = getArgs()
    data = readFile(args.inFile)
    res = calc_ripemd160(data)
    print "hash: ", res
    writeFile(args.outFile, res)
	
	
if __name__ == "__main__":
main()