Esempio n. 1
0
        public static byte[] SHA1(byte[] message)
        {
            // Initialize buffers
            uint h0 = 0x67452301;
            uint h1 = 0xEFCDAB89;
            uint h2 = 0x98BADCFE;
            uint h3 = 0x10325476;
            uint h4 = 0xC3D2E1F0;

            // Pad message
            int ml = message.Length + 1;

            byte[] msg = new byte[ml + ((960 - (ml * 8 % 512)) % 512) / 8 + 8];
            Array.Copy(message, msg, message.Length);
            msg[message.Length] = 0x80;
            long len = message.Length * 8;

            for (int i = 0; i < 8; ++i)
            {
                msg[msg.Length - 1 - i] = (byte)((len >> (i * 8)) & 255);
            }
            //Support.WriteToArray(msg, message.Length * 8, msg.Length - 8);
            //for (int i = 0; i <4; ++i) msg[msg.Length - 5 - i] = (byte)(((message.Length*8) >> (i * 8)) & 255);

            int chunks = msg.Length / 64;

            // Perform hashing for each 512-bit block
            for (int i = 0; i < chunks; ++i)
            {
                // Split block into words (allocated out here to prevent massive garbage buildup)
                uint[] w = new uint[80];

                // Compute initial source data from padded message
                for (int j = 0; j < 16; ++j)
                {
                    w[j] |= (uint)((msg[i * 64 + j * 4] << 24) | (msg[i * 64 + j * 4 + 1] << 16) | (msg[i * 64 + j * 4 + 2] << 8) | (msg[i * 64 + j * 4 + 3] << 0));
                }

                // Expand words
                for (int j = 16; j < 80; ++j)
                {
                    w[j] = Rot(w[j - 3] ^ w[j - 8] ^ w[j - 14] ^ w[j - 16], 1);
                }

                // Initialize chunk-hash
                uint
                    a = h0,
                    b = h1,
                    c = h2,
                    d = h3,
                    e = h4;

                // Do hash rounds
                for (int t = 0; t < 80; ++t)
                {
                    uint tmp = Rot(a, 5) + func(t, b, c, d) + e + K(t) + w[t];
                    e = d;
                    d = c;
                    c = Rot(b, 30);
                    b = a;
                    a = tmp;
                }

                // Add to result
                h0 += a;
                h1 += b;
                h2 += c;
                h3 += d;
                h4 += e;
            }

            return(Support.WriteContiguous(new byte[20], 0, Support.SwapEndian(h0), Support.SwapEndian(h1), Support.SwapEndian(h2), Support.SwapEndian(h3), Support.SwapEndian(h4)));
        }
Esempio n. 2
0
        // Memory-optimized implementation of Secure Hashing Algorithm 1 (SHA1)
        // NOTE: This method is NOT thread-safe!
        public static SHA1Result SHA1_Opt(byte[] message)
        {
            SHA1Result result = new SHA1Result
            {
                // Initialize buffers
                i0 = 0x67452301,
                i1 = 0xEFCDAB89,
                i2 = 0x98BADCFE,
                i3 = 0x10325476,
                i4 = 0xC3D2E1F0
            };

            // Pad message
            long len = message.Length * 8;
            int
                ml  = message.Length + 1,
                max = ml + ((960 - (ml * 8 % 512)) % 512) / 8 + 8;

            // Replaces the allocation of a lot of bytes
            byte GetMsg(int idx)
            {
                if (idx < message.Length)
                {
                    return(message[idx]);
                }
                else if (idx == message.Length)
                {
                    return(0x80);
                }
                else if (max - idx <= 8)
                {
                    return((byte)((len >> ((max - 1 - idx) * 8)) & 255));
                }
                return(0);
            }

            int chunks = max / 64;

            // Slow (at least with debugger because it spams stack frames)

            /*uint ComputeIndex(int block, int idx)
             * {
             *  if (idx < 16)
             *      return (uint)((GetMsg(block * 64 + idx * 4) << 24) | (GetMsg(block * 64 + idx * 4 + 1) << 16) | (GetMsg(block * 64 + idx * 4 + 2) << 8) | (GetMsg(block * 64 + idx * 4 + 3) << 0));
             *  else
             *      return Rot(ComputeIndex(block, idx - 3) ^ ComputeIndex(block, idx - 8) ^ ComputeIndex(block, idx - 14) ^ ComputeIndex(block, idx - 16), 1);
             * }*/

            // Perform hashing for each 512-bit block
            for (int i = 0; i < chunks; ++i)
            {
                // Compute initial source data from padded message
                for (int j = 0; j < 16; ++j)
                {
                    block[j] = (uint)((GetMsg(i * 64 + j * 4) << 24) | (GetMsg(i * 64 + j * 4 + 1) << 16) | (GetMsg(i * 64 + j * 4 + 2) << 8) | (GetMsg(i * 64 + j * 4 + 3) << 0));
                }

                // Expand words
                for (int j = 16; j < 80; ++j)
                {
                    block[j] = Rot(block[j - 3] ^ block[j - 8] ^ block[j - 14] ^ block[j - 16], 1);
                }

                // Initialize chunk-hash
                uint
                    a = result.i0,
                    b = result.i1,
                    c = result.i2,
                    d = result.i3,
                    e = result.i4;

                // Do hash rounds
                for (int t = 0; t < 80; ++t)
                {
                    uint tmp = Rot(a, 5) + func(t, b, c, d) + e + K(t) + block[i];
                    e = d;
                    d = c;
                    c = Rot(b, 30);
                    b = a;
                    a = tmp;
                }
                result.i0 += a;
                result.i1 += b;
                result.i2 += c;
                result.i3 += d;
                result.i4 += e;
            }

            // Serialize result
            result.i0 = Support.SwapEndian(result.i0);
            result.i1 = Support.SwapEndian(result.i1);
            result.i2 = Support.SwapEndian(result.i2);
            result.i3 = Support.SwapEndian(result.i3);
            result.i4 = Support.SwapEndian(result.i4);
            return(result);
        }
Esempio n. 3
0
        // Password-Based Key Derivation Function 2. Used to generate "pseudorandom" keys from a given password and salt using a certain PRF applied a certain amount of times (iterations).
        // dklen specified the "derived key length" in bytes. It is recommended to use a high number for the iterations variable (somewhere around 4096 is the standard for SHA1 currently)
        public static byte[] PBKDF2(PRF function, byte[] password, byte[] salt, int iterations, int dklen)
        {
            byte[] dk   = new byte[0]; // Create a placeholder for the derived key
            uint   iter = 1;           // Track the iterations

            while (dk.Length < dklen)
            {
                // F-function
                // The F-function (PRF) takes the amount of iterations performed in the opposite endianness format from what C# uses, so we have to swap the endianness
                byte[] u    = function(password, Support.Concatenate(salt, Support.WriteToArray(new byte[4], Support.SwapEndian(iter), 0)));
                byte[] ures = new byte[u.Length];
                Array.Copy(u, ures, u.Length);
                for (int i = 1; i < iterations; ++i)
                {
                    // Iteratively apply the PRF
                    u = function(password, u);
                    for (int j = 0; j < u.Length; ++j)
                    {
                        ures[j] ^= u[j];
                    }
                }

                // Concatenate the result to the dk
                dk = Support.Concatenate(dk, ures);

                ++iter;
            }

            // Clip aby bytes past what we needed (yes, that's really what the standard is)
            return(dk.ToLength(dklen));
        }