public bool IsValid(SecureChannelHandshakeHello hello, byte[] masterKey) { using (MemoryStream mS = new MemoryStream(32)) { hello.WriteTo(mS); mS.Position = 0; BinaryNumber computedHmac = new BinaryNumber((new HMACSHA256(masterKey)).ComputeHash(mS)); return(_hmac.Equals(computedHmac)); } }
public SecureChannelHandshakeAuthentication(SecureChannelHandshakeHello hello, byte[] masterKey) : base(SecureChannelCode.None) { using (MemoryStream mS = new MemoryStream(32)) { hello.WriteTo(mS); mS.Position = 0; _hmac = new BinaryNumber((new HMACSHA256(masterKey)).ComputeHash(mS)); } }
protected byte[] GenerateMasterKey(SecureChannelHandshakeHello clientHello, SecureChannelHandshakeHello serverHello, byte[] preSharedKey, KeyAgreement keyAgreement, byte[] otherPartyPublicKey) { using (MemoryStream mS = new MemoryStream(128)) { clientHello.WriteTo(mS); serverHello.WriteTo(mS); if (preSharedKey == null) { keyAgreement.HmacMessage = mS.ToArray(); } else { keyAgreement.HmacMessage = (new HMACSHA256(preSharedKey)).ComputeHash(mS.ToArray()); } } return(keyAgreement.DeriveKeyMaterial(otherPartyPublicKey)); }
private void ProtocolV4(Stream stream) { WriteBufferedStream bufferedStream = new WriteBufferedStream(stream, 8 * 1024); #region 1. hello handshake //read client hello SecureChannelHandshakeHello clientHello = new SecureChannelHandshakeHello(bufferedStream); //select crypto option _selectedCryptoOption = _supportedOptions & clientHello.CryptoOptions; if (_selectedCryptoOption == SecureChannelCryptoOptionFlags.None) { throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert); } else if ((_selectedCryptoOption & SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256) > 0) { _selectedCryptoOption = SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256; } else if ((_selectedCryptoOption & SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256) > 0) { _selectedCryptoOption = SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256; } else { throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert); } //send server hello SecureChannelHandshakeHello serverHello = new SecureChannelHandshakeHello(BinaryNumber.GenerateRandomNumber256(), _selectedCryptoOption); serverHello.WriteTo(bufferedStream); #endregion #region 2. key exchange SymmetricEncryptionAlgorithm encAlgo; string hashAlgo; KeyAgreement keyAgreement; switch (_selectedCryptoOption) { case SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256: encAlgo = SymmetricEncryptionAlgorithm.Rijndael; hashAlgo = "SHA256"; keyAgreement = new DiffieHellman(DiffieHellmanGroupType.RFC3526, 2048, KeyAgreementKeyDerivationFunction.Hmac, KeyAgreementKeyDerivationHashAlgorithm.SHA256); break; case SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256: encAlgo = SymmetricEncryptionAlgorithm.Rijndael; hashAlgo = "SHA256"; keyAgreement = new TechnitiumLibrary.Security.Cryptography.ECDiffieHellman(256, KeyAgreementKeyDerivationFunction.Hmac, KeyAgreementKeyDerivationHashAlgorithm.SHA256); break; default: throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert); } //send server key exchange data new SecureChannelHandshakeKeyExchange(keyAgreement.GetPublicKey(), _serverCredentials.PrivateKey, hashAlgo).WriteTo(bufferedStream); bufferedStream.Flush(); //read client key exchange data SecureChannelHandshakeKeyExchange clientKeyExchange = new SecureChannelHandshakeKeyExchange(bufferedStream); //generate master key byte[] masterKey = GenerateMasterKey(clientHello, serverHello, _preSharedKey, keyAgreement, clientKeyExchange.PublicKey); //verify master key using HMAC authentication { SecureChannelHandshakeAuthentication clientAuthentication = new SecureChannelHandshakeAuthentication(bufferedStream); if (!clientAuthentication.IsValid(serverHello, masterKey)) { throw new SecureChannelException(SecureChannelCode.ProtocolAuthenticationFailed, _remotePeerEP, _remotePeerCert); } SecureChannelHandshakeAuthentication serverAuthentication = new SecureChannelHandshakeAuthentication(clientHello, masterKey); serverAuthentication.WriteTo(bufferedStream); bufferedStream.Flush(); } //enable channel encryption switch (encAlgo) { case SymmetricEncryptionAlgorithm.Rijndael: //using MD5 for generating AES IV of 128bit block size HashAlgorithm md5Hash = HashAlgorithm.Create("MD5"); byte[] eIV = md5Hash.ComputeHash(serverHello.Nonce.Number); byte[] dIV = md5Hash.ComputeHash(clientHello.Nonce.Number); //create encryption and decryption objects SymmetricCryptoKey encryptionKey = new SymmetricCryptoKey(SymmetricEncryptionAlgorithm.Rijndael, masterKey, eIV, PaddingMode.None); SymmetricCryptoKey decryptionKey = new SymmetricCryptoKey(SymmetricEncryptionAlgorithm.Rijndael, masterKey, dIV, PaddingMode.None); //enable encryption EnableEncryption(stream, encryptionKey, decryptionKey, new HMACSHA256(masterKey), new HMACSHA256(masterKey)); break; default: throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert); } //channel encryption is ON! #endregion #region 3. exchange & verify certificates & signatures if (!IsReNegotiating()) { //read client certificate _remotePeerCert = new SecureChannelHandshakeCertificate(this).Certificate; //verify client certificate try { _remotePeerCert.Verify(_trustedRootCertificates); } catch (Exception ex) { throw new SecureChannelException(SecureChannelCode.InvalidRemoteCertificate, _remotePeerEP, _remotePeerCert, "Invalid remote certificate.", ex); } } //verify key exchange signature switch (_selectedCryptoOption) { case SecureChannelCryptoOptionFlags.DHE2048_RSA_WITH_AES256_CBC_HMAC_SHA256: case SecureChannelCryptoOptionFlags.ECDHE256_RSA_WITH_AES256_CBC_HMAC_SHA256: if (_remotePeerCert.PublicKeyEncryptionAlgorithm != AsymmetricEncryptionAlgorithm.RSA) { throw new SecureChannelException(SecureChannelCode.InvalidRemoteCertificateAlgorithm, _remotePeerEP, _remotePeerCert); } if (!clientKeyExchange.IsSignatureValid(_remotePeerCert, "SHA256")) { throw new SecureChannelException(SecureChannelCode.InvalidRemoteKeyExchangeSignature, _remotePeerEP, _remotePeerCert); } break; default: throw new SecureChannelException(SecureChannelCode.NoMatchingCryptoAvailable, _remotePeerEP, _remotePeerCert); } if ((_manager != null) && !_manager.ProceedConnection(_remotePeerCert)) { throw new SecureChannelException(SecureChannelCode.SecurityManagerDeclinedAccess, _remotePeerEP, _remotePeerCert, "Security manager declined access."); } //send server certificate if (!IsReNegotiating()) { new SecureChannelHandshakeCertificate(_serverCredentials.Certificate).WriteTo(this); this.Flush(); } #endregion }