protected SslHandshakeStatus ProcessAlert(RecordMessage message)
 {
     if (message.length != 2 || message.fragment.Length != 2)
     {
         throw new SslException(AlertDescription.RecordOverflow, "The alert message is invalid.");
     }
     try {
         AlertLevel       level       = (AlertLevel)message.fragment[0];
         AlertDescription description = (AlertDescription)message.fragment[1];
         if (level == AlertLevel.Fatal)
         {
             throw new SslException(description, "The other side has sent a failure alert.");
         }
         SslHandshakeStatus ret;
         if (description == AlertDescription.CloseNotify)
         {
             if (m_State == HandshakeType.ShuttingDown)                       // true if we've already sent a shutdown notification
             // close connection
             {
                 ret = new SslHandshakeStatus(SslStatus.Close, null);
             }
             else
             {
                 // send a shutdown notifications, and then close the connection
                 ret = new SslHandshakeStatus(SslStatus.Close, GetControlBytes(ControlType.Shutdown));
             }
         }
         else
         {
             ret = new SslHandshakeStatus(SslStatus.OK, null);
         }
         return(ret);
     } catch (SslException t) {
         throw t;
     } catch (Exception e) {
         throw new SslException(e, AlertDescription.InternalError, "There was an internal error.");
     }
 }
Beispiel #2
0
 protected abstract SslHandshakeStatus ProcessChangeCipherSpec(RecordMessage message);
 protected override SslHandshakeStatus ProcessChangeCipherSpec(RecordMessage message)
 {
     if (message.length != 1 || message.fragment[0] != 1)
         throw new SslException(AlertDescription.IllegalParameter, "The ChangeCipherSpec message was invalid.");
     if (m_State == HandshakeType.ServerHelloDone) {
         m_RecordLayer.ChangeRemoteState(null, m_CipherSuite.Decryptor, m_CipherSuite.RemoteHasher);
         return new SslHandshakeStatus(SslStatus.MessageIncomplete, null); // needs a finished message
     } else {
         throw new SslException(AlertDescription.UnexpectedMessage, "ChangeCipherSpec message must be preceded by a ServerHelloDone message.");
     }
 }
 protected abstract SslHandshakeStatus ProcessChangeCipherSpec(RecordMessage message);
 protected SslHandshakeStatus ProcessAlert(RecordMessage message)
 {
     if (message.length != 2 || message.fragment.Length != 2)
         throw new SslException(AlertDescription.RecordOverflow, "The alert message is invalid.");
     try {
         AlertLevel level = (AlertLevel)message.fragment[0];
         AlertDescription description = (AlertDescription)message.fragment[1];
         if (level == AlertLevel.Fatal)
             throw new SslException(description, "The other side has sent a failure alert.");
         SslHandshakeStatus ret;
         if (description == AlertDescription.CloseNotify) {
             if (m_State == HandshakeType.ShuttingDown) { // true if we've already sent a shutdown notification
                 // close connection
                 ret = new SslHandshakeStatus(SslStatus.Close, null);
             } else {
                 // send a shutdown notifications, and then close the connection
                 ret = new SslHandshakeStatus(SslStatus.Close, GetControlBytes(ControlType.Shutdown));
             }
         } else {
             ret = new SslHandshakeStatus(SslStatus.OK, null);
         }
         return ret;
     } catch (SslException t) {
         throw t;
     } catch (Exception e) {
         throw new SslException(e, AlertDescription.InternalError, "There was an internal error.");
     }
 }
 // processes Handshake & ChangeCipherSpec messages
 public SslHandshakeStatus ProcessMessages(RecordMessage message)
 {
     if (message == null)
         throw new ArgumentNullException();
     SslHandshakeStatus ret;
     if (message.contentType == ContentType.ChangeCipherSpec) {
         ret = ProcessChangeCipherSpec(message);
         m_State = HandshakeType.ChangeCipherSpec;
     } else if (message.contentType == ContentType.Handshake) {
         ret = new SslHandshakeStatus();
         // copy the new bytes and the old bytes in one buffer
         MemoryStream ms = new MemoryStream();
         byte[] fullbuffer = new byte[m_IncompleteMessage.Length + message.length];
         Array.Copy(m_IncompleteMessage, 0, fullbuffer, 0, m_IncompleteMessage.Length);
         Array.Copy(message.fragment, 0, fullbuffer, m_IncompleteMessage.Length, message.length);
         // loop through all messages in buffer, if any
         int offset = 0;
         HandshakeMessage hm = GetHandshakeMessage(fullbuffer, offset);
         while(hm != null) {
             offset += hm.fragment.Length + 4;
             SslHandshakeStatus status = ProcessMessage(hm);
             if (status.Message != null) {
                 ms.Write(status.Message, 0, status.Message.Length);
             }
             ret.Status = status.Status;
             // go to next message
             m_State = hm.type;
             hm = GetHandshakeMessage(fullbuffer, offset);
         }
         if (offset > 0) {
             m_IncompleteMessage = new byte[fullbuffer.Length - offset];
             Array.Copy(fullbuffer, offset, m_IncompleteMessage, 0, m_IncompleteMessage.Length);
         } else {
             m_IncompleteMessage = fullbuffer;
         }
         if (ms.Length > 0) {
             ret.Message = ms.ToArray();
         }
         ms.Close();
     } else { // message.contentType == ContentType.Alert
         ret = ProcessAlert(message);
     }
     return ret;
 }
