/* * Mentalis.org Security Library * * Copyright © 2002-2005, The KPD-Team * All rights reserved. * http://www.mentalis.org/ * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Neither the name of the KPD-Team, nor the names of its contributors * may be used to endorse or promote products derived from this * software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Security.Cryptography; using System.Runtime.InteropServices; using Org.Mentalis.Security; namespace Org.Mentalis.Security.Cryptography { /// /// Computes the hash for the input data. /// /// Based on the papers located at the RIPEMD homepage. public sealed class RIPEMD160Managed : RIPEMD160 { /// /// Initializes a new instance of the class. This class cannot be inherited. /// public RIPEMD160Managed() { m_X = new uint[16]; m_HashValue = new uint[5]; m_ExtraData = new byte[0]; m_Disposed = false; Initialize(); } /// /// When overridden in a derived class, gets the input block size. /// /// The input block size. public override int InputBlockSize { get { return 64; } } /// /// Initializes an instance of . /// /// The RIPEMD160Managed instance has been disposed. public override void Initialize() { if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); m_HashValue[0] = 0x67452301; m_HashValue[1] = 0xefcdab89; m_HashValue[2] = 0x98badcfe; m_HashValue[3] = 0x10325476; m_HashValue[4] = 0xc3d2e1f0; m_ExtraData = new byte[0]; m_Length = 0; } /// /// Routes data written to the object into the hash algorithm for computing the hash. /// /// The array of data bytes. /// The offset into the byte array from which to begin using data. /// The number of bytes in the array to use as data. /// The instance has been disposed. protected override void HashCore(byte[] array, int ibStart, int cbSize) { if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); if (cbSize == 0) return; int offset = 0; byte[] total = new byte[m_ExtraData.Length + cbSize]; Array.Copy(m_ExtraData, 0, total, 0, m_ExtraData.Length); Array.Copy(array, ibStart, total, m_ExtraData.Length, cbSize); GCHandle gch = GCHandle.Alloc(m_X, GCHandleType.Pinned); IntPtr pointer = gch.AddrOfPinnedObject(); while(total.Length - offset >= 64) { // blocks must be handled in 64-byte blocks [array of 16 uints] Marshal.Copy(total, offset, pointer, 64); Compress(); offset += 64; } gch.Free(); m_ExtraData = new byte[total.Length - offset]; Array.Copy(total, offset, m_ExtraData, 0, m_ExtraData.Length); Array.Clear(total, 0, total.Length); m_Length += (uint)cbSize; } /// /// Returns the computed hash as an array of bytes after all data has been written to the object. /// /// The computed hash value. /// The instance has been disposed. protected override byte[] HashFinal() { if (m_Disposed) throw new ObjectDisposedException(this.GetType().FullName); CompressFinal(m_Length); byte[] hash = new byte[20]; GCHandle gch = GCHandle.Alloc(m_HashValue, GCHandleType.Pinned); IntPtr pointer = gch.AddrOfPinnedObject(); Marshal.Copy(pointer, hash, 0, 20); gch.Free(); return hash; } /// /// Releases the unmanaged resources used by the and optionally releases the managed resources. /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. protected override void Dispose(bool disposing) { base.Dispose(disposing); try { GC.SuppressFinalize(this); } catch {} m_Disposed = true; } /// /// Finalizes the MD2CryptoServiceProvider. /// ~RIPEMD160Managed() { Clear(); } #region Compress Method private void Compress() { uint aa = m_HashValue[0], bb = m_HashValue[1], cc = m_HashValue[2], dd = m_HashValue[3], ee = m_HashValue[4]; uint aaa = m_HashValue[0], bbb = m_HashValue[1], ccc = m_HashValue[2], ddd = m_HashValue[3], eee = m_HashValue[4]; /* round 1 */ FF(ref aa, bb, ref cc, dd, ee, m_X[ 0], 11); FF(ref ee, aa, ref bb, cc, dd, m_X[ 1], 14); FF(ref dd, ee, ref aa, bb, cc, m_X[ 2], 15); FF(ref cc, dd, ref ee, aa, bb, m_X[ 3], 12); FF(ref bb, cc, ref dd, ee, aa, m_X[ 4], 5); FF(ref aa, bb, ref cc, dd, ee, m_X[ 5], 8); FF(ref ee, aa, ref bb, cc, dd, m_X[ 6], 7); FF(ref dd, ee, ref aa, bb, cc, m_X[ 7], 9); FF(ref cc, dd, ref ee, aa, bb, m_X[ 8], 11); FF(ref bb, cc, ref dd, ee, aa, m_X[ 9], 13); FF(ref aa, bb, ref cc, dd, ee, m_X[10], 14); FF(ref ee, aa, ref bb, cc, dd, m_X[11], 15); FF(ref dd, ee, ref aa, bb, cc, m_X[12], 6); FF(ref cc, dd, ref ee, aa, bb, m_X[13], 7); FF(ref bb, cc, ref dd, ee, aa, m_X[14], 9); FF(ref aa, bb, ref cc, dd, ee, m_X[15], 8); /* round 2 */ GG(ref ee, aa, ref bb, cc, dd, m_X[ 7], 7); GG(ref dd, ee, ref aa, bb, cc, m_X[ 4], 6); GG(ref cc, dd, ref ee, aa, bb, m_X[13], 8); GG(ref bb, cc, ref dd, ee, aa, m_X[ 1], 13); GG(ref aa, bb, ref cc, dd, ee, m_X[10], 11); GG(ref ee, aa, ref bb, cc, dd, m_X[ 6], 9); GG(ref dd, ee, ref aa, bb, cc, m_X[15], 7); GG(ref cc, dd, ref ee, aa, bb, m_X[ 3], 15); GG(ref bb, cc, ref dd, ee, aa, m_X[12], 7); GG(ref aa, bb, ref cc, dd, ee, m_X[ 0], 12); GG(ref ee, aa, ref bb, cc, dd, m_X[ 9], 15); GG(ref dd, ee, ref aa, bb, cc, m_X[ 5], 9); GG(ref cc, dd, ref ee, aa, bb, m_X[ 2], 11); GG(ref bb, cc, ref dd, ee, aa, m_X[14], 7); GG(ref aa, bb, ref cc, dd, ee, m_X[11], 13); GG(ref ee, aa, ref bb, cc, dd, m_X[ 8], 12); /* round 3 */ HH(ref dd, ee, ref aa, bb, cc, m_X[ 3], 11); HH(ref cc, dd, ref ee, aa, bb, m_X[10], 13); HH(ref bb, cc, ref dd, ee, aa, m_X[14], 6); HH(ref aa, bb, ref cc, dd, ee, m_X[ 4], 7); HH(ref ee, aa, ref bb, cc, dd, m_X[ 9], 14); HH(ref dd, ee, ref aa, bb, cc, m_X[15], 9); HH(ref cc, dd, ref ee, aa, bb, m_X[ 8], 13); HH(ref bb, cc, ref dd, ee, aa, m_X[ 1], 15); HH(ref aa, bb, ref cc, dd, ee, m_X[ 2], 14); HH(ref ee, aa, ref bb, cc, dd, m_X[ 7], 8); HH(ref dd, ee, ref aa, bb, cc, m_X[ 0], 13); HH(ref cc, dd, ref ee, aa, bb, m_X[ 6], 6); HH(ref bb, cc, ref dd, ee, aa, m_X[13], 5); HH(ref aa, bb, ref cc, dd, ee, m_X[11], 12); HH(ref ee, aa, ref bb, cc, dd, m_X[ 5], 7); HH(ref dd, ee, ref aa, bb, cc, m_X[12], 5); /* round 4 */ II(ref cc, dd, ref ee, aa, bb, m_X[ 1], 11); II(ref bb, cc, ref dd, ee, aa, m_X[ 9], 12); II(ref aa, bb, ref cc, dd, ee, m_X[11], 14); II(ref ee, aa, ref bb, cc, dd, m_X[10], 15); II(ref dd, ee, ref aa, bb, cc, m_X[ 0], 14); II(ref cc, dd, ref ee, aa, bb, m_X[ 8], 15); II(ref bb, cc, ref dd, ee, aa, m_X[12], 9); II(ref aa, bb, ref cc, dd, ee, m_X[ 4], 8); II(ref ee, aa, ref bb, cc, dd, m_X[13], 9); II(ref dd, ee, ref aa, bb, cc, m_X[ 3], 14); II(ref cc, dd, ref ee, aa, bb, m_X[ 7], 5); II(ref bb, cc, ref dd, ee, aa, m_X[15], 6); II(ref aa, bb, ref cc, dd, ee, m_X[14], 8); II(ref ee, aa, ref bb, cc, dd, m_X[ 5], 6); II(ref dd, ee, ref aa, bb, cc, m_X[ 6], 5); II(ref cc, dd, ref ee, aa, bb, m_X[ 2], 12); /* round 5 */ JJ(ref bb, cc, ref dd, ee, aa, m_X[ 4], 9); JJ(ref aa, bb, ref cc, dd, ee, m_X[ 0], 15); JJ(ref ee, aa, ref bb, cc, dd, m_X[ 5], 5); JJ(ref dd, ee, ref aa, bb, cc, m_X[ 9], 11); JJ(ref cc, dd, ref ee, aa, bb, m_X[ 7], 6); JJ(ref bb, cc, ref dd, ee, aa, m_X[12], 8); JJ(ref aa, bb, ref cc, dd, ee, m_X[ 2], 13); JJ(ref ee, aa, ref bb, cc, dd, m_X[10], 12); JJ(ref dd, ee, ref aa, bb, cc, m_X[14], 5); JJ(ref cc, dd, ref ee, aa, bb, m_X[ 1], 12); JJ(ref bb, cc, ref dd, ee, aa, m_X[ 3], 13); JJ(ref aa, bb, ref cc, dd, ee, m_X[ 8], 14); JJ(ref ee, aa, ref bb, cc, dd, m_X[11], 11); JJ(ref dd, ee, ref aa, bb, cc, m_X[ 6], 8); JJ(ref cc, dd, ref ee, aa, bb, m_X[15], 5); JJ(ref bb, cc, ref dd, ee, aa, m_X[13], 6); /* parallel round 1 */ JJJ(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 5], 8); JJJ(ref eee, aaa, ref bbb, ccc, ddd, m_X[14], 9); JJJ(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 7], 9); JJJ(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 0], 11); JJJ(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 9], 13); JJJ(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 2], 15); JJJ(ref eee, aaa, ref bbb, ccc, ddd, m_X[11], 15); JJJ(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 4], 5); JJJ(ref ccc, ddd, ref eee, aaa, bbb, m_X[13], 7); JJJ(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 6], 7); JJJ(ref aaa, bbb, ref ccc, ddd, eee, m_X[15], 8); JJJ(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 8], 11); JJJ(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 1], 14); JJJ(ref ccc, ddd, ref eee, aaa, bbb, m_X[10], 14); JJJ(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 3], 12); JJJ(ref aaa, bbb, ref ccc, ddd, eee, m_X[12], 6); /* parallel round 2 */ III(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 6], 9); III(ref ddd, eee, ref aaa, bbb, ccc, m_X[11], 13); III(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 3], 15); III(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 7], 7); III(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 0], 12); III(ref eee, aaa, ref bbb, ccc, ddd, m_X[13], 8); III(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 5], 9); III(ref ccc, ddd, ref eee, aaa, bbb, m_X[10], 11); III(ref bbb, ccc, ref ddd, eee, aaa, m_X[14], 7); III(ref aaa, bbb, ref ccc, ddd, eee, m_X[15], 7); III(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 8], 12); III(ref ddd, eee, ref aaa, bbb, ccc, m_X[12], 7); III(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 4], 6); III(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 9], 15); III(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 1], 13); III(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 2], 11); /* parallel round 3 */ HHH(ref ddd, eee, ref aaa, bbb, ccc, m_X[15], 9); HHH(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 5], 7); HHH(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 1], 15); HHH(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 3], 11); HHH(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 7], 8); HHH(ref ddd, eee, ref aaa, bbb, ccc, m_X[14], 6); HHH(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 6], 6); HHH(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 9], 14); HHH(ref aaa, bbb, ref ccc, ddd, eee, m_X[11], 12); HHH(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 8], 13); HHH(ref ddd, eee, ref aaa, bbb, ccc, m_X[12], 5); HHH(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 2], 14); HHH(ref bbb, ccc, ref ddd, eee, aaa, m_X[10], 13); HHH(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 0], 13); HHH(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 4], 7); HHH(ref ddd, eee, ref aaa, bbb, ccc, m_X[13], 5); /* parallel round 4 */ GGG(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 8], 15); GGG(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 6], 5); GGG(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 4], 8); GGG(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 1], 11); GGG(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 3], 14); GGG(ref ccc, ddd, ref eee, aaa, bbb, m_X[11], 14); GGG(ref bbb, ccc, ref ddd, eee, aaa, m_X[15], 6); GGG(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 0], 14); GGG(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 5], 6); GGG(ref ddd, eee, ref aaa, bbb, ccc, m_X[12], 9); GGG(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 2], 12); GGG(ref bbb, ccc, ref ddd, eee, aaa, m_X[13], 9); GGG(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 9], 12); GGG(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 7], 5); GGG(ref ddd, eee, ref aaa, bbb, ccc, m_X[10], 15); GGG(ref ccc, ddd, ref eee, aaa, bbb, m_X[14], 8); /* parallel round 5 */ FFF(ref bbb, ccc, ref ddd, eee, aaa, m_X[12], 8); FFF(ref aaa, bbb, ref ccc, ddd, eee, m_X[15], 5); FFF(ref eee, aaa, ref bbb, ccc, ddd, m_X[10], 12); FFF(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 4], 9); FFF(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 1], 12); FFF(ref bbb, ccc, ref ddd, eee, aaa, m_X[ 5], 5); FFF(ref aaa, bbb, ref ccc, ddd, eee, m_X[ 8], 14); FFF(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 7], 6); FFF(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 6], 8); FFF(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 2], 13); FFF(ref bbb, ccc, ref ddd, eee, aaa, m_X[13], 6); FFF(ref aaa, bbb, ref ccc, ddd, eee, m_X[14], 5); FFF(ref eee, aaa, ref bbb, ccc, ddd, m_X[ 0], 15); FFF(ref ddd, eee, ref aaa, bbb, ccc, m_X[ 3], 13); FFF(ref ccc, ddd, ref eee, aaa, bbb, m_X[ 9], 11); FFF(ref bbb, ccc, ref ddd, eee, aaa, m_X[11], 11); /* combine results */ ddd += cc + m_HashValue[1]; /* final result for m_HashValue[0] */ m_HashValue[1] = m_HashValue[2] + dd + eee; m_HashValue[2] = m_HashValue[3] + ee + aaa; m_HashValue[3] = m_HashValue[4] + aa + bbb; m_HashValue[4] = m_HashValue[0] + bb + ccc; m_HashValue[0] = ddd; } private void CompressFinal(ulong length) { uint lswlen = (uint)(length & 0xFFFFFFFF); uint mswlen = (uint)(length >> 32); // clear m_X Array.Clear(m_X, 0, m_X.Length); // put bytes from m_ExtraData into m_X int ptr = 0; for (uint i = 0; i < (lswlen & 63); i++) { // byte i goes into word X[i div 4] at pos. 8*(i mod 4) m_X[i >> 2] ^= ((uint)m_ExtraData[ptr++]) << (int)(8 * (i & 3)); } // append the bit m_n == 1 m_X[(lswlen >> 2) & 15] ^= (uint)1 << (int)(8 * (lswlen & 3) + 7); if ((lswlen & 63) > 55) { // length goes to next block Compress(); Array.Clear(m_X, 0, m_X.Length); } // append length in bits m_X[14] = lswlen << 3; m_X[15] = (lswlen >> 29) | (mswlen << 3); Compress(); } #endregion #region RIPEMD Core Functions private uint ROL(uint x, int n) { return (((x) << (n)) | ((x) >> (32-(n)))); } private uint F(uint x, uint y, uint z) { return ((x) ^ (y) ^ (z)) ; } private uint G(uint x, uint y, uint z) { return (((x) & (y)) | (~(x) & (z))); } private uint H(uint x, uint y, uint z) { return (((x) | ~(y)) ^ (z)); } private uint I(uint x, uint y, uint z) { return (((x) & (z)) | ((y) & ~(z))); } private uint J(uint x, uint y, uint z) { return ((x) ^ ((y) | ~(z))); } private void FF(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += F(b, c, d) + x; a = ROL(a, s) + e; c = ROL(c, 10); } private void GG(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += G(b, c, d) + x + 0x5a827999; a = ROL(a, s) + e; c = ROL(c, 10); } private void HH(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += H(b, c, d) + x + 0x6ed9eba1; a = ROL(a, s) + e; c = ROL(c, 10); } private void II(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += I(b, c, d) + x + 0x8f1bbcdc; a = ROL(a, s) + e; c = ROL(c, 10); } private void JJ(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += J(b, c, d) + x + 0xa953fd4e; a = ROL(a, s) + e; c = ROL(c, 10); } private void FFF(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += F(b, c, d) + x; a = ROL(a, s) + e; c = ROL(c, 10); } private void GGG(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += G(b, c, d) + x + 0x7a6d76e9; a = ROL(a, s) + e; c = ROL(c, 10); } private void HHH(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += H(b, c, d) + x + 0x6d703ef3; a = ROL(a, s) + e; c = ROL(c, 10); } private void III(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += I(b, c, d) + x + 0x5c4dd124; a = ROL(a, s) + e; c = ROL(c, 10); } private void JJJ(ref uint a, uint b, ref uint c, uint d, uint e, uint x, int s) { a += J(b, c, d) + x + 0x50a28be6; a = ROL(a, s) + e; c = ROL(c, 10); } #endregion /// /// A buffer that holds the extra data. /// private byte[] m_ExtraData; /// /// The X vectors. /// private uint[] m_X; /// /// The current value of the hash. /// private uint[] m_HashValue; /// /// The nubver of bytes hashed. /// private ulong m_Length; /// /// A boolean that indicates whether the object has been disposed or not. /// private bool m_Disposed; } }