internal void WriteMessage( ContentType type, byte[] message, int offset, int len) { if (type == ContentType.handshake) { UpdateHandshakeData(message, offset, len); } Stream cOut = writeCompression.Compress(buffer); byte[] ciphertext; if (cOut == buffer) { ciphertext = writeCipher.EncodePlaintext(type, message, offset, len); } else { cOut.Write(message, offset, len); cOut.Flush(); ciphertext = writeCipher.EncodePlaintext(type, buffer.GetBuffer(), 0, (int)buffer.Position); buffer.SetLength(0); } byte[] writeMessage = new byte[ciphertext.Length + 5]; TlsUtilities.WriteUint8((byte)type, writeMessage, 0); TlsUtilities.WriteVersion(writeMessage, 1); TlsUtilities.WriteUint16(ciphertext.Length, writeMessage, 3); Array.Copy(ciphertext, 0, writeMessage, 5, ciphertext.Length); outStr.Write(writeMessage, 0, writeMessage.Length); outStr.Flush(); }
public byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len) { byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len); int size = len + mac.Length; byte[] outbuf = new byte[size]; encryptCipher.ProcessBytes(plaintext, offset, len, outbuf, 0); encryptCipher.ProcessBytes(mac, 0, mac.Length, outbuf, len); return outbuf; }
/** * Calculate the mac for some given data. * <p/> * TlsMac will keep track of the sequence number internally. * * @param type The message type of the message. * @param message A byte-buffer containing the message. * @param offset The number of bytes to skip, before the message starts. * @param len The length of the message. * @return A new byte-buffer containing the mac value. */ public virtual byte[] CalculateMac( ContentType type, byte[] message, int offset, int len) { byte[] macHeader = new byte[13]; TlsUtilities.WriteUint64(seqNo++, macHeader, 0); TlsUtilities.WriteUint8((byte)type, macHeader, 8); TlsUtilities.WriteVersion(macHeader, 9); TlsUtilities.WriteUint16(len, macHeader, 11); mac.BlockUpdate(macHeader, 0, macHeader.Length); mac.BlockUpdate(message, offset, len); return MacUtilities.DoFinal(mac); }
public byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len) { byte[] deciphered = new byte[len]; decryptCipher.ProcessBytes(ciphertext, offset, len, deciphered, 0); int plaintextSize = deciphered.Length - readMac.Size; byte[] plainText = CopyData(deciphered, 0, plaintextSize); byte[] receivedMac = CopyData(deciphered, plaintextSize, readMac.Size); byte[] computedMac = readMac.CalculateMac(type, plainText, 0, plainText.Length); if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac)) { throw new TlsFatalAlert(AlertDescription.bad_record_mac); } return plainText; }
internal byte[] DecodeAndVerify( ContentType type, Stream inStr, int len) { byte[] buf = new byte[len]; TlsUtilities.ReadFully(buf, inStr); byte[] decoded = readCipher.DecodeCiphertext(type, buf, 0, buf.Length); Stream cOut = readCompression.Decompress(buffer); if (cOut == buffer) { return decoded; } cOut.Write(decoded, 0, decoded.Length); cOut.Flush(); byte[] contents = buffer.ToArray(); buffer.SetLength(0); return contents; }
public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len) { int blocksize = encryptCipher.GetBlockSize(); // Add a random number of extra blocks worth of padding int minPaddingSize = blocksize - ((len + writeMac.Size + 1) % blocksize); int maxExtraPadBlocks = (255 - minPaddingSize) / blocksize; int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks); int paddingsize = minPaddingSize + (actualExtraPadBlocks * blocksize); int totalsize = len + writeMac.Size + paddingsize + 1; byte[] outbuf = new byte[totalsize]; Array.Copy(plaintext, offset, outbuf, 0, len); byte[] mac = writeMac.CalculateMac(type, plaintext, offset, len); Array.Copy(mac, 0, outbuf, len, mac.Length); int paddoffset = len + mac.Length; for (int i = 0; i <= paddingsize; i++) { outbuf[i + paddoffset] = (byte)paddingsize; } for (int i = 0; i < totalsize; i += blocksize) { encryptCipher.ProcessBlock(outbuf, i, outbuf, i); } return outbuf; }
public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len) { // TODO TLS 1.1 (RFC 4346) introduces an explicit IV int minLength = readMac.Size + 1; int blocksize = decryptCipher.GetBlockSize(); bool decrypterror = false; /* * ciphertext must be at least (macsize + 1) bytes long */ if (len < minLength) { throw new TlsFatalAlert(AlertDescription.decode_error); } /* * ciphertext must be a multiple of blocksize */ if (len % blocksize != 0) { throw new TlsFatalAlert(AlertDescription.decryption_failed); } /* * Decrypt all the ciphertext using the blockcipher */ for (int i = 0; i < len; i += blocksize) { decryptCipher.ProcessBlock(ciphertext, i + offset, ciphertext, i + offset); } /* * Check if padding is correct */ int lastByteOffset = offset + len - 1; byte paddingsizebyte = ciphertext[lastByteOffset]; int paddingsize = paddingsizebyte; int maxPaddingSize = len - minLength; if (paddingsize > maxPaddingSize) { decrypterror = true; paddingsize = 0; } else { /* * Now, check all the padding-bytes (constant-time comparison). */ byte diff = 0; for (int i = lastByteOffset - paddingsize; i < lastByteOffset; ++i) { diff |= (byte)(ciphertext[i] ^ paddingsizebyte); } if (diff != 0) { /* Wrong padding */ decrypterror = true; paddingsize = 0; } } /* * We now don't care if padding verification has failed or not, we will calculate * the mac to give an attacker no kind of timing profile he can use to find out if * mac verification failed or padding verification failed. */ int plaintextlength = len - minLength - paddingsize; byte[] calculatedMac = readMac.CalculateMac(type, ciphertext, offset, plaintextlength); /* * Check all bytes in the mac (constant-time comparison). */ byte[] decryptedMac = new byte[calculatedMac.Length]; Array.Copy(ciphertext, offset + plaintextlength, decryptedMac, 0, calculatedMac.Length); if (!Arrays.ConstantTimeAreEqual(calculatedMac, decryptedMac)) { decrypterror = true; } /* * Now, it is safe to fail. */ if (decrypterror) { throw new TlsFatalAlert(AlertDescription.bad_record_mac); } byte[] plaintext = new byte[plaintextlength]; Array.Copy(ciphertext, offset, plaintext, 0, plaintextlength); return plaintext; }
internal void ProcessData( ContentType protocol, byte[] buf, int offset, int len) { /* * Have a look at the protocol type, and add it to the correct queue. */ switch (protocol) { case ContentType.change_cipher_spec: changeCipherSpecQueue.AddData(buf, offset, len); ProcessChangeCipherSpec(); break; case ContentType.alert: alertQueue.AddData(buf, offset, len); ProcessAlert(); break; case ContentType.handshake: handshakeQueue.AddData(buf, offset, len); ProcessHandshake(); break; case ContentType.application_data: if (!appDataReady) { this.FailWithError(AlertLevel.fatal, AlertDescription.unexpected_message); } applicationDataQueue.AddData(buf, offset, len); ProcessApplicationData(); break; default: /* * Uh, we don't know this protocol. * * RFC2246 defines on page 13, that we should ignore this. */ break; } }
private void SafeWriteMessage(ContentType type, byte[] buf, int offset, int len) { try { rs.WriteMessage(type, buf, offset, len); } catch (TlsFatalAlert e) { if (!this.closed) { this.FailWithError(AlertLevel.fatal, e.AlertDescription); } throw e; } catch (IOException e) { if (!closed) { this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error); } throw e; } catch (Exception e) { if (!closed) { this.FailWithError(AlertLevel.fatal, AlertDescription.internal_error); } throw e; } }
/** * Calculate the mac for some given data. * <p/> * TlsMac will keep track of the sequence number internally. * * @param type The message type of the message. * @param message A byte-buffer containing the message. * @param offset The number of bytes to skip, before the message starts. * @param len The length of the message. * @return A new byte-buffer containing the mac value. */ public virtual byte[] CalculateMac(ContentType type, byte[] message, int offset, int len) { //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion; bool isTls = true; byte[] macHeader = new byte[isTls ? 13 : 11]; TlsUtilities.WriteUint64(seqNo++, macHeader, 0); TlsUtilities.WriteUint8((byte)type, macHeader, 8); if (isTls) { TlsUtilities.WriteVersion(macHeader, 9); } TlsUtilities.WriteUint16(len, macHeader, 11); mac.BlockUpdate(macHeader, 0, macHeader.Length); mac.BlockUpdate(message, offset, len); return MacUtilities.DoFinal(mac); }
public virtual byte[] CalculateMacConstantTime(ContentType type, byte[] message, int offset, int len, int fullLength, byte[] dummyData) { // Actual MAC only calculated on 'len' bytes byte[] result = CalculateMac(type, message, offset, len); //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion; bool isTls = true; // ...but ensure a constant number of complete digest blocks are processed (per 'fullLength') if (isTls) { // TODO Currently all TLS digests use a block size of 64, a suffix (length field) of 8, and padding (1+) int db = 64, ds = 8; int L1 = 13 + fullLength; int L2 = 13 + len; // How many extra full blocks do we need to calculate? int extra = ((L1 + ds) / db) - ((L2 + ds) / db); while (--extra >= 0) { mac.BlockUpdate(dummyData, 0, db); } // One more byte in case the implementation is "lazy" about processing blocks mac.Update(dummyData[0]); mac.Reset(); } return result; }
public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len) { int blockSize = decryptCipher.GetBlockSize(); int macSize = rMac.Size; /* * TODO[TLS 1.1] Explicit IV implies minLen = blockSize + max(blockSize, macSize + 1), * and will need further changes to offset and plen variables below. */ int minLen = System.Math.Max(blockSize, macSize + 1); if (len < minLen) throw new TlsFatalAlert(AlertDescription.decode_error); if (len % blockSize != 0) throw new TlsFatalAlert(AlertDescription.decryption_failed); for (int i = 0; i < len; i += blockSize) { decryptCipher.ProcessBlock(ciphertext, offset + i, ciphertext, offset + i); } int plen = len; // If there's anything wrong with the padding, this will return zero int totalPad = CheckPaddingConstantTime(ciphertext, offset, plen, blockSize, macSize); int macInputLen = plen - totalPad - macSize; byte[] decryptedMac = Arrays.Copy(ciphertext, offset + macInputLen, macSize); byte[] calculatedMac = rMac.CalculateMacConstantTime(type, ciphertext, offset, macInputLen, plen - macSize, randomData); bool badMac = !Arrays.ConstantTimeAreEqual(calculatedMac, decryptedMac); if (badMac || totalPad == 0) throw new TlsFatalAlert(AlertDescription.bad_record_mac); return Arrays.Copy(ciphertext, offset, macInputLen); }
public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len) { int blocksize = encryptCipher.GetBlockSize(); int padding_length = blocksize - 1 - ((len + wMac.Size) % blocksize); //bool isTls = context.ServerVersion.FullVersion >= ProtocolVersion.TLSv10.FullVersion; bool isTls = true; if (isTls) { // Add a random number of extra blocks worth of padding int maxExtraPadBlocks = (255 - padding_length) / blocksize; int actualExtraPadBlocks = ChooseExtraPadBlocks(context.SecureRandom, maxExtraPadBlocks); padding_length += actualExtraPadBlocks * blocksize; } int totalsize = len + wMac.Size + padding_length + 1; byte[] outbuf = new byte[totalsize]; Array.Copy(plaintext, offset, outbuf, 0, len); byte[] mac = wMac.CalculateMac(type, plaintext, offset, len); Array.Copy(mac, 0, outbuf, len, mac.Length); int paddoffset = len + mac.Length; for (int i = 0; i <= padding_length; i++) { outbuf[i + paddoffset] = (byte)padding_length; } for (int i = 0; i < totalsize; i += blocksize) { encryptCipher.ProcessBlock(outbuf, i, outbuf, i); } return outbuf; }
public virtual byte[] DecodeCiphertext(ContentType type, byte[] ciphertext, int offset, int len) { return CopyData(ciphertext, offset, len); }
public virtual byte[] EncodePlaintext(ContentType type, byte[] plaintext, int offset, int len) { return CopyData(plaintext, offset, len); }