protected SecureBuffer Expand (DisposeContext d, HMac hmac, string label, SecureBuffer seed, int length) { var blockSize = hmac.MacSize; var iterations = (int)(length / blockSize); if ((length % blockSize) > 0) iterations++; var resMacs = d.CreateBuffer (length); var resOff = 0; var tempBuf = d.CreateBuffer (blockSize); var labelBytes = Encoding.ASCII.GetBytes (label); for (int i = 1; i <= iterations; i++) { hmac.Reset (); if (i == 1) { hmac.TransformBlock (labelBytes, 0, labelBytes.Length); hmac.TransformBlock (seed.Buffer, 0, seed.Size); } else { hmac.TransformBlock (tempBuf.Buffer, 0, blockSize); } hmac.TransformFinalBlock (tempBuf.Buffer, 0, blockSize); hmac.Reset (); hmac.TransformBlock (tempBuf.Buffer, 0, blockSize); hmac.TransformBlock (labelBytes, 0, labelBytes.Length); hmac.TransformBlock (seed.Buffer, 0, seed.Size); hmac.TransformFinalBlock (resMacs.Buffer, resOff, Min (length - resOff, blockSize)); resOff += blockSize; } return new SecureBuffer (resMacs.StealBuffer ()); }
static byte[] ComputeRecordMAC (TlsProtocolCode protocol, HMac hmac, ulong seqnum, ContentType contentType, IBufferOffsetSize fragment) { var header = new TlsBuffer (13); header.Write (seqnum); header.Write ((byte)contentType); header.Write ((short)protocol); header.Write ((short)fragment.Size); hmac.Reset (); hmac.TransformBlock (header.Buffer, 0, header.Size); hmac.TransformBlock (fragment.Buffer, fragment.Offset, fragment.Size); return hmac.TransformFinalBlock (); }
static byte[] ComputeRecordMAC(TlsProtocolCode protocol, HMac hmac, ulong seqnum, ContentType contentType, IBufferOffsetSize fragment) { var header = new TlsBuffer(13); header.Write(seqnum); header.Write((byte)contentType); header.Write((short)protocol); header.Write((short)fragment.Size); hmac.Reset(); hmac.TransformBlock(header.Buffer, 0, header.Size); hmac.TransformBlock(fragment.Buffer, fragment.Offset, fragment.Size); return(hmac.TransformFinalBlock()); }
public override void InitializeCipher() { // Create the HMAC algorithm if (IsClient) { ClientHMac = HMac.Create(Cipher.HashAlgorithmType, ClientWriteMac); ServerHMac = HMac.Create(Cipher.HashAlgorithmType, ServerWriteMac); } else { ServerHMac = HMac.Create(Cipher.HashAlgorithmType, ServerWriteMac); ClientHMac = HMac.Create(Cipher.HashAlgorithmType, ClientWriteMac); } }
protected override SecureBuffer PRF(DisposeContext d, SecureBuffer secret, string label, SecureBuffer data, int length) { /* Secret Length calc exmplain from the RFC2246. Section 5 * * S1 and S2 are the two halves of the secret and each is the same * length. S1 is taken from the first half of the secret, S2 from the * second half. Their length is created by rounding up the length of the * overall secret divided by two; thus, if the original secret is an odd * number of bytes long, the last byte of S1 will be the same as the * first byte of S2. */ // split secret in 2 int secretLen = secret.Size >> 1; // rounding up if ((secret.Size & 0x1) == 0x1) { secretLen++; } // Secret 1 var secret1 = d.CreateBuffer(secretLen); Buffer.BlockCopy(secret.Buffer, 0, secret1.Buffer, 0, secretLen); // Secret2 var secret2 = d.CreateBuffer(secretLen); Buffer.BlockCopy(secret.Buffer, (secret.Size - secretLen), secret2.Buffer, 0, secretLen); // Secret 1 processing var p_md5 = d.Add(Expand(d, HMac.Create(HashAlgorithmType.Md5, secret1), label, data, length)); // Secret 2 processing var p_sha = d.Add(Expand(d, HMac.Create(HashAlgorithmType.Sha1, secret2), label, data, length)); // Perfor XOR of both results var masterSecret = new SecureBuffer(length); for (int i = 0; i < length; i++) { masterSecret.Buffer[i] = (byte)(p_md5.Buffer[i] ^ p_sha.Buffer[i]); } return(masterSecret); }
protected override SecureBuffer PRF(DisposeContext d, SecureBuffer secret, string label, SecureBuffer data, int length) { return(Expand(d, HMac.Create(HandshakeHashType, secret), label, data, length)); }
public BlockCipherWithHMac(bool isServer, TlsProtocolCode protocol, CipherSuite cipher) : base(isServer, protocol, cipher) { MacSize = HMac.GetMacSize(Cipher.HashAlgorithmType); }
protected override int Decrypt(DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output) { if ((input.Size % BlockSize) != 0) { return(-1); } if (input.Size < MinExtraEncryptedBytes) { return(-1); } var plen = DecryptRecord(d, input, output); if (plen <= 0) { return(-1); } var padlen = output.Buffer [output.Offset + plen - 1]; #if DEBUG_FULL if (Cipher.EnableDebugging) { DebugHelper.WriteLine("DECRYPT: {0} {1} {2}", input.Size, plen, padlen); DebugHelper.WriteBuffer("DECRYPTED", output.Buffer, output.Offset, plen); } #endif /* * VERY IMPORTANT: * * The Compiler and JIT *** MUST NOT *** optimize the following block of code. * * It is essential that the dummy checks and dummy calls be kept in place. * Also do not put any debugging code into that region as it would mess up with * the timing. * */ #region The following block of code *** MUST NOT *** be optimized in any way if (MacSize + padlen + 1 > plen) { // Invalid padding: plaintext is not long enough. // First run a loop as if there were 256 bytes of padding, with a dummy check. int ok = -1; for (int i = 0; i < 256; i++) { if (output.Buffer [i % output.Size] != padlen) { ok--; } } // Now assume there's no padding, compute the MAC over the entire buffer. var first = new BufferOffsetSize(output.Buffer, output.Offset, plen - MacSize); var invalidMac = ComputeRecordMAC(contentType, first); // Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error. ok += TlsBuffer.ConstantTimeCompare(invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize); return(ok); } else { int ok = 0; var resultLength = plen - padlen - MacSize - 1; for (int i = 0; i < padlen; i++) { if (output.Buffer [output.Offset + resultLength + MacSize + i] != padlen) { ok--; } } var dummyOk = ok; var dummyLen = 256 - padlen - 1; for (int i = 0; i < dummyLen; i++) { if (output.Buffer [i % output.Size] != padlen) { dummyOk--; } } if (ok < 0) { // Now assume there's no padding, compute the MAC over the entire buffer. var first = new BufferOffsetSize(output.Buffer, output.Offset, plen - MacSize); var invalidMac = ComputeRecordMAC(contentType, first); // Constant-time compare - this will always fail, TlsBuffer.ConstantTimeCompare() will return a negative value on error. ok += TlsBuffer.ConstantTimeCompare(invalidMac, 0, invalidMac.Length, output.Buffer, output.Offset + plen - MacSize, MacSize); return(ok); } else { var first = new BufferOffsetSize(output.Buffer, output.Offset, resultLength); var checkMac = ComputeRecordMAC(contentType, first); var L1 = 13 + plen - MacSize; var L2 = 13 + plen - padlen - 1 - MacSize; var additional = ((L1 - 55) / 64) - ((L2 - 55) / 64); if (additional > 0) { var algorithm = HMac.CreateHash(Cipher.HashAlgorithmType); for (int i = 0; i < additional; i++) { algorithm.TransformBlock(input.Buffer, input.Offset, BlockSize, null, 0); } } ok += TlsBuffer.ConstantTimeCompare(checkMac, 0, checkMac.Length, output.Buffer, output.Offset + resultLength, MacSize); if (ok == 0) { ok = resultLength; } return(ok); } } #endregion }