Beispiel #7
0
		public SslRecordStatus ProcessBytes(byte[] buffer, int offset, int size) {
			if (buffer == null)
				throw new ArgumentNullException();
			if (offset < 0 || offset + size > buffer.Length || size <= 0)
				throw new ArgumentException();
			SslRecordStatus ret = new SslRecordStatus();
			ret.Status = SslStatus.MessageIncomplete;
			MemoryStream decrypted = new MemoryStream();
			MemoryStream protocol = new MemoryStream();
			// copy the new bytes and the old bytes in one buffer
			byte[] fullbuffer = new byte[m_IncompleteMessage.Length + size];
			Array.Copy(m_IncompleteMessage, 0, fullbuffer, 0, m_IncompleteMessage.Length);
			Array.Copy(buffer, offset, fullbuffer, m_IncompleteMessage.Length, size);
			// extract all record messages, if any, and process them
			int recordSize = 0;
			int recordLength;
			while(IsRecordMessageComplete(fullbuffer, recordSize)) {
				RecordMessage message = new RecordMessage(fullbuffer, recordSize);
				recordLength = message.length + 5;
				UnwrapMessage(message); // decrypt and verify message
				// process message
				if (message.contentType == ContentType.ApplicationData) {
					if (!m_HandshakeLayer.IsNegotiating()) {
						decrypted.Write(message.fragment, 0, message.fragment.Length);
					} else {
						throw new SslException(AlertDescription.UnexpectedMessage, "The handshake procedure was not completed successfully before application data was received.");
					}
					ret.Status = SslStatus.OK;
				} else { // handshake message or change cipher spec message
					SslHandshakeStatus status = m_HandshakeLayer.ProcessMessages(message);
					if (status.Message != null)
						protocol.Write(status.Message, 0, status.Message.Length);
					ret.Status = status.Status;
				}
				recordSize += recordLength;
			}
			// copy remaining data [incomplete record]
			if (recordSize > 0) {
				m_IncompleteMessage = new byte[fullbuffer.Length - recordSize];
				Array.Copy(fullbuffer, recordSize, m_IncompleteMessage, 0, m_IncompleteMessage.Length);
			} else {
				m_IncompleteMessage = fullbuffer;
			}
			if (decrypted.Length > 0) {
				ret.Decrypted = decrypted.ToArray();
			}
			decrypted.Close();
			if (protocol.Length > 0) {
				ret.Buffer = protocol.ToArray();
			}
			protocol.Close();
			return ret;
		}
