// Transport Security Layer (TLS) // Copyright (c) 2003-2004 Carlos Guzman Alvarez // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Security.Cryptography; namespace Mono.Security.Protocol.Tls { internal class SslHandshakeHash : System.Security.Cryptography.HashAlgorithm { #region Fields private HashAlgorithm md5; private HashAlgorithm sha; private bool hashing; private byte[] secret; private byte[] innerPadMD5; private byte[] outerPadMD5; private byte[] innerPadSHA; private byte[] outerPadSHA; #endregion #region Constructors public SslHandshakeHash(byte[] secret) { // Create md5 and sha1 hashes this.md5 = HashAlgorithm.Create("MD5"); this.sha = HashAlgorithm.Create("SHA1"); // Set HashSizeValue this.HashSizeValue = md5.HashSize + sha.HashSize; // Update secret this.secret = secret; this.Initialize(); } #endregion #region Methods public override void Initialize() { this.md5.Initialize(); this.sha.Initialize(); this.initializePad(); this.hashing = false; } protected override byte[] HashFinal() { if (!this.hashing) { this.hashing = true; } // Finalize the md5 hash this.md5.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0); this.md5.TransformFinalBlock(this.innerPadMD5, 0, this.innerPadMD5.Length); byte[] firstResultMD5 = this.md5.Hash; this.md5.Initialize(); this.md5.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0); this.md5.TransformBlock(this.outerPadMD5, 0, this.outerPadMD5.Length, this.outerPadMD5, 0); this.md5.TransformFinalBlock(firstResultMD5, 0, firstResultMD5.Length); // Finalize the sha1 hash this.sha.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0); this.sha.TransformFinalBlock(this.innerPadSHA, 0, this.innerPadSHA.Length); byte[] firstResultSHA = this.sha.Hash; this.sha.Initialize(); this.sha.TransformBlock(this.secret, 0, this.secret.Length, this.secret, 0); this.sha.TransformBlock(this.outerPadSHA, 0, this.outerPadSHA.Length, this.outerPadSHA, 0); this.sha.TransformFinalBlock(firstResultSHA, 0, firstResultSHA.Length); this.Initialize(); byte[] result = new byte[36]; Buffer.BlockCopy(this.md5.Hash, 0, result, 0, 16); Buffer.BlockCopy(this.sha.Hash, 0, result, 16, 20); return result; } protected override void HashCore(byte[] array, int ibStart, int cbSize) { if (!this.hashing) { this.hashing = true; } this.md5.TransformBlock(array, ibStart, cbSize, array, ibStart); this.sha.TransformBlock(array, ibStart, cbSize, array, ibStart); } public byte[] CreateSignature(RSA rsa) { if (rsa == null) { throw new CryptographicUnexpectedOperationException ("missing key"); } RSASslSignatureFormatter f = new RSASslSignatureFormatter(rsa); f.SetHashAlgorithm("MD5SHA1"); return f.CreateSignature(this.Hash); } public bool VerifySignature(RSA rsa, byte[] rgbSignature) { if (rsa == null) { throw new CryptographicUnexpectedOperationException ("missing key"); } if (rgbSignature == null) { throw new ArgumentNullException ("rgbSignature"); } RSASslSignatureDeformatter d = new RSASslSignatureDeformatter(rsa); d.SetHashAlgorithm("MD5SHA1"); return d.VerifySignature(this.Hash, rgbSignature); } #endregion #region Private Methods private void initializePad() { // Fill md5 arrays this.innerPadMD5 = new byte[48]; this.outerPadMD5 = new byte[48]; /* Pad the key for inner and outer digest */ for (int i = 0; i < 48; ++i) { this.innerPadMD5[i] = 0x36; this.outerPadMD5[i] = 0x5C; } // Fill sha arrays this.innerPadSHA = new byte[40]; this.outerPadSHA = new byte[40]; /* Pad the key for inner and outer digest */ for (int i = 0; i < 40; ++i) { this.innerPadSHA[i] = 0x36; this.outerPadSHA[i] = 0x5C; } } #endregion } }