@Test public void testWriteUnpaddedFinalFrameWithoutTag() throws Exception { ByteArrayOutputStream out = new ByteArrayOutputStream(); StreamEncrypterImpl s = new StreamEncrypterImpl(out, cipher, streamNumber, null, streamHeaderNonce, streamHeaderKey, frameKey); s.writeFrame(payload, payloadLength, 0, true); ByteArrayOutputStream expected = new ByteArrayOutputStream(); expected.write(streamHeaderNonce); expected.write(protocolVersionBytes); expected.write(streamNumberBytes); expected.write(frameKey.getBytes()); expected.write(new byte[MAC_LENGTH]); byte[] expectedFrameHeader = new byte[FRAME_HEADER_LENGTH]; FrameEncoder.encodeHeader(expectedFrameHeader, true, payloadLength, 0); expected.write(expectedFrameHeader); expected.write(payload); expected.write(new byte[MAC_LENGTH]); assertArrayEquals(expected.toByteArray(), out.toByteArray()); }
@Override public void writeFrame(byte[] payload, int payloadLength, int paddingLength, boolean finalFrame) throws IOException { if (payloadLength < 0 || paddingLength < 0) throw new IllegalArgumentException(); if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) throw new IllegalArgumentException(); if (frameNumber < 0) throw new IOException(); if (writeTag) writeTag(); if (writeStreamHeader) writeStreamHeader(); FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength, paddingLength); FrameEncoder.encodeNonce(frameNonce, frameNumber, true); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(frameHeader, 0, FRAME_HEADER_PLAINTEXT_LENGTH, frameCiphertext, 0); if (encrypted != FRAME_HEADER_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } System.arraycopy(payload, 0, framePlaintext, 0, payloadLength); for (int i = 0; i < paddingLength; i++) framePlaintext[payloadLength + i] = 0; FrameEncoder.encodeNonce(frameNonce, frameNumber, false); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(framePlaintext, 0, payloadLength + paddingLength, frameCiphertext, FRAME_HEADER_LENGTH); if (encrypted != payloadLength + paddingLength + MAC_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } out.write(frameCiphertext, 0, FRAME_HEADER_LENGTH + payloadLength + paddingLength + MAC_LENGTH); frameNumber++; }
StreamEncrypterImpl implements StreamEncrypter { @Override public void writeFrame(byte[] payload, int payloadLength, int paddingLength, boolean finalFrame) throws IOException { if (payloadLength < 0 || paddingLength < 0) throw new IllegalArgumentException(); if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) throw new IllegalArgumentException(); if (frameNumber < 0) throw new IOException(); if (writeTag) writeTag(); if (writeStreamHeader) writeStreamHeader(); FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength, paddingLength); FrameEncoder.encodeNonce(frameNonce, frameNumber, true); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(frameHeader, 0, FRAME_HEADER_PLAINTEXT_LENGTH, frameCiphertext, 0); if (encrypted != FRAME_HEADER_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } System.arraycopy(payload, 0, framePlaintext, 0, payloadLength); for (int i = 0; i < paddingLength; i++) framePlaintext[payloadLength + i] = 0; FrameEncoder.encodeNonce(frameNonce, frameNumber, false); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(framePlaintext, 0, payloadLength + paddingLength, frameCiphertext, FRAME_HEADER_LENGTH); if (encrypted != payloadLength + paddingLength + MAC_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } out.write(frameCiphertext, 0, FRAME_HEADER_LENGTH + payloadLength + paddingLength + MAC_LENGTH); frameNumber++; } }
StreamEncrypterImpl implements StreamEncrypter { @Override public void writeFrame(byte[] payload, int payloadLength, int paddingLength, boolean finalFrame) throws IOException { if (payloadLength < 0 || paddingLength < 0) throw new IllegalArgumentException(); if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) throw new IllegalArgumentException(); if (frameNumber < 0) throw new IOException(); if (writeTag) writeTag(); if (writeStreamHeader) writeStreamHeader(); FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength, paddingLength); FrameEncoder.encodeNonce(frameNonce, frameNumber, true); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(frameHeader, 0, FRAME_HEADER_PLAINTEXT_LENGTH, frameCiphertext, 0); if (encrypted != FRAME_HEADER_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } System.arraycopy(payload, 0, framePlaintext, 0, payloadLength); for (int i = 0; i < paddingLength; i++) framePlaintext[payloadLength + i] = 0; FrameEncoder.encodeNonce(frameNonce, frameNumber, false); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(framePlaintext, 0, payloadLength + paddingLength, frameCiphertext, FRAME_HEADER_LENGTH); if (encrypted != payloadLength + paddingLength + MAC_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } out.write(frameCiphertext, 0, FRAME_HEADER_LENGTH + payloadLength + paddingLength + MAC_LENGTH); frameNumber++; } StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
			long streamNumber, @Nullable byte[] tag, byte[] streamHeaderNonce,
			SecretKey streamHeaderKey, SecretKey frameKey); }