Beispiel #8
0
		} //*/
		protected void UnwrapMessage(RecordMessage message) {
			if (message.length != message.fragment.Length)
				throw new SslException(AlertDescription.IllegalParameter, "Message length is invalid.");
			byte[] remoteMac = null, decrypted = null, localMac = null;
			bool cipherError = false;
			// decrypt and verify the message
			if (m_BulkDecryption != null) {
				if (message.length <= m_RemoteHasher.HashSize / 8)
					throw new SslException(AlertDescription.DecodeError, "Message is too small.");
				if (message.length % m_BulkDecryption.OutputBlockSize != 0)
					throw new SslException(AlertDescription.DecryptError, "Message length is invalid.");
				// decrypt the message
				if (m_BulkDecryption.OutputBlockSize == 1) { // is stream cipher?
					decrypted = new byte[message.length];
					m_BulkDecryption.TransformBlock(message.fragment, 0, message.length, decrypted, 0);
					remoteMac = new byte[m_RemoteHasher.HashSize / 8];
					Array.Copy(decrypted, message.length - remoteMac.Length, remoteMac, 0, remoteMac.Length);
					message.fragment = new byte[decrypted.Length - remoteMac.Length];
					Array.Copy(decrypted, 0, message.fragment, 0, message.fragment.Length);
					message.length = (ushort)message.fragment.Length;
				} else { // cipher is block cipher
					decrypted = new byte[message.fragment.Length];
					m_BulkDecryption.TransformBlock(message.fragment, 0, decrypted.Length, decrypted, 0);
					byte padding = decrypted[decrypted.Length - 1];
					if (message.length < padding + m_RemoteHasher.HashSize / 8 + 1) {
						cipherError = true;
						remoteMac = new byte[m_RemoteHasher.HashSize / 8];
					} else {
						int realSize = (message.length - padding) - 1;
						remoteMac = new byte[m_RemoteHasher.HashSize / 8];
						Array.Copy(decrypted, realSize - remoteMac.Length, remoteMac, 0, remoteMac.Length);
						message.fragment = new byte[realSize - remoteMac.Length];
						Array.Copy(decrypted, 0, message.fragment, 0, message.fragment.Length);
						message.length = (ushort)message.fragment.Length;
						if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1) {
							// check padding
							for(int i = realSize; i < decrypted.Length; i++) {
								if (decrypted[i] != padding) {
									cipherError = true;
								}
							}
						}
					}
				}
				// calculate the MAC
				localMac = GetULongBytes(m_InputSequenceNumber);
				m_RemoteHasher.Initialize();
				m_RemoteHasher.TransformBlock(localMac, 0, localMac.Length, localMac, 0);	// seq_num + ..
				localMac = message.ToBytes();
				if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1) {
					m_RemoteHasher.TransformFinalBlock(localMac, 0, localMac.Length);		// .. + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment
				} else if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Ssl3) {
					m_RemoteHasher.TransformBlock(localMac, 0, 1, localMac, 0); // type
					m_RemoteHasher.TransformFinalBlock(localMac, 3, localMac.Length - 3); // length + fragment
				} else {
					throw new NotSupportedException("Only SSL3 and TLS1 are supported");
				}
				localMac = m_RemoteHasher.Hash;
				// compare MACs
				for(int i = 0; i < remoteMac.Length; i++) {
					if (remoteMac[i] != localMac[i]) {
						cipherError = true;
					}
				}
				// throw cipher error, if necessary
				if (cipherError)
					throw new SslException(AlertDescription.BadRecordMac, "An error occurred during the decryption and verification process.");
			}
			// decompress the message
			if (m_RemoteCompressor != null) {
				message.fragment = m_RemoteCompressor.Decompress(message.fragment);
				message.length = (ushort)message.fragment.Length;
			}
			// final adjustments
			message.messageType = MessageType.PlainText;
			m_InputSequenceNumber++;
		}
