/*
* 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;
}
}