view dcrypt/crypto/hashes/SHA1.d @ 28:ad687db713a4

Further reworked the code for hash padding. Replaced all instances of 'char[]' with 'string' and removed a few 'const' modifiers as per Glenn Haecker's patch for D2 compatibility. Updated CONTRIBUTORS file.
author Thomas Dixon <reikon@reikon.us>
date Sun, 10 May 2009 22:38:48 -0400
parents 8b5eaf3c2979
children
line wrap: on
line source

/**
 * This file is part of the dcrypt project.
 *
 * Copyright: Copyright (C) dcrypt contributors 2008. All rights reserved.
 * License:   MIT
 * Authors:   Thomas Dixon
 */

module dcrypt.crypto.hashes.SHA1;

public import dcrypt.crypto.Hash;

/** 
 * Implementation of the US NSA's SHA-1.
 * 
 * Conforms: FIPS 180-1
 * References: http://www.itl.nist.gov/fipspubs/fip180-1.htm
 * Bugs: SHA-1 is not cryptographically secure.
 */
class SHA1 : Hash
{
    protected uint h0, h1, h2, h3, h4;
    
    this (void[] input_=null)
    {
        reset();
        super(input_);
    }

    uint blockSize()
    {
        return 64;
    }
    
    uint digestSize()
    {
        return 20;
    }
    
    string name()
    {
        return "SHA1";
    }
    
    void transform(ubyte[] input)
    {
        uint[] w = new uint[80];
        
        for (int i = 0, j = 0; i < 16; i++,j+=int.sizeof)
            w[i] = ByteConverter.BigEndian.to!(uint)(input[j..j+int.sizeof]);
        
        for (int i = 16; i < 80; i++)
            w[i] = Bitwise.rotateLeft(w[i-3]^w[i-8]^w[i-14]^w[i-16], 1);
        
        uint a = h0,
             b = h1,
             c = h2,
             d = h3,
             e = h4;

        int i = 0;
        for (; i < 20;)
        {
            e += Bitwise.rotateLeft(a, 5) + f0(b, c, d) + w[i++];
            b = Bitwise.rotateLeft(b, 30);
            
            d += Bitwise.rotateLeft(e, 5) + f0(a, b, c) + w[i++];
            a = Bitwise.rotateLeft(a, 30);
       
            c += Bitwise.rotateLeft(d, 5) + f0(e, a, b) + w[i++];
            e = Bitwise.rotateLeft(e, 30);
       
            b += Bitwise.rotateLeft(c, 5) + f0(d, e, a) + w[i++];
            d = Bitwise.rotateLeft(d, 30);

            a += Bitwise.rotateLeft(b, 5) + f0(c, d, e) + w[i++];
            c = Bitwise.rotateLeft(c, 30);
        }
        
        for (; i < 40;)
        {
            e += Bitwise.rotateLeft(a, 5) + f1(b, c, d) + w[i++];
            b = Bitwise.rotateLeft(b, 30);
            
            d += Bitwise.rotateLeft(e, 5) + f1(a, b, c) + w[i++];
            a = Bitwise.rotateLeft(a, 30);
       
            c += Bitwise.rotateLeft(d, 5) + f1(e, a, b) + w[i++];
            e = Bitwise.rotateLeft(e, 30);
       
            b += Bitwise.rotateLeft(c, 5) + f1(d, e, a) + w[i++];
            d = Bitwise.rotateLeft(d, 30);

            a += Bitwise.rotateLeft(b, 5) + f1(c, d, e) + w[i++];
            c = Bitwise.rotateLeft(c, 30);
        }
        
        for (; i < 60;)
        {
            e += Bitwise.rotateLeft(a, 5) + f2(b, c, d) + w[i++];
            b = Bitwise.rotateLeft(b, 30);
            
            d += Bitwise.rotateLeft(e, 5) + f2(a, b, c) + w[i++];
            a = Bitwise.rotateLeft(a, 30);
       
            c += Bitwise.rotateLeft(d, 5) + f2(e, a, b) + w[i++];
            e = Bitwise.rotateLeft(e, 30);
       
            b += Bitwise.rotateLeft(c, 5) + f2(d, e, a) + w[i++];
            d = Bitwise.rotateLeft(d, 30);

            a += Bitwise.rotateLeft(b, 5) + f2(c, d, e) + w[i++];
            c = Bitwise.rotateLeft(c, 30);
        }
        
        for (; i < 80;)
        {
            e += Bitwise.rotateLeft(a, 5) + f3(b, c, d) + w[i++];
            b = Bitwise.rotateLeft(b, 30);
            
            d += Bitwise.rotateLeft(e, 5) + f3(a, b, c) + w[i++];
            a = Bitwise.rotateLeft(a, 30);
       
            c += Bitwise.rotateLeft(d, 5) + f3(e, a, b) + w[i++];
            e = Bitwise.rotateLeft(e, 30);
       
            b += Bitwise.rotateLeft(c, 5) + f3(d, e, a) + w[i++];
            d = Bitwise.rotateLeft(d, 30);

            a += Bitwise.rotateLeft(b, 5) + f3(c, d, e) + w[i++];
            c = Bitwise.rotateLeft(c, 30);
        }

        h0 += a;
        h1 += b;
        h2 += c;
        h3 += d;
        h4 += e;
    }
    
