| package org.bouncycastle.crypto.tls; |
| |
| import java.io.IOException; |
| |
| import org.bouncycastle.crypto.Digest; |
| import org.bouncycastle.util.Arrays; |
| |
| /** |
| * A NULL CipherSuite with optional MAC |
| */ |
| public class TlsNullCipher |
| implements TlsCipher |
| { |
| protected TlsContext context; |
| |
| protected TlsMac writeMac; |
| protected TlsMac readMac; |
| |
| public TlsNullCipher(TlsContext context) |
| { |
| this.context = context; |
| this.writeMac = null; |
| this.readMac = null; |
| } |
| |
| public TlsNullCipher(TlsContext context, Digest clientWriteDigest, Digest serverWriteDigest) |
| throws IOException |
| { |
| if ((clientWriteDigest == null) != (serverWriteDigest == null)) |
| { |
| throw new TlsFatalAlert(AlertDescription.internal_error); |
| } |
| |
| this.context = context; |
| |
| TlsMac clientWriteMac = null, serverWriteMac = null; |
| |
| if (clientWriteDigest != null) |
| { |
| int key_block_size = clientWriteDigest.getDigestSize() |
| + serverWriteDigest.getDigestSize(); |
| byte[] key_block = TlsUtils.calculateKeyBlock(context, key_block_size); |
| |
| int offset = 0; |
| |
| clientWriteMac = new TlsMac(context, clientWriteDigest, key_block, offset, |
| clientWriteDigest.getDigestSize()); |
| offset += clientWriteDigest.getDigestSize(); |
| |
| serverWriteMac = new TlsMac(context, serverWriteDigest, key_block, offset, |
| serverWriteDigest.getDigestSize()); |
| offset += serverWriteDigest.getDigestSize(); |
| |
| if (offset != key_block_size) |
| { |
| throw new TlsFatalAlert(AlertDescription.internal_error); |
| } |
| } |
| |
| if (context.isServer()) |
| { |
| writeMac = serverWriteMac; |
| readMac = clientWriteMac; |
| } |
| else |
| { |
| writeMac = clientWriteMac; |
| readMac = serverWriteMac; |
| } |
| } |
| |
| public int getPlaintextLimit(int ciphertextLimit) |
| { |
| int result = ciphertextLimit; |
| if (writeMac != null) |
| { |
| result -= writeMac.getSize(); |
| } |
| return result; |
| } |
| |
| public byte[] encodePlaintext(long seqNo, short type, byte[] plaintext, int offset, int len) |
| throws IOException |
| { |
| 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]; |
| System.arraycopy(plaintext, offset, ciphertext, 0, len); |
| System.arraycopy(mac, 0, ciphertext, len, mac.length); |
| return ciphertext; |
| } |
| |
| public byte[] decodeCiphertext(long seqNo, short type, byte[] ciphertext, int offset, int len) |
| throws IOException |
| { |
| if (readMac == null) |
| { |
| return Arrays.copyOfRange(ciphertext, offset, offset + len); |
| } |
| |
| int macSize = readMac.getSize(); |
| 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); |
| } |
| } |