/** * @return <c>true</c> if the keyDigest is compatible with the specified saltData and saltHash */ public bool Validate(byte[] saltData, byte[] saltHash) { Check16Bytes(saltData, "saltData"); Check16Bytes(saltHash, "saltHash"); // validation uses the RC4 for block zero RC4 rc4 = CreateRC4(0); byte[] saltDataPrime = new byte[saltData.Length]; Array.Copy(saltData, saltDataPrime, saltData.Length); rc4.Encrypt(saltDataPrime); byte[] saltHashPrime = new byte[saltHash.Length]; Array.Copy(saltHash, saltHashPrime, saltHash.Length); rc4.Encrypt(saltHashPrime); using (MD5 md5 = new MD5CryptoServiceProvider()) { byte[] finalSaltResult = md5.ComputeHash(saltDataPrime); //if (false) //{ // set true to see a valid saltHash value // byte[] saltHashThatWouldWork = xor(saltHash, xor(saltHashPrime, finalSaltResult)); // Console.WriteLine(HexDump.ToHex(saltHashThatWouldWork)); //} return(Arrays.Equals(saltHashPrime, finalSaltResult)); } }
public void Xor(byte[] buf, int pOffSet, int pLen) { int nLeftInBlock; nLeftInBlock = _nextRC4BlockStart - _streamPos; if (pLen <= nLeftInBlock) { // simple case - this read does not cross key blocks _rc4.Encrypt(buf, pOffSet, pLen); _streamPos += pLen; return; } int offset = pOffSet; int len = pLen; // start by using the rest of the current block if (len > nLeftInBlock) { if (nLeftInBlock > 0) { _rc4.Encrypt(buf, offset, nLeftInBlock); _streamPos += nLeftInBlock; offset += nLeftInBlock; len -= nLeftInBlock; } RekeyForNextBlock(); } // all full blocks following while (len > RC4_REKEYING_INTERVAL) { _rc4.Encrypt(buf, offset, RC4_REKEYING_INTERVAL); _streamPos += RC4_REKEYING_INTERVAL; offset += RC4_REKEYING_INTERVAL; len -= RC4_REKEYING_INTERVAL; RekeyForNextBlock(); } // finish with incomplete block _rc4.Encrypt(buf, offset, len); _streamPos += len; }