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 ()); }
void ComputeMasterSecret (DisposeContext d, TlsContext ctx, SecureBuffer preMasterSecret) { // Compute ClientRandom + ServerRandom int clen = ctx.HandshakeParameters.ClientRandom.Size; int slen = ctx.HandshakeParameters.ServerRandom.Size; int rlen = clen + slen; var cs = d.CreateBuffer (rlen); Buffer.BlockCopy (ctx.HandshakeParameters.ClientRandom.Buffer, 0, cs.Buffer, 0, clen); Buffer.BlockCopy (ctx.HandshakeParameters.ServerRandom.Buffer, 0, cs.Buffer, clen, slen); // Server Random + Client Random var sc = d.CreateBuffer (rlen); Buffer.BlockCopy (ctx.HandshakeParameters.ServerRandom.Buffer, 0, sc.Buffer, 0, slen); Buffer.BlockCopy (ctx.HandshakeParameters.ClientRandom.Buffer, 0, sc.Buffer, slen, clen); // Create master secret var crypto = ctx.Session.PendingCrypto; crypto.MasterSecret = crypto.Cipher.PRF.ComputeMasterSecret (preMasterSecret, cs); #if DEBUG_FULL if (ctx.EnableDebugging) { DebugHelper.WriteLine ("CS", cs); DebugHelper.WriteLine ("SC", sc); DebugHelper.WriteLine ("PRE-MASTER", preMasterSecret); DebugHelper.WriteLine ("MASTER SECRET", crypto.MasterSecret.Buffer); } #endif var keyBlock = crypto.Cipher.PRF.ComputeKeyExpansion (d, crypto.MasterSecret, sc, crypto.Cipher.KeyBlockSize); #if DEBUG_FULL if (ctx.EnableDebugging) { DebugHelper.WriteLine ("KEY BLOCK SIZE: {0}", crypto.Cipher.KeyBlockSize); DebugHelper.WriteLine ("KEY BLOCK", keyBlock.Buffer); } #endif crypto.ClientWriteMac = keyBlock.ReadSecureBuffer (crypto.Cipher.HashSize); crypto.ServerWriteMac = keyBlock.ReadSecureBuffer (crypto.Cipher.HashSize); crypto.ClientWriteKey = keyBlock.ReadSecureBuffer (crypto.Cipher.KeyMaterialSize); crypto.ServerWriteKey = keyBlock.ReadSecureBuffer (crypto.Cipher.KeyMaterialSize); if (crypto.Cipher.HasFixedIV) { crypto.ClientWriteIV = keyBlock.ReadSecureBuffer (crypto.Cipher.FixedIvSize); crypto.ServerWriteIV = keyBlock.ReadSecureBuffer (crypto.Cipher.FixedIvSize); #if DEBUG_FULL if (ctx.EnableDebugging) { DebugHelper.WriteLine ("CLIENT IV", crypto.ClientWriteIV.Buffer); DebugHelper.WriteLine ("SERVER IV", crypto.ServerWriteIV.Buffer); } #endif } }
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 int Decrypt(DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output) { var implicitNonce = IsClient ? ServerWriteIV : ClientWriteIV; var writeKey = IsClient ? ServerWriteKey : ClientWriteKey; #if DEBUG_FULL if (Cipher.EnableDebugging) { DebugHelper.WriteLine("FIXED IV", implicitNonce); DebugHelper.WriteLine("WRITE KEY", writeKey); DebugHelper.WriteLine("SEQUENCE: {0}", ReadSequenceNumber); } #endif var length = input.Size - ExplicitNonceSize; var aad = new TlsBuffer(13); aad.Write(ReadSequenceNumber); aad.Write((byte)contentType); aad.Write((short)Protocol); aad.Write((short)(length - MacSize)); #if DEBUG_FULL if (Cipher.EnableDebugging) { DebugHelper.WriteFull("TAG", aad); } #endif var gcm = new GcmBlockCipher(new AesEngine()); var key = new KeyParameter(writeKey.Buffer); var nonce = d.CreateBuffer(ImplicitNonceSize + ExplicitNonceSize); Buffer.BlockCopy(implicitNonce.Buffer, 0, nonce.Buffer, 0, ImplicitNonceSize); Buffer.BlockCopy(input.Buffer, input.Offset, nonce.Buffer, ImplicitNonceSize, ExplicitNonceSize); #if DEBUG_FULL if (Cipher.EnableDebugging) { DebugHelper.WriteLine("NONCE", nonce); } #endif var parameters = new AeadParameters(key, 128, nonce.Buffer, aad.Buffer); gcm.Init(false, parameters); int ret; try { ret = gcm.ProcessBytes(input.Buffer, input.Offset + ExplicitNonceSize, length, output.Buffer, output.Offset); ret += gcm.DoFinal(output.Buffer, output.Offset + ret); } catch (CryptoException ex) { throw new TlsException(AlertDescription.BadRecordMAC, ex.Message); } return(ret); }
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; }
void ComputeMasterSecret(DisposeContext d, TlsContext ctx, SecureBuffer preMasterSecret) { // Compute ClientRandom + ServerRandom int clen = ctx.HandshakeParameters.ClientRandom.Size; int slen = ctx.HandshakeParameters.ServerRandom.Size; int rlen = clen + slen; var cs = d.CreateBuffer(rlen); Buffer.BlockCopy(ctx.HandshakeParameters.ClientRandom.Buffer, 0, cs.Buffer, 0, clen); Buffer.BlockCopy(ctx.HandshakeParameters.ServerRandom.Buffer, 0, cs.Buffer, clen, slen); // Server Random + Client Random var sc = d.CreateBuffer(rlen); Buffer.BlockCopy(ctx.HandshakeParameters.ServerRandom.Buffer, 0, sc.Buffer, 0, slen); Buffer.BlockCopy(ctx.HandshakeParameters.ClientRandom.Buffer, 0, sc.Buffer, slen, clen); // Create master secret var crypto = ctx.Session.PendingCrypto; crypto.MasterSecret = crypto.Cipher.PRF.ComputeMasterSecret(preMasterSecret, cs); #if DEBUG_FULL if (ctx.EnableDebugging) { DebugHelper.WriteLine("CS", cs); DebugHelper.WriteLine("SC", sc); DebugHelper.WriteLine("PRE-MASTER", preMasterSecret); DebugHelper.WriteLine("MASTER SECRET", crypto.MasterSecret.Buffer); } #endif var keyBlock = crypto.Cipher.PRF.ComputeKeyExpansion(d, crypto.MasterSecret, sc, crypto.Cipher.KeyBlockSize); #if DEBUG_FULL if (ctx.EnableDebugging) { DebugHelper.WriteLine("KEY BLOCK SIZE: {0}", crypto.Cipher.KeyBlockSize); DebugHelper.WriteLine("KEY BLOCK", keyBlock.Buffer); } #endif crypto.ClientWriteMac = keyBlock.ReadSecureBuffer(crypto.Cipher.HashSize); crypto.ServerWriteMac = keyBlock.ReadSecureBuffer(crypto.Cipher.HashSize); crypto.ClientWriteKey = keyBlock.ReadSecureBuffer(crypto.Cipher.KeyMaterialSize); crypto.ServerWriteKey = keyBlock.ReadSecureBuffer(crypto.Cipher.KeyMaterialSize); if (crypto.Cipher.HasFixedIV) { crypto.ClientWriteIV = keyBlock.ReadSecureBuffer(crypto.Cipher.FixedIvSize); crypto.ServerWriteIV = keyBlock.ReadSecureBuffer(crypto.Cipher.FixedIvSize); #if DEBUG_FULL if (ctx.EnableDebugging) { DebugHelper.WriteLine("CLIENT IV", crypto.ClientWriteIV.Buffer); DebugHelper.WriteLine("SERVER IV", crypto.ServerWriteIV.Buffer); } #endif } }
protected override int Decrypt (DisposeContext d, ContentType contentType, IBufferOffsetSize input, IBufferOffsetSize output) { var implicitNonce = IsClient ? ServerWriteIV : ClientWriteIV; var writeKey = IsClient ? ServerWriteKey : ClientWriteKey; #if DEBUG_FULL if (Cipher.EnableDebugging) { DebugHelper.WriteLine ("FIXED IV", implicitNonce); DebugHelper.WriteLine ("WRITE KEY", writeKey); DebugHelper.WriteLine ("SEQUENCE: {0}", ReadSequenceNumber); } #endif var length = input.Size - ExplicitNonceSize; var aad = new TlsBuffer (13); aad.Write (ReadSequenceNumber); aad.Write ((byte)contentType); aad.Write ((short)Protocol); aad.Write ((short)(length - MacSize)); #if DEBUG_FULL if (Cipher.EnableDebugging) DebugHelper.WriteFull ("TAG", aad); #endif var gcm = new GcmBlockCipher (new AesEngine ()); var key = new KeyParameter (writeKey.Buffer); var nonce = d.CreateBuffer (ImplicitNonceSize + ExplicitNonceSize); Buffer.BlockCopy (implicitNonce.Buffer, 0, nonce.Buffer, 0, ImplicitNonceSize); Buffer.BlockCopy (input.Buffer, input.Offset, nonce.Buffer, ImplicitNonceSize, ExplicitNonceSize); #if DEBUG_FULL if (Cipher.EnableDebugging) DebugHelper.WriteLine ("NONCE", nonce); #endif var parameters = new AeadParameters (key, 128, nonce.Buffer, aad.Buffer); gcm.Init (false, parameters); int ret; try { ret = gcm.ProcessBytes (input.Buffer, input.Offset + ExplicitNonceSize, length, output.Buffer, output.Offset); ret += gcm.DoFinal (output.Buffer, output.Offset + ret); } catch (CryptoException ex) { throw new TlsException (AlertDescription.BadRecordMAC, ex.Message); } return ret; }