/// <exception cref="IOException"></exception> public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len) { if (readMac == null) { return(Arrays.CopyOfRange(ciphertext, offset, offset + len)); } int macSize = readMac.Size; if (len < macSize) { throw new TlsFatalAlert(AlertDescription.decode_error); } int macInputLen = len - macSize; byte[] receivedMac = Arrays.CopyOfRange(ciphertext, offset + macInputLen, offset + len); byte[] computedMac = readMac.CalculateMac(seqNo, type, ciphertext, offset, macInputLen); if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac)) { throw new TlsFatalAlert(AlertDescription.bad_record_mac); } return(Arrays.CopyOfRange(ciphertext, offset, offset + macInputLen)); }
/// <exception cref="IOException"></exception> protected virtual void CheckMac(long seqNo, byte type, byte[] recBuf, int recStart, int recEnd, byte[] calcBuf, int calcOff, int calcLen) { byte[] receivedMac = Arrays.CopyOfRange(recBuf, recStart, recEnd); byte[] computedMac = readMac.CalculateMac(seqNo, type, calcBuf, calcOff, calcLen); if (!Arrays.ConstantTimeAreEqual(receivedMac, computedMac)) { throw new TlsFatalAlert(AlertDescription.bad_record_mac); } }
/// <exception cref="IOException"></exception> public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len) { if (writeMac == null) { return(Arrays.CopyOfRange(plaintext, offset, offset + len)); } byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len); byte[] ciphertext = new byte[len + mac.Length]; Array.Copy(plaintext, offset, ciphertext, 0, len); Array.Copy(mac, 0, ciphertext, len, mac.Length); return(ciphertext); }
public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len) { /* * draft-josefsson-salsa20-tls-04 2.1 Note that Salsa20 requires a 64-bit nonce. That * nonce is updated on the encryption of every TLS record, and is set to be the 64-bit TLS * record sequence number. In case of DTLS the 64-bit nonce is formed as the concatenation * of the 16-bit epoch with the 48-bit sequence number. */ if (usesNonce) { UpdateIV(encryptCipher, true, seqNo); } byte[] outBuf = new byte[len + writeMac.Size]; encryptCipher.ProcessBytes(plaintext, offset, len, outBuf, 0); byte[] mac = writeMac.CalculateMac(seqNo, type, plaintext, offset, len); encryptCipher.ProcessBytes(mac, 0, mac.Length, outBuf, len); return(outBuf); }
/// <exception cref="IOException"></exception> public virtual byte[] DecodeCiphertext(long seqNo, byte type, byte[] ciphertext, int offset, int len) { int blockSize = decryptCipher.GetBlockSize(); int macSize = mReadMac.Size; int minLen = blockSize; if (encryptThenMac) { minLen += macSize; } else { minLen = System.Math.Max(minLen, macSize + 1); } if (useExplicitIV) { minLen += blockSize; } if (len < minLen) { throw new TlsFatalAlert(AlertDescription.decode_error); } int blocks_length = len; if (encryptThenMac) { blocks_length -= macSize; } if (blocks_length % blockSize != 0) { throw new TlsFatalAlert(AlertDescription.decryption_failed); } if (encryptThenMac) { int end = offset + len; byte[] receivedMac = Arrays.CopyOfRange(ciphertext, end - macSize, end); byte[] calculatedMac = mReadMac.CalculateMac(seqNo, type, ciphertext, offset, len - macSize); bool badMacEtm = !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac); if (badMacEtm) { /* * RFC 7366 3. The MAC SHALL be evaluated before any further processing such as * decryption is performed, and if the MAC verification fails, then processing SHALL * terminate immediately. For TLS, a fatal bad_record_mac MUST be generated [2]. For * DTLS, the record MUST be discarded, and a fatal bad_record_mac MAY be generated * [4]. This immediate response to a bad MAC eliminates any timing channels that may * be available through the use of manipulated packet data. */ throw new TlsFatalAlert(AlertDescription.bad_record_mac); } } if (useExplicitIV) { decryptCipher.Init(false, new ParametersWithIV(null, ciphertext, offset, blockSize)); offset += blockSize; blocks_length -= blockSize; } for (int i = 0; i < blocks_length; i += blockSize) { decryptCipher.ProcessBlock(ciphertext, offset + i, ciphertext, offset + i); } // If there's anything wrong with the padding, this will return zero int totalPad = CheckPaddingConstantTime(ciphertext, offset, blocks_length, blockSize, encryptThenMac ? 0 : macSize); bool badMac = (totalPad == 0); int dec_output_length = blocks_length - totalPad; if (!encryptThenMac) { dec_output_length -= macSize; int macInputLen = dec_output_length; int macOff = offset + macInputLen; byte[] receivedMac = Arrays.CopyOfRange(ciphertext, macOff, macOff + macSize); byte[] calculatedMac = mReadMac.CalculateMacConstantTime(seqNo, type, ciphertext, offset, macInputLen, blocks_length - macSize, randomData); badMac |= !Arrays.ConstantTimeAreEqual(calculatedMac, receivedMac); } if (badMac) { throw new TlsFatalAlert(AlertDescription.bad_record_mac); } return(Arrays.CopyOfRange(ciphertext, offset, offset + dec_output_length)); }
public virtual byte[] EncodePlaintext(long seqNo, byte type, byte[] plaintext, int offset, int len) { int blockSize = encryptCipher.GetBlockSize(); int macSize = mWriteMac.Size; ProtocolVersion version = context.ServerVersion; int enc_input_length = len; if (!encryptThenMac) { enc_input_length += macSize; } int padding_length = blockSize - 1 - (enc_input_length % blockSize); // TODO[DTLS] Consider supporting in DTLS (without exceeding send limit though) if (!version.IsDtls && !version.IsSsl) { // 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 + macSize + padding_length + 1; if (useExplicitIV) { totalSize += blockSize; } byte[] outBuf = new byte[totalSize]; int outOff = 0; if (useExplicitIV) { byte[] explicitIV = new byte[blockSize]; context.NonceRandomGenerator.NextBytes(explicitIV); encryptCipher.Init(true, new ParametersWithIV(null, explicitIV)); Array.Copy(explicitIV, 0, outBuf, outOff, blockSize); outOff += blockSize; } int blocks_start = outOff; Array.Copy(plaintext, offset, outBuf, outOff, len); outOff += len; if (!encryptThenMac) { byte[] mac = mWriteMac.CalculateMac(seqNo, type, plaintext, offset, len); Array.Copy(mac, 0, outBuf, outOff, mac.Length); outOff += mac.Length; } for (int i = 0; i <= padding_length; i++) { outBuf[outOff++] = (byte)padding_length; } for (int i = blocks_start; i < outOff; i += blockSize) { encryptCipher.ProcessBlock(outBuf, i, outBuf, i); } if (encryptThenMac) { byte[] mac = mWriteMac.CalculateMac(seqNo, type, outBuf, 0, outOff); Array.Copy(mac, 0, outBuf, outOff, mac.Length); outOff += mac.Length; } // assert outBuf.length == outOff; return(outBuf); }