    private uint f0(uint x, uint y, uint z)
    {
        return (z^(x&(y^z))) + 0x5a827999;
    }

    private uint f1(uint x, uint y, uint z)
    {
        return (x^y^z) + 0x6ed9eba1;
    }

    private uint f2(uint x, uint y, uint z)
    {
        return ((x&y)|(z&(x|y))) + 0x8f1bbcdc;
    }

    private uint f3(uint x, uint y, uint z)
    {
        return (x^y^z) + 0xca62c1d6;
    }
    
    ubyte[] digest()
    {
        padMessage(MODE_SHA);
        ubyte[] result = new ubyte[digestSize];
        
        result[0..4] = ByteConverter.BigEndian.from!(uint)(h0);
        result[4..8] = ByteConverter.BigEndian.from!(uint)(h1);
        result[8..12] = ByteConverter.BigEndian.from!(uint)(h2);
        result[12..16] = ByteConverter.BigEndian.from!(uint)(h3);
        result[16..20] = ByteConverter.BigEndian.from!(uint)(h4);
        
        reset();
        return result;
    }

    void reset()
    {
        super.reset();
        h0 = 0x67452301u;
        h1 = 0xefcdab89u;
        h2 = 0x98badcfeu;
        h3 = 0x10325476u;
        h4 = 0xc3d2e1f0u;
    }
    
    SHA1 copy()
    {
        SHA1 h = new SHA1(buffer[0..index]);
        h.bytes = bytes;
        h.h0 = h0;
        h.h1 = h1;
        h.h2 = h2;
        h.h3 = h3;
        h.h4 = h4;
        return h;
    }
   
    debug (UnitTest)
    {
        unittest
        {
            static string[] test_inputs = [
                "",
                "abc",
                "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
                "a",
                "0123456701234567012345670123456701234567012345670123456701234567"
            ];
            
            static int[] test_repeat = [
                1, 1, 1, 1000000, 10
            ];
            
            static string[] test_results = [
                "da39a3ee5e6b4b0d3255bfef95601890afd80709",
                "a9993e364706816aba3e25717850c26c9cd0d89d",
                "84983e441c3bd26ebaae4aa1f95129e5e54670f1",
                "34aa973cd4c4daa4f61eeb2bdbad27316534016f",
                "dea356a2cddd90c7a7ecedc5ebb563934f460452"
            ];
            
            SHA1 h = new SHA1();
            foreach (uint i, string input; test_inputs)
            {
                for (int j = 0; j < test_repeat[i]; j++)
                    h.update(input);
                string digest = h.hexDigest();
                assert(digest == test_results[i], 
                        h.name~": ("~digest~") != ("~test_results[i]~")");
            }
        }
    }
}