StreamEncrypterImpl implements StreamEncrypter { @Override public void writeFrame(byte[] payload, int payloadLength, int paddingLength, boolean finalFrame) throws IOException { if (payloadLength < 0 || paddingLength < 0) throw new IllegalArgumentException(); if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) throw new IllegalArgumentException(); if (frameNumber < 0) throw new IOException(); if (writeTag) writeTag(); if (writeStreamHeader) writeStreamHeader(); FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength, paddingLength); FrameEncoder.encodeNonce(frameNonce, frameNumber, true); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(frameHeader, 0, FRAME_HEADER_PLAINTEXT_LENGTH, frameCiphertext, 0); if (encrypted != FRAME_HEADER_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } System.arraycopy(payload, 0, framePlaintext, 0, payloadLength); for (int i = 0; i < paddingLength; i++) framePlaintext[payloadLength + i] = 0; FrameEncoder.encodeNonce(frameNonce, frameNumber, false); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(framePlaintext, 0, payloadLength + paddingLength, frameCiphertext, FRAME_HEADER_LENGTH); if (encrypted != payloadLength + paddingLength + MAC_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } out.write(frameCiphertext, 0, FRAME_HEADER_LENGTH + payloadLength + paddingLength + MAC_LENGTH); frameNumber++; } StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
			long streamNumber, @Nullable byte[] tag, byte[] streamHeaderNonce,
			SecretKey streamHeaderKey, SecretKey frameKey); @Override void writeFrame(byte[] payload, int payloadLength,
			int paddingLength, boolean finalFrame); @Override void flush(); }
StreamEncrypterImpl implements StreamEncrypter { @Override public void writeFrame(byte[] payload, int payloadLength, int paddingLength, boolean finalFrame) throws IOException { if (payloadLength < 0 || paddingLength < 0) throw new IllegalArgumentException(); if (payloadLength + paddingLength > MAX_PAYLOAD_LENGTH) throw new IllegalArgumentException(); if (frameNumber < 0) throw new IOException(); if (writeTag) writeTag(); if (writeStreamHeader) writeStreamHeader(); FrameEncoder.encodeHeader(frameHeader, finalFrame, payloadLength, paddingLength); FrameEncoder.encodeNonce(frameNonce, frameNumber, true); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(frameHeader, 0, FRAME_HEADER_PLAINTEXT_LENGTH, frameCiphertext, 0); if (encrypted != FRAME_HEADER_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } System.arraycopy(payload, 0, framePlaintext, 0, payloadLength); for (int i = 0; i < paddingLength; i++) framePlaintext[payloadLength + i] = 0; FrameEncoder.encodeNonce(frameNonce, frameNumber, false); try { cipher.init(true, frameKey, frameNonce); int encrypted = cipher.process(framePlaintext, 0, payloadLength + paddingLength, frameCiphertext, FRAME_HEADER_LENGTH); if (encrypted != payloadLength + paddingLength + MAC_LENGTH) throw new RuntimeException(); } catch (GeneralSecurityException badCipher) { throw new RuntimeException(badCipher); } out.write(frameCiphertext, 0, FRAME_HEADER_LENGTH + payloadLength + paddingLength + MAC_LENGTH); frameNumber++; } StreamEncrypterImpl(OutputStream out, AuthenticatedCipher cipher,
			long streamNumber, @Nullable byte[] tag, byte[] streamHeaderNonce,
			SecretKey streamHeaderKey, SecretKey frameKey); @Override void writeFrame(byte[] payload, int payloadLength,
			int paddingLength, boolean finalFrame); @Override void flush();  }