Beispiel #9
0
		protected void WrapMessage(RecordMessage message) {
			if (message.length != message.fragment.Length)
				throw new SslException(AlertDescription.IllegalParameter, "Message length is invalid.");
			byte[] mac = null;
			try {
				// compress the message
				if (m_LocalCompressor != null) {
					message.fragment = m_LocalCompressor.Compress(message.fragment);
					message.length = (ushort)message.fragment.Length;
				}
				// encrypt the message and MAC
				if (m_LocalHasher != null) {
					// calculate the MAC
					mac = GetULongBytes(m_OutputSequenceNumber);
					m_LocalHasher.Initialize();
					m_LocalHasher.TransformBlock(mac, 0, mac.Length, mac, 0);	// seq_num + ..
					mac = message.ToBytes();
					if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1) {
						m_LocalHasher.TransformFinalBlock(mac, 0, mac.Length);		// .. + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment
					} else if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Ssl3) {
						m_LocalHasher.TransformBlock(mac, 0, 1, mac, 0); // type
						m_LocalHasher.TransformFinalBlock(mac, 3, mac.Length - 3); // length + fragment
					} else {
						throw new NotSupportedException("Only SSL3 and TLS1 are supported");
					}
					mac = m_LocalHasher.Hash;
					// encrypt the message
					if (m_BulkEncryption.OutputBlockSize == 1) { // is stream cipher?
						byte[] ret = new byte[message.length + mac.Length];
						m_BulkEncryption.TransformBlock(message.fragment, 0, message.length, ret, 0);
						m_BulkEncryption.TransformBlock(mac, 0, mac.Length, ret, message.length);
						message.fragment = ret;
					} else { // cipher is block cipher
						int obs = m_BulkEncryption.OutputBlockSize;
						byte padding = (byte)((obs - (message.length + mac.Length + 1) % obs) % obs);
						byte[] ret = new byte[message.length + mac.Length + padding + 1];
						Array.Copy(message.fragment, 0, ret, 0, message.length);
						Array.Copy(mac, 0, ret, message.length, mac.Length);
						if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1) {
							for(int i = message.length + mac.Length; i < ret.Length; i++) {
								ret[i] = padding;
							}
						} else {
							byte[] buffer = new byte[ret.Length - message.length - mac.Length];
							m_HandshakeLayer.RNG.GetBytes(buffer);
							Array.Copy(buffer, 0, ret, message.length + mac.Length, buffer.Length);
							ret[ret.Length - 1] = padding;
						}
						m_BulkEncryption.TransformBlock(ret, 0, ret.Length, ret, 0);
						message.fragment = ret;
					}
					message.length = (ushort)message.fragment.Length;
				}
			} catch (Exception e) {
				throw new SslException(e, AlertDescription.InternalError, "An exception occurred");
			}
			// final adjustments
			message.messageType = MessageType.Encrypted;
			m_OutputSequenceNumber++;
		} //*/
