001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.BasicAgreement;
004: import org.bouncycastle.crypto.BufferedBlockCipher;
005: import org.bouncycastle.crypto.CipherParameters;
006: import org.bouncycastle.crypto.DerivationFunction;
007: import org.bouncycastle.crypto.InvalidCipherTextException;
008: import org.bouncycastle.crypto.Mac;
009: import org.bouncycastle.crypto.params.IESParameters;
010: import org.bouncycastle.crypto.params.IESWithCipherParameters;
011: import org.bouncycastle.crypto.params.KDFParameters;
012: import org.bouncycastle.crypto.params.KeyParameter;
013:
014: import java.math.BigInteger;
015:
016: /**
017: * support class for constructing intergrated encryption ciphers
018: * for doing basic message exchanges on top of key agreement ciphers
019: */
020: public class IESEngine {
021: BasicAgreement agree;
022: DerivationFunction kdf;
023: Mac mac;
024: BufferedBlockCipher cipher;
025: byte[] macBuf;
026:
027: boolean forEncryption;
028: CipherParameters privParam, pubParam;
029: IESParameters param;
030:
031: /**
032: * set up for use with stream mode, where the key derivation function
033: * is used to provide a stream of bytes to xor with the message.
034: *
035: * @param agree the key agreement used as the basis for the encryption
036: * @param kdf the key derivation function used for byte generation
037: * @param mac the message authentication code generator for the message
038: */
039: public IESEngine(BasicAgreement agree, DerivationFunction kdf,
040: Mac mac) {
041: this .agree = agree;
042: this .kdf = kdf;
043: this .mac = mac;
044: this .macBuf = new byte[mac.getMacSize()];
045: this .cipher = null;
046: }
047:
048: /**
049: * set up for use in conjunction with a block cipher to handle the
050: * message.
051: *
052: * @param agree the key agreement used as the basis for the encryption
053: * @param kdf the key derivation function used for byte generation
054: * @param mac the message authentication code generator for the message
055: * @param cipher the cipher to used for encrypting the message
056: */
057: public IESEngine(BasicAgreement agree, DerivationFunction kdf,
058: Mac mac, BufferedBlockCipher cipher) {
059: this .agree = agree;
060: this .kdf = kdf;
061: this .mac = mac;
062: this .macBuf = new byte[mac.getMacSize()];
063: this .cipher = cipher;
064: }
065:
066: /**
067: * Initialise the encryptor.
068: *
069: * @param forEncryption whether or not this is encryption/decryption.
070: * @param privParam our private key parameters
071: * @param pubParam the recipient's/sender's public key parameters
072: * @param param encoding and derivation parameters.
073: */
074: public void init(boolean forEncryption, CipherParameters privParam,
075: CipherParameters pubParam, CipherParameters param) {
076: this .forEncryption = forEncryption;
077: this .privParam = privParam;
078: this .pubParam = pubParam;
079: this .param = (IESParameters) param;
080: }
081:
082: private byte[] decryptBlock(byte[] in_enc, int inOff, int inLen,
083: byte[] z) throws InvalidCipherTextException {
084: byte[] M = null;
085: KeyParameter macKey = null;
086: KDFParameters kParam = new KDFParameters(z, param
087: .getDerivationV());
088: int macKeySize = param.getMacKeySize();
089:
090: kdf.init(kParam);
091:
092: inLen -= mac.getMacSize();
093:
094: if (cipher == null) // stream mode
095: {
096: byte[] buf = generateKdfBytes(kParam, inLen
097: + (macKeySize / 8));
098:
099: M = new byte[inLen];
100:
101: for (int i = 0; i != inLen; i++) {
102: M[i] = (byte) (in_enc[inOff + i] ^ buf[i]);
103: }
104:
105: macKey = new KeyParameter(buf, inLen, (macKeySize / 8));
106: } else {
107: int cipherKeySize = ((IESWithCipherParameters) param)
108: .getCipherKeySize();
109: byte[] buf = generateKdfBytes(kParam, (cipherKeySize / 8)
110: + (macKeySize / 8));
111:
112: cipher.init(false, new KeyParameter(buf, 0,
113: (cipherKeySize / 8)));
114:
115: byte[] tmp = new byte[cipher.getOutputSize(inLen)];
116:
117: int len = cipher.processBytes(in_enc, inOff, inLen, tmp, 0);
118:
119: len += cipher.doFinal(tmp, len);
120:
121: M = new byte[len];
122:
123: System.arraycopy(tmp, 0, M, 0, len);
124:
125: macKey = new KeyParameter(buf, (cipherKeySize / 8),
126: (macKeySize / 8));
127: }
128:
129: byte[] macIV = param.getEncodingV();
130:
131: mac.init(macKey);
132: mac.update(in_enc, inOff, inLen);
133: mac.update(macIV, 0, macIV.length);
134: mac.doFinal(macBuf, 0);
135:
136: inOff += inLen;
137:
138: for (int t = 0; t < macBuf.length; t++) {
139: if (macBuf[t] != in_enc[inOff + t]) {
140: throw (new InvalidCipherTextException(
141: "Mac codes failed to equal."));
142: }
143: }
144:
145: return M;
146: }
147:
148: private byte[] encryptBlock(byte[] in, int inOff, int inLen,
149: byte[] z) throws InvalidCipherTextException {
150: byte[] C = null;
151: KeyParameter macKey = null;
152: KDFParameters kParam = new KDFParameters(z, param
153: .getDerivationV());
154: int c_text_length = 0;
155: int macKeySize = param.getMacKeySize();
156:
157: if (cipher == null) // stream mode
158: {
159: byte[] buf = generateKdfBytes(kParam, inLen
160: + (macKeySize / 8));
161:
162: C = new byte[inLen + mac.getMacSize()];
163: c_text_length = inLen;
164:
165: for (int i = 0; i != inLen; i++) {
166: C[i] = (byte) (in[inOff + i] ^ buf[i]);
167: }
168:
169: macKey = new KeyParameter(buf, inLen, (macKeySize / 8));
170: } else {
171: int cipherKeySize = ((IESWithCipherParameters) param)
172: .getCipherKeySize();
173: byte[] buf = generateKdfBytes(kParam, (cipherKeySize / 8)
174: + (macKeySize / 8));
175:
176: cipher.init(true, new KeyParameter(buf, 0,
177: (cipherKeySize / 8)));
178:
179: c_text_length = cipher.getOutputSize(inLen);
180:
181: byte[] tmp = new byte[c_text_length];
182:
183: int len = cipher.processBytes(in, inOff, inLen, tmp, 0);
184:
185: len += cipher.doFinal(tmp, len);
186:
187: C = new byte[len + mac.getMacSize()];
188: c_text_length = len;
189:
190: System.arraycopy(tmp, 0, C, 0, len);
191:
192: macKey = new KeyParameter(buf, (cipherKeySize / 8),
193: (macKeySize / 8));
194: }
195:
196: byte[] macIV = param.getEncodingV();
197:
198: mac.init(macKey);
199: mac.update(C, 0, c_text_length);
200: mac.update(macIV, 0, macIV.length);
201: //
202: // return the message and it's MAC
203: //
204: mac.doFinal(C, c_text_length);
205: return C;
206: }
207:
208: private byte[] generateKdfBytes(KDFParameters kParam, int length) {
209: byte[] buf = new byte[length];
210:
211: kdf.init(kParam);
212:
213: kdf.generateBytes(buf, 0, buf.length);
214:
215: return buf;
216: }
217:
218: public byte[] processBlock(byte[] in, int inOff, int inLen)
219: throws InvalidCipherTextException {
220: agree.init(privParam);
221:
222: BigInteger z = agree.calculateAgreement(pubParam);
223:
224: if (forEncryption) {
225: return encryptBlock(in, inOff, inLen, z.toByteArray());
226: } else {
227: return decryptBlock(in, inOff, inLen, z.toByteArray());
228: }
229: }
230: }
|