001: package org.bouncycastle.crypto.tls;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.Digest;
005: import org.bouncycastle.crypto.params.KeyParameter;
006: import org.bouncycastle.crypto.params.ParametersWithIV;
007:
008: import java.io.IOException;
009:
010: /**
011: * A generic TLS 1.0 block cipher suite. This can be used for AES or 3DES for
012: * example.
013: */
014: public class TlsBlockCipherCipherSuite extends TlsCipherSuite {
015:
016: private BlockCipher encryptCipher;
017:
018: private BlockCipher decryptCipher;
019:
020: private Digest writeDigest;
021:
022: private Digest readDigest;
023:
024: private int cipherKeySize;
025:
026: private short keyExchange;
027:
028: private TlsMac writeMac;
029:
030: private TlsMac readMac;
031:
032: protected TlsBlockCipherCipherSuite(BlockCipher encrypt,
033: BlockCipher decrypt, Digest writeDigest, Digest readDigest,
034: int cipherKeySize, short keyExchange) {
035: this .encryptCipher = encrypt;
036: this .decryptCipher = decrypt;
037: this .writeDigest = writeDigest;
038: this .readDigest = readDigest;
039: this .cipherKeySize = cipherKeySize;
040: this .keyExchange = keyExchange;
041: }
042:
043: protected void init(byte[] ms, byte[] cr, byte[] sr) {
044: int prfSize = (2 * cipherKeySize)
045: + (2 * writeDigest.getDigestSize())
046: + (2 * encryptCipher.getBlockSize());
047: byte[] key_block = new byte[prfSize];
048: byte[] random = new byte[cr.length + sr.length];
049: System.arraycopy(cr, 0, random, sr.length, cr.length);
050: System.arraycopy(sr, 0, random, 0, sr.length);
051: TlsUtils.PRF(ms, TlsUtils.toByteArray("key expansion"), random,
052: key_block);
053:
054: int offset = 0;
055:
056: // Init MACs
057: writeMac = new TlsMac(writeDigest, key_block, offset,
058: writeDigest.getDigestSize());
059: offset += writeDigest.getDigestSize();
060: readMac = new TlsMac(readDigest, key_block, offset, readDigest
061: .getDigestSize());
062: offset += readDigest.getDigestSize();
063:
064: // Init Ciphers
065: this .initCipher(true, encryptCipher, key_block, cipherKeySize,
066: offset, offset + (cipherKeySize * 2));
067: offset += cipherKeySize;
068: this .initCipher(false, decryptCipher, key_block, cipherKeySize,
069: offset, offset + cipherKeySize
070: + decryptCipher.getBlockSize());
071: }
072:
073: private void initCipher(boolean forEncryption, BlockCipher cipher,
074: byte[] key_block, int key_size, int key_offset,
075: int iv_offset) {
076: KeyParameter key_parameter = new KeyParameter(key_block,
077: key_offset, key_size);
078: ParametersWithIV parameters_with_iv = new ParametersWithIV(
079: key_parameter, key_block, iv_offset, cipher
080: .getBlockSize());
081: cipher.init(forEncryption, parameters_with_iv);
082: }
083:
084: protected byte[] encodePlaintext(short type, byte[] plaintext,
085: int offset, int len) {
086: int blocksize = encryptCipher.getBlockSize();
087: int paddingsize = blocksize
088: - ((len + writeMac.getSize() + 1) % blocksize);
089: int totalsize = len + writeMac.getSize() + paddingsize + 1;
090: byte[] outbuf = new byte[totalsize];
091: System.arraycopy(plaintext, offset, outbuf, 0, len);
092: byte[] mac = writeMac
093: .calculateMac(type, plaintext, offset, len);
094: System.arraycopy(mac, 0, outbuf, len, mac.length);
095: int paddoffset = len + mac.length;
096: for (int i = 0; i <= paddingsize; i++) {
097: outbuf[i + paddoffset] = (byte) paddingsize;
098: }
099: for (int i = 0; i < totalsize; i += blocksize) {
100: encryptCipher.processBlock(outbuf, i, outbuf, i);
101: }
102: return outbuf;
103:
104: }
105:
106: protected byte[] decodeCiphertext(short type, byte[] ciphertext,
107: int offset, int len, TlsProtocolHandler handler)
108: throws IOException {
109: int blocksize = decryptCipher.getBlockSize();
110: boolean decrypterror = false;
111:
112: /*
113: * Decrypt all the ciphertext using the blockcipher
114: */
115: for (int i = 0; i < len; i += blocksize) {
116: decryptCipher.processBlock(ciphertext, i + offset,
117: ciphertext, i + offset);
118: }
119:
120: /*
121: * Check if padding is correct
122: */
123: int paddingsize = ciphertext[offset + len - 1];
124: if (offset + len - 1 - paddingsize < 0) {
125: /*
126: * This would lead to an negativ array index, so this padding
127: * must be incorrect!
128: */
129: decrypterror = true;
130: paddingsize = 0;
131: } else {
132: /*
133: * Now, check all the padding-bytes.
134: */
135: for (int i = 0; i <= paddingsize; i++) {
136: if (ciphertext[offset + len - 1 - i] != paddingsize) {
137: /* Wrong padding */
138: decrypterror = true;
139: }
140: }
141: }
142:
143: /*
144: * We now don't care if padding verification has failed or not,
145: * we will calculate the mac to give an attacker no kind of timing
146: * profile he can use to find out if mac verification failed or
147: * padding verification failed.
148: */
149: int plaintextlength = len - readMac.getSize() - paddingsize - 1;
150: byte[] calculatedMac = readMac.calculateMac(type, ciphertext,
151: offset, plaintextlength);
152:
153: /*
154: * Check all bytes in the mac.
155: */
156: for (int i = 0; i < calculatedMac.length; i++) {
157: if (ciphertext[offset + plaintextlength + i] != calculatedMac[i]) {
158: decrypterror = true;
159: }
160: }
161:
162: /*
163: * Now, it is save to fail.
164: */
165: if (decrypterror) {
166: handler.failWithError(TlsProtocolHandler.AL_fatal,
167: TlsProtocolHandler.AP_bad_record_mac);
168: }
169: byte[] plaintext = new byte[plaintextlength];
170: System.arraycopy(ciphertext, offset, plaintext, 0,
171: plaintextlength);
172: return plaintext;
173:
174: }
175:
176: protected short getKeyExchangeAlgorithm() {
177: return this.keyExchange;
178: }
179:
180: }
|