Beispiel #10
0
		protected byte[] InternalEncryptBytes(byte[] buffer, int offset, int size, ContentType type) { // only accepts sizes of less than 16Kb; does not do any error checking
			byte[] bytes = new byte[size];
			Array.Copy(buffer, offset, bytes, 0, size);
			RecordMessage message = new RecordMessage(MessageType.PlainText, type, m_HandshakeLayer.GetVersion(), bytes);
			WrapMessage(message);
			return message.ToBytes();
		}
        public SslRecordStatus ProcessBytes(byte[] buffer, int offset, int size)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException();
            }
            if (offset < 0 || offset + size > buffer.Length || size <= 0)
            {
                throw new ArgumentException();
            }
            SslRecordStatus ret = new SslRecordStatus();

            ret.Status = SslStatus.MessageIncomplete;
            MemoryStream decrypted = new MemoryStream();
            MemoryStream protocol  = new MemoryStream();

            // copy the new bytes and the old bytes in one buffer
            byte[] fullbuffer = new byte[m_IncompleteMessage.Length + size];
            Array.Copy(m_IncompleteMessage, 0, fullbuffer, 0, m_IncompleteMessage.Length);
            Array.Copy(buffer, offset, fullbuffer, m_IncompleteMessage.Length, size);
            // extract all record messages, if any, and process them
            int recordSize = 0;
            int recordLength;

            while (IsRecordMessageComplete(fullbuffer, recordSize))
            {
                RecordMessage message = new RecordMessage(fullbuffer, recordSize);
                recordLength = message.length + 5;
                UnwrapMessage(message);                 // decrypt and verify message
                // process message
                if (message.contentType == ContentType.ApplicationData)
                {
                    if (!m_HandshakeLayer.IsNegotiating())
                    {
                        decrypted.Write(message.fragment, 0, message.fragment.Length);
                    }
                    else
                    {
                        throw new SslException(AlertDescription.UnexpectedMessage, "The handshake procedure was not completed successfully before application data was received.");
                    }
                    ret.Status = SslStatus.OK;
                }
                else                     // handshake message or change cipher spec message
                {
                    SslHandshakeStatus status = m_HandshakeLayer.ProcessMessages(message);
                    if (status.Message != null)
                    {
                        protocol.Write(status.Message, 0, status.Message.Length);
                    }
                    ret.Status = status.Status;
                }
                recordSize += recordLength;
            }
            // copy remaining data [incomplete record]
            if (recordSize > 0)
            {
                m_IncompleteMessage = new byte[fullbuffer.Length - recordSize];
                Array.Copy(fullbuffer, recordSize, m_IncompleteMessage, 0, m_IncompleteMessage.Length);
            }
            else
            {
                m_IncompleteMessage = fullbuffer;
            }
            if (decrypted.Length > 0)
            {
                ret.Decrypted = decrypted.ToArray();
            }
            decrypted.Close();
            if (protocol.Length > 0)
            {
                ret.Buffer = protocol.ToArray();
            }
            protocol.Close();
            return(ret);
        }
        }         //*/

        protected void UnwrapMessage(RecordMessage message)
        {
            if (message.length != message.fragment.Length)
            {
                throw new SslException(AlertDescription.IllegalParameter, "Message length is invalid.");
            }
            byte[] remoteMac   = null, decrypted = null, localMac = null;
            bool   cipherError = false;

            // decrypt and verify the message
            if (m_BulkDecryption != null)
            {
                if (message.length <= m_RemoteHasher.HashSize / 8)
                {
                    throw new SslException(AlertDescription.DecodeError, "Message is too small.");
                }
                if (message.length % m_BulkDecryption.OutputBlockSize != 0)
                {
                    throw new SslException(AlertDescription.DecryptError, "Message length is invalid.");
                }
                // decrypt the message
                if (m_BulkDecryption.OutputBlockSize == 1)                   // is stream cipher?
                {
                    decrypted = new byte[message.length];
                    m_BulkDecryption.TransformBlock(message.fragment, 0, message.length, decrypted, 0);
                    remoteMac = new byte[m_RemoteHasher.HashSize / 8];
                    Array.Copy(decrypted, message.length - remoteMac.Length, remoteMac, 0, remoteMac.Length);
                    message.fragment = new byte[decrypted.Length - remoteMac.Length];
                    Array.Copy(decrypted, 0, message.fragment, 0, message.fragment.Length);
                    message.length = (ushort)message.fragment.Length;
                }
                else                     // cipher is block cipher
                {
                    decrypted = new byte[message.fragment.Length];
                    m_BulkDecryption.TransformBlock(message.fragment, 0, decrypted.Length, decrypted, 0);
                    byte padding = decrypted[decrypted.Length - 1];
                    if (message.length < padding + m_RemoteHasher.HashSize / 8 + 1)
                    {
                        cipherError = true;
                        remoteMac   = new byte[m_RemoteHasher.HashSize / 8];
                    }
                    else
                    {
                        int realSize = (message.length - padding) - 1;
                        remoteMac = new byte[m_RemoteHasher.HashSize / 8];
                        Array.Copy(decrypted, realSize - remoteMac.Length, remoteMac, 0, remoteMac.Length);
                        message.fragment = new byte[realSize - remoteMac.Length];
                        Array.Copy(decrypted, 0, message.fragment, 0, message.fragment.Length);
                        message.length = (ushort)message.fragment.Length;
                        if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1)
                        {
                            // check padding
                            for (int i = realSize; i < decrypted.Length; i++)
                            {
                                if (decrypted[i] != padding)
                                {
                                    cipherError = true;
                                }
                            }
                        }
                    }
                }
                // calculate the MAC
                localMac = GetULongBytes(m_InputSequenceNumber);
                m_RemoteHasher.Initialize();
                m_RemoteHasher.TransformBlock(localMac, 0, localMac.Length, localMac, 0);                       // seq_num + ..
                localMac = message.ToBytes();
                if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1)
                {
                    m_RemoteHasher.TransformFinalBlock(localMac, 0, localMac.Length);                                   // .. + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment
                }
                else if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Ssl3)
                {
                    m_RemoteHasher.TransformBlock(localMac, 0, 1, localMac, 0);                     // type
                    m_RemoteHasher.TransformFinalBlock(localMac, 3, localMac.Length - 3);           // length + fragment
                }
                else
                {
                    throw new NotSupportedException("Only SSL3 and TLS1 are supported");
                }
                localMac = m_RemoteHasher.Hash;
                // compare MACs
                for (int i = 0; i < remoteMac.Length; i++)
                {
                    if (remoteMac[i] != localMac[i])
                    {
                        cipherError = true;
                    }
                }
                // throw cipher error, if necessary
                if (cipherError)
                {
                    throw new SslException(AlertDescription.BadRecordMac, "An error occurred during the decryption and verification process.");
                }
            }
            // decompress the message
            if (m_RemoteCompressor != null)
            {
                message.fragment = m_RemoteCompressor.Decompress(message.fragment);
                message.length   = (ushort)message.fragment.Length;
            }
            // final adjustments
            message.messageType = MessageType.PlainText;
            m_InputSequenceNumber++;
        }
 protected void WrapMessage(RecordMessage message)
 {
     if (message.length != message.fragment.Length)
     {
         throw new SslException(AlertDescription.IllegalParameter, "Message length is invalid.");
     }
     byte[] mac = null;
     try {
         // compress the message
         if (m_LocalCompressor != null)
         {
             message.fragment = m_LocalCompressor.Compress(message.fragment);
             message.length   = (ushort)message.fragment.Length;
         }
         // encrypt the message and MAC
         if (m_LocalHasher != null)
         {
             // calculate the MAC
             mac = GetULongBytes(m_OutputSequenceNumber);
             m_LocalHasher.Initialize();
             m_LocalHasher.TransformBlock(mac, 0, mac.Length, mac, 0);                           // seq_num + ..
             mac = message.ToBytes();
             if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1)
             {
                 m_LocalHasher.TransformFinalBlock(mac, 0, mac.Length);                                  // .. + TLSCompressed.type + TLSCompressed.version + TLSCompressed.length + TLSCompressed.fragment
             }
             else if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Ssl3)
             {
                 m_LocalHasher.TransformBlock(mac, 0, 1, mac, 0);                         // type
                 m_LocalHasher.TransformFinalBlock(mac, 3, mac.Length - 3);               // length + fragment
             }
             else
             {
                 throw new NotSupportedException("Only SSL3 and TLS1 are supported");
             }
             mac = m_LocalHasher.Hash;
             // encrypt the message
             if (m_BulkEncryption.OutputBlockSize == 1)                       // is stream cipher?
             {
                 byte[] ret = new byte[message.length + mac.Length];
                 m_BulkEncryption.TransformBlock(message.fragment, 0, message.length, ret, 0);
                 m_BulkEncryption.TransformBlock(mac, 0, mac.Length, ret, message.length);
                 message.fragment = ret;
             }
             else                         // cipher is block cipher
             {
                 int    obs     = m_BulkEncryption.OutputBlockSize;
                 byte   padding = (byte)((obs - (message.length + mac.Length + 1) % obs) % obs);
                 byte[] ret     = new byte[message.length + mac.Length + padding + 1];
                 Array.Copy(message.fragment, 0, ret, 0, message.length);
                 Array.Copy(mac, 0, ret, message.length, mac.Length);
                 if (m_HandshakeLayer.GetProtocol() == SecureProtocol.Tls1)
                 {
                     for (int i = message.length + mac.Length; i < ret.Length; i++)
                     {
                         ret[i] = padding;
                     }
                 }
                 else
                 {
                     byte[] buffer = new byte[ret.Length - message.length - mac.Length];
                     m_HandshakeLayer.RNG.GetBytes(buffer);
                     Array.Copy(buffer, 0, ret, message.length + mac.Length, buffer.Length);
                     ret[ret.Length - 1] = padding;
                 }
                 m_BulkEncryption.TransformBlock(ret, 0, ret.Length, ret, 0);
                 message.fragment = ret;
             }
             message.length = (ushort)message.fragment.Length;
         }
     } catch (Exception e) {
         throw new SslException(e, AlertDescription.InternalError, "An exception occurred");
     }
     // final adjustments
     message.messageType = MessageType.Encrypted;
     m_OutputSequenceNumber++;
 }         //*/