public virtual void Send(byte[] buf, int off, int len) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) byte contentType = 23; if (mInHandshake || mWriteEpoch == mRetransmitEpoch) { contentType = 22; byte b = TlsUtilities.ReadUint8(buf, off); if (b == 20) { DtlsEpoch dtlsEpoch = null; if (mInHandshake) { dtlsEpoch = mPendingEpoch; } else if (mWriteEpoch == mRetransmitEpoch) { dtlsEpoch = mCurrentEpoch; } if (dtlsEpoch == null) { throw new InvalidOperationException(); } byte[] array = new byte[1] { 1 }; SendRecord(20, array, 0, array.Length); mWriteEpoch = dtlsEpoch; } } SendRecord(contentType, buf, off, len); }
public virtual void Send(byte[] buf, int off, int len) { byte contentType = 23; if (this.mInHandshake || this.mWriteEpoch == this.mRetransmitEpoch) { contentType = 22; byte b = TlsUtilities.ReadUint8(buf, off); if (b == 20) { DtlsEpoch dtlsEpoch = null; if (this.mInHandshake) { dtlsEpoch = this.mPendingEpoch; } else if (this.mWriteEpoch == this.mRetransmitEpoch) { dtlsEpoch = this.mCurrentEpoch; } if (dtlsEpoch == null) { throw new InvalidOperationException(); } byte[] array = new byte[] { 1 }; this.SendRecord(20, array, 0, array.Length); this.mWriteEpoch = dtlsEpoch; } } this.SendRecord(contentType, buf, off, len); }
internal virtual void InitPendingEpoch(TlsCipher pendingCipher) { if (this.mPendingEpoch != null) { throw new InvalidOperationException(); } this.mPendingEpoch = new DtlsEpoch(this.mWriteEpoch.Epoch + 1, pendingCipher); }
internal virtual void InitPendingEpoch(TlsCipher pendingCipher) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) if (mPendingEpoch != null) { throw new InvalidOperationException(); } mPendingEpoch = new DtlsEpoch(mWriteEpoch.Epoch + 1, pendingCipher); }
internal virtual void ResetWriteEpoch() { if (this.mRetransmitEpoch != null) { this.mWriteEpoch = this.mRetransmitEpoch; return; } this.mWriteEpoch = this.mCurrentEpoch; }
internal virtual void ResetWriteEpoch() { if (mRetransmitEpoch != null) { mWriteEpoch = mRetransmitEpoch; } else { mWriteEpoch = mCurrentEpoch; } }
internal DtlsRecordLayer(DatagramTransport transport, TlsContext context, TlsPeer peer, byte contentType) { mTransport = transport; mContext = context; mPeer = peer; mInHandshake = true; mCurrentEpoch = new DtlsEpoch(0, new TlsNullCipher(context)); mPendingEpoch = null; mReadEpoch = mCurrentEpoch; mWriteEpoch = mCurrentEpoch; SetPlaintextLimit(16384); }
internal DtlsRecordLayer(DatagramTransport transport, TlsContext context, TlsPeer peer, byte contentType) { this.mTransport = transport; this.mContext = context; this.mPeer = peer; this.mInHandshake = true; this.mCurrentEpoch = new DtlsEpoch(0, new TlsNullCipher(context)); this.mPendingEpoch = null; this.mReadEpoch = mCurrentEpoch; this.mWriteEpoch = mCurrentEpoch; SetPlaintextLimit(MAX_FRAGMENT_LENGTH); }
internal virtual void HandshakeSuccessful(DtlsHandshakeRetransmit retransmit) { if (this.mReadEpoch == this.mCurrentEpoch || this.mWriteEpoch == this.mCurrentEpoch) { throw new InvalidOperationException(); } if (retransmit != null) { this.mRetransmit = retransmit; this.mRetransmitEpoch = this.mCurrentEpoch; this.mRetransmitExpiry = DateTimeUtilities.CurrentUnixMs() + 240000L; } this.mInHandshake = false; this.mCurrentEpoch = this.mPendingEpoch; this.mPendingEpoch = null; }
internal virtual void HandshakeSuccessful(DtlsHandshakeRetransmit retransmit) { //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (mReadEpoch == mCurrentEpoch || mWriteEpoch == mCurrentEpoch) { throw new InvalidOperationException(); } if (retransmit != null) { mRetransmit = retransmit; mRetransmitEpoch = mCurrentEpoch; mRetransmitExpiry = DateTimeUtilities.CurrentUnixMs() + 240000; } mInHandshake = false; mCurrentEpoch = mPendingEpoch; mPendingEpoch = null; }
internal virtual void HandshakeSuccessful(DtlsHandshakeRetransmit retransmit) { if (mReadEpoch == mCurrentEpoch || mWriteEpoch == mCurrentEpoch) { // TODO throw new InvalidOperationException(); } if (retransmit != null) { this.mRetransmit = retransmit; this.mRetransmitEpoch = mCurrentEpoch; this.mRetransmitTimeout = new Timeout(RETRANSMIT_TIMEOUT); } this.mInHandshake = false; this.mCurrentEpoch = mPendingEpoch; this.mPendingEpoch = null; }
/// <exception cref="IOException"/> public virtual void Send(byte[] buf, int off, int len) { byte contentType = ContentType.application_data; if (this.mInHandshake || this.mWriteEpoch == this.mRetransmitEpoch) { contentType = ContentType.handshake; byte handshakeType = TlsUtilities.ReadUint8(buf, off); if (handshakeType == HandshakeType.finished) { DtlsEpoch nextEpoch = null; if (this.mInHandshake) { nextEpoch = mPendingEpoch; } else if (this.mWriteEpoch == this.mRetransmitEpoch) { nextEpoch = mCurrentEpoch; } if (nextEpoch == null) { // TODO throw new InvalidOperationException(); } // Implicitly send change_cipher_spec and change to pending cipher state // TODO Send change_cipher_spec and finished records in single datagram? byte[] data = new byte[] { 1 }; SendRecord(ContentType.change_cipher_spec, data, 0, data.Length); mWriteEpoch = nextEpoch; } } SendRecord(contentType, buf, off, len); }
public virtual int Receive(byte[] buf, int off, int len, int waitMillis) { long currentTimeMillis = DateTimeUtilities.CurrentUnixMs(); Timeout timeout = Timeout.ForWaitMillis(waitMillis, currentTimeMillis); byte[] record = null; while (waitMillis >= 0) { if (mRetransmitTimeout != null && mRetransmitTimeout.RemainingMillis(currentTimeMillis) < 1) { mRetransmit = null; mRetransmitEpoch = null; mRetransmitTimeout = null; } int receiveLimit = mTransport.GetReceiveLimit(); if (record == null || record.Length < receiveLimit) { record = new byte[receiveLimit]; } int received = ReceiveRecord(record, 0, receiveLimit, waitMillis); int processed = ProcessRecord(received, record, buf, off); if (processed >= 0) { return(processed); } currentTimeMillis = DateTimeUtilities.CurrentUnixMs(); waitMillis = Timeout.GetWaitMillis(timeout, currentTimeMillis); } return(-1); }
public virtual int Receive(byte[] buf, int off, int len, int waitMillis) { //IL_02c8: Expected O, but got Unknown byte[] array = null; while (true) { int num = Math.Min(len, GetReceiveLimit()) + 13; if (array == null || array.Length < num) { array = new byte[num]; } try { if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry) { mRetransmit = null; mRetransmitEpoch = null; } int num2 = ReceiveRecord(array, 0, num, waitMillis); if (num2 < 0) { return(num2); } if (num2 < 13) { continue; } int num3 = TlsUtilities.ReadUint16(array, 11); if (num2 != num3 + 13) { continue; } byte b = TlsUtilities.ReadUint8(array, 0); switch (b) { case 20: case 21: case 22: case 23: case 24: { int num4 = TlsUtilities.ReadUint16(array, 3); DtlsEpoch dtlsEpoch = null; if (num4 == mReadEpoch.Epoch) { dtlsEpoch = mReadEpoch; } else if (b == 22 && mRetransmitEpoch != null && num4 == mRetransmitEpoch.Epoch) { dtlsEpoch = mRetransmitEpoch; } if (dtlsEpoch == null) { break; } long num5 = TlsUtilities.ReadUint48(array, 5); if (dtlsEpoch.ReplayWindow.ShouldDiscard(num5)) { break; } ProtocolVersion protocolVersion = TlsUtilities.ReadVersion(array, 1); if (!protocolVersion.IsDtls || (mReadVersion != null && !mReadVersion.Equals(protocolVersion))) { break; } byte[] array2 = dtlsEpoch.Cipher.DecodeCiphertext(GetMacSequenceNumber(dtlsEpoch.Epoch, num5), b, array, 13, num2 - 13); dtlsEpoch.ReplayWindow.ReportAuthenticated(num5); if (array2.Length > mPlaintextLimit) { break; } if (mReadVersion == null) { mReadVersion = protocolVersion; } switch (b) { case 21: if (array2.Length == 2) { byte b2 = array2[0]; byte b3 = array2[1]; mPeer.NotifyAlertReceived(b2, b3); if (b2 == 2) { Fail(b3); throw new TlsFatalAlert(b3); } if (b3 == 0) { CloseTransport(); } } goto end_IL_0022; case 23: if (!mInHandshake) { break; } goto end_IL_0022; case 20: { for (int i = 0; i < array2.Length; i++) { byte b4 = TlsUtilities.ReadUint8(array2, i); if (b4 == 1 && mPendingEpoch != null) { mReadEpoch = mPendingEpoch; } } goto end_IL_0022; } case 22: if (mInHandshake) { break; } if (mRetransmit != null) { mRetransmit.ReceivedHandshakeRecord(num4, array2, 0, array2.Length); } goto end_IL_0022; case 24: goto end_IL_0022; } if (!mInHandshake && mRetransmit != null) { mRetransmit = null; mRetransmitEpoch = null; } global::System.Array.Copy((global::System.Array)array2, 0, (global::System.Array)buf, off, array2.Length); return(array2.Length); } } end_IL_0022 :; } catch (IOException val) { IOException val2 = val; throw val2; } } }
public virtual int Receive(byte[] buf, int off, int len, int waitMillis) { byte[] record = null; for (;;) { int receiveLimit = System.Math.Min(len, GetReceiveLimit()) + RECORD_HEADER_LENGTH; if (record == null || record.Length < receiveLimit) { record = new byte[receiveLimit]; } try { if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry) { mRetransmit = null; mRetransmitEpoch = null; } int received = ReceiveRecord(record, 0, receiveLimit, waitMillis); if (received < 0) { return(received); } if (received < RECORD_HEADER_LENGTH) { continue; } int length = TlsUtilities.ReadUint16(record, 11); if (received != (length + RECORD_HEADER_LENGTH)) { continue; } byte type = TlsUtilities.ReadUint8(record, 0); // TODO Support user-specified custom protocols? switch (type) { case ContentType.alert: case ContentType.application_data: case ContentType.change_cipher_spec: case ContentType.handshake: case ContentType.heartbeat: break; default: // TODO Exception? continue; } int epoch = TlsUtilities.ReadUint16(record, 3); DtlsEpoch recordEpoch = null; if (epoch == mReadEpoch.Epoch) { recordEpoch = mReadEpoch; } else if (type == ContentType.handshake && mRetransmitEpoch != null && epoch == mRetransmitEpoch.Epoch) { recordEpoch = mRetransmitEpoch; } if (recordEpoch == null) { continue; } long seq = TlsUtilities.ReadUint48(record, 5); if (recordEpoch.ReplayWindow.ShouldDiscard(seq)) { continue; } ProtocolVersion version = TlsUtilities.ReadVersion(record, 1); if (!version.IsDtls) { continue; } if (mReadVersion != null && !mReadVersion.Equals(version)) { continue; } byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext( GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH, received - RECORD_HEADER_LENGTH); recordEpoch.ReplayWindow.ReportAuthenticated(seq); if (plaintext.Length > this.mPlaintextLimit) { continue; } if (mReadVersion == null) { mReadVersion = version; } switch (type) { case ContentType.alert: { if (plaintext.Length == 2) { byte alertLevel = plaintext[0]; byte alertDescription = plaintext[1]; mPeer.NotifyAlertReceived(alertLevel, alertDescription); if (alertLevel == AlertLevel.fatal) { Failed(); throw new TlsFatalAlert(alertDescription); } // TODO Can close_notify be a fatal alert? if (alertDescription == AlertDescription.close_notify) { CloseTransport(); } } continue; } case ContentType.application_data: { if (mInHandshake) { // TODO Consider buffering application data for new epoch that arrives // out-of-order with the Finished message continue; } break; } case ContentType.change_cipher_spec: { // Implicitly receive change_cipher_spec and change to pending cipher state for (int i = 0; i < plaintext.Length; ++i) { byte message = TlsUtilities.ReadUint8(plaintext, i); if (message != ChangeCipherSpec.change_cipher_spec) { continue; } if (mPendingEpoch != null) { mReadEpoch = mPendingEpoch; } } continue; } case ContentType.handshake: { if (!mInHandshake) { if (mRetransmit != null) { mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length); } // TODO Consider support for HelloRequest continue; } break; } case ContentType.heartbeat: { // TODO[RFC 6520] continue; } } /* * NOTE: If we receive any non-handshake data in the new epoch implies the peer has * received our final flight. */ if (!mInHandshake && mRetransmit != null) { this.mRetransmit = null; this.mRetransmitEpoch = null; } Array.Copy(plaintext, 0, buf, off, plaintext.Length); return(plaintext.Length); } catch (IOException e) { // NOTE: Assume this is a timeout for the moment throw e; } } }
internal virtual void HandshakeSuccessful(DtlsHandshakeRetransmit retransmit) { if (mReadEpoch == mCurrentEpoch || mWriteEpoch == mCurrentEpoch) { // TODO throw new InvalidOperationException(); } if (retransmit != null) { this.mRetransmit = retransmit; this.mRetransmitEpoch = mCurrentEpoch; this.mRetransmitExpiry = DateTimeUtilities.CurrentUnixMs() + RETRANSMIT_TIMEOUT; } this.mInHandshake = false; this.mCurrentEpoch = mPendingEpoch; this.mPendingEpoch = null; }
public virtual int Receive(byte[] buf, int off, int len, int waitMillis) { byte[] array = null; int result; while (true) { int num = Math.Min(len, this.GetReceiveLimit()) + 13; if (array == null || array.Length < num) { array = new byte[num]; } try { if (this.mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > this.mRetransmitExpiry) { this.mRetransmit = null; this.mRetransmitEpoch = null; } int num2 = this.ReceiveRecord(array, 0, num, waitMillis); if (num2 < 0) { result = num2; } else { if (num2 < 13) { continue; } int num3 = TlsUtilities.ReadUint16(array, 11); if (num2 != num3 + 13) { continue; } byte b = TlsUtilities.ReadUint8(array, 0); switch (b) { case 20: case 21: case 22: case 23: case 24: { int num4 = TlsUtilities.ReadUint16(array, 3); DtlsEpoch dtlsEpoch = null; if (num4 == this.mReadEpoch.Epoch) { dtlsEpoch = this.mReadEpoch; } else if (b == 22 && this.mRetransmitEpoch != null && num4 == this.mRetransmitEpoch.Epoch) { dtlsEpoch = this.mRetransmitEpoch; } if (dtlsEpoch == null) { continue; } long num5 = TlsUtilities.ReadUint48(array, 5); if (dtlsEpoch.ReplayWindow.ShouldDiscard(num5)) { continue; } ProtocolVersion other = TlsUtilities.ReadVersion(array, 1); if (this.mDiscoveredPeerVersion != null && !this.mDiscoveredPeerVersion.Equals(other)) { continue; } byte[] array2 = dtlsEpoch.Cipher.DecodeCiphertext(DtlsRecordLayer.GetMacSequenceNumber(dtlsEpoch.Epoch, num5), b, array, 13, num2 - 13); dtlsEpoch.ReplayWindow.ReportAuthenticated(num5); if (array2.Length > this.mPlaintextLimit) { continue; } if (this.mDiscoveredPeerVersion == null) { this.mDiscoveredPeerVersion = other; } switch (b) { case 20: for (int i = 0; i < array2.Length; i++) { byte b2 = TlsUtilities.ReadUint8(array2, i); if (b2 == 1 && this.mPendingEpoch != null) { this.mReadEpoch = this.mPendingEpoch; } } continue; case 21: if (array2.Length == 2) { byte b3 = array2[0]; byte b4 = array2[1]; this.mPeer.NotifyAlertReceived(b3, b4); if (b3 == 2) { this.Fail(b4); throw new TlsFatalAlert(b4); } if (b4 == 0) { this.CloseTransport(); } } continue; case 22: if (!this.mInHandshake) { if (this.mRetransmit != null) { this.mRetransmit.ReceivedHandshakeRecord(num4, array2, 0, array2.Length); } continue; } break; case 23: if (this.mInHandshake) { continue; } break; case 24: continue; } if (!this.mInHandshake && this.mRetransmit != null) { this.mRetransmit = null; this.mRetransmitEpoch = null; } Array.Copy(array2, 0, buf, off, array2.Length); result = array2.Length; break; } default: continue; } } } catch (IOException ex) { throw ex; } break; } return(result); }
public virtual int Receive(byte[] buf, int off, int len, int waitMillis) { byte[] record = null; for (;;) { int receiveLimit = System.Math.Min(len, GetReceiveLimit()) + RECORD_HEADER_LENGTH; if (record == null || record.Length < receiveLimit) { record = new byte[receiveLimit]; } try { if (mRetransmit != null && DateTimeUtilities.CurrentUnixMs() > mRetransmitExpiry) { mRetransmit = null; mRetransmitEpoch = null; } int received = ReceiveRecord(record, 0, receiveLimit, waitMillis); if (received < 0) { return received; } if (received < RECORD_HEADER_LENGTH) { continue; } int length = TlsUtilities.ReadUint16(record, 11); if (received != (length + RECORD_HEADER_LENGTH)) { continue; } byte type = TlsUtilities.ReadUint8(record, 0); // TODO Support user-specified custom protocols? switch (type) { case ContentType.alert: case ContentType.application_data: case ContentType.change_cipher_spec: case ContentType.handshake: case ContentType.heartbeat: break; default: // TODO Exception? continue; } int epoch = TlsUtilities.ReadUint16(record, 3); DtlsEpoch recordEpoch = null; if (epoch == mReadEpoch.Epoch) { recordEpoch = mReadEpoch; } else if (type == ContentType.handshake && mRetransmitEpoch != null && epoch == mRetransmitEpoch.Epoch) { recordEpoch = mRetransmitEpoch; } if (recordEpoch == null) { continue; } long seq = TlsUtilities.ReadUint48(record, 5); if (recordEpoch.ReplayWindow.ShouldDiscard(seq)) { continue; } ProtocolVersion version = TlsUtilities.ReadVersion(record, 1); if (!version.IsDtls) { continue; } if (mReadVersion != null && !mReadVersion.Equals(version)) { continue; } byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext( GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH, received - RECORD_HEADER_LENGTH); recordEpoch.ReplayWindow.ReportAuthenticated(seq); if (plaintext.Length > this.mPlaintextLimit) { continue; } if (mReadVersion == null) { mReadVersion = version; } switch (type) { case ContentType.alert: { if (plaintext.Length == 2) { byte alertLevel = plaintext[0]; byte alertDescription = plaintext[1]; mPeer.NotifyAlertReceived(alertLevel, alertDescription); if (alertLevel == AlertLevel.fatal) { Failed(); throw new TlsFatalAlert(alertDescription); } // TODO Can close_notify be a fatal alert? if (alertDescription == AlertDescription.close_notify) { CloseTransport(); } } continue; } case ContentType.application_data: { if (mInHandshake) { // TODO Consider buffering application data for new epoch that arrives // out-of-order with the Finished message continue; } break; } case ContentType.change_cipher_spec: { // Implicitly receive change_cipher_spec and change to pending cipher state for (int i = 0; i < plaintext.Length; ++i) { byte message = TlsUtilities.ReadUint8(plaintext, i); if (message != ChangeCipherSpec.change_cipher_spec) { continue; } if (mPendingEpoch != null) { mReadEpoch = mPendingEpoch; } } continue; } case ContentType.handshake: { if (!mInHandshake) { if (mRetransmit != null) { mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length); } // TODO Consider support for HelloRequest continue; } break; } case ContentType.heartbeat: { // TODO[RFC 6520] continue; } } /* * NOTE: If we receive any non-handshake data in the new epoch implies the peer has * received our final flight. */ if (!mInHandshake && mRetransmit != null) { this.mRetransmit = null; this.mRetransmitEpoch = null; } Array.Copy(plaintext, 0, buf, off, plaintext.Length); return plaintext.Length; } catch (IOException e) { // NOTE: Assume this is a timeout for the moment throw e; } } }
private int ProcessRecord(int received, byte[] record, byte[] buf, int off) { // NOTE: received < 0 (timeout) is covered by this first case if (received < RECORD_HEADER_LENGTH) { return(-1); } int length = TlsUtilities.ReadUint16(record, 11); if (received != (length + RECORD_HEADER_LENGTH)) { return(-1); } byte type = TlsUtilities.ReadUint8(record, 0); switch (type) { case ContentType.alert: case ContentType.application_data: case ContentType.change_cipher_spec: case ContentType.handshake: case ContentType.heartbeat: break; default: return(-1); } int epoch = TlsUtilities.ReadUint16(record, 3); DtlsEpoch recordEpoch = null; if (epoch == mReadEpoch.Epoch) { recordEpoch = mReadEpoch; } else if (type == ContentType.handshake && mRetransmitEpoch != null && epoch == mRetransmitEpoch.Epoch) { recordEpoch = mRetransmitEpoch; } if (recordEpoch == null) { return(-1); } long seq = TlsUtilities.ReadUint48(record, 5); if (recordEpoch.ReplayWindow.ShouldDiscard(seq)) { return(-1); } ProtocolVersion version = TlsUtilities.ReadVersion(record, 1); if (!version.IsDtls) { return(-1); } if (mReadVersion != null && !mReadVersion.Equals(version)) { return(-1); } byte[] plaintext = recordEpoch.Cipher.DecodeCiphertext( GetMacSequenceNumber(recordEpoch.Epoch, seq), type, record, RECORD_HEADER_LENGTH, received - RECORD_HEADER_LENGTH); recordEpoch.ReplayWindow.ReportAuthenticated(seq); if (plaintext.Length > this.mPlaintextLimit) { return(-1); } if (mReadVersion == null) { mReadVersion = version; } switch (type) { case ContentType.alert: { if (plaintext.Length == 2) { byte alertLevel = plaintext[0]; byte alertDescription = plaintext[1]; mPeer.NotifyAlertReceived(alertLevel, alertDescription); if (alertLevel == AlertLevel.fatal) { Failed(); throw new TlsFatalAlert(alertDescription); } // TODO Can close_notify be a fatal alert? if (alertDescription == AlertDescription.close_notify) { CloseTransport(); } } return(-1); } case ContentType.application_data: { if (mInHandshake) { // TODO Consider buffering application data for new epoch that arrives // out-of-order with the Finished message return(-1); } break; } case ContentType.change_cipher_spec: { // Implicitly receive change_cipher_spec and change to pending cipher state for (int i = 0; i < plaintext.Length; ++i) { byte message = TlsUtilities.ReadUint8(plaintext, i); if (message != ChangeCipherSpec.change_cipher_spec) { continue; } if (mPendingEpoch != null) { mReadEpoch = mPendingEpoch; } } return(-1); } case ContentType.handshake: { if (!mInHandshake) { if (mRetransmit != null) { mRetransmit.ReceivedHandshakeRecord(epoch, plaintext, 0, plaintext.Length); } // TODO Consider support for HelloRequest return(-1); } break; } case ContentType.heartbeat: { // TODO[RFC 6520] return(-1); } } /* * NOTE: If we receive any non-handshake data in the new epoch implies the peer has * received our final flight. */ if (!mInHandshake && mRetransmit != null) { this.mRetransmit = null; this.mRetransmitEpoch = null; this.mRetransmitTimeout = null; } Array.Copy(plaintext, 0, buf, off, plaintext.Length); return(plaintext.Length); }