001: package org.bouncycastle.jce.provider;
002:
003: import org.bouncycastle.crypto.CipherParameters;
004: import org.bouncycastle.crypto.InvalidCipherTextException;
005: import org.bouncycastle.crypto.agreement.DHBasicAgreement;
006: import org.bouncycastle.crypto.agreement.ECDHBasicAgreement;
007: import org.bouncycastle.crypto.digests.SHA1Digest;
008: import org.bouncycastle.crypto.engines.IESEngine;
009: import org.bouncycastle.crypto.generators.KDF2BytesGenerator;
010: import org.bouncycastle.crypto.macs.HMac;
011: import org.bouncycastle.crypto.params.IESParameters;
012: import org.bouncycastle.jce.interfaces.ECPrivateKey;
013: import org.bouncycastle.jce.interfaces.ECPublicKey;
014: import org.bouncycastle.jce.interfaces.IESKey;
015: import org.bouncycastle.jce.spec.IESParameterSpec;
016:
017: import javax.crypto.BadPaddingException;
018: import javax.crypto.Cipher;
019: import javax.crypto.IllegalBlockSizeException;
020: import javax.crypto.NoSuchPaddingException;
021: import javax.crypto.interfaces.DHPrivateKey;
022: import java.io.ByteArrayOutputStream;
023: import java.security.AlgorithmParameters;
024: import java.security.InvalidAlgorithmParameterException;
025: import java.security.InvalidKeyException;
026: import java.security.Key;
027: import java.security.SecureRandom;
028: import java.security.spec.AlgorithmParameterSpec;
029:
030: public class JCEIESCipher extends WrapCipherSpi {
031: private IESEngine cipher;
032: private int state = -1;
033: private ByteArrayOutputStream buffer = new ByteArrayOutputStream();
034: private AlgorithmParameters engineParam = null;
035: private IESParameterSpec engineParams = null;
036:
037: //
038: // specs we can handle.
039: //
040: private Class[] availableSpecs = { IESParameterSpec.class };
041:
042: public JCEIESCipher(IESEngine engine) {
043: cipher = engine;
044: }
045:
046: protected int engineGetBlockSize() {
047: return 0;
048: }
049:
050: protected byte[] engineGetIV() {
051: return null;
052: }
053:
054: protected int engineGetKeySize(Key key) {
055: if (!(key instanceof IESKey)) {
056: throw new IllegalArgumentException("must be passed IE key");
057: }
058:
059: IESKey ieKey = (IESKey) key;
060:
061: if (ieKey.getPrivate() instanceof DHPrivateKey) {
062: DHPrivateKey k = (DHPrivateKey) ieKey.getPrivate();
063:
064: return k.getX().bitLength();
065: } else if (ieKey.getPrivate() instanceof ECPrivateKey) {
066: ECPrivateKey k = (ECPrivateKey) ieKey.getPrivate();
067:
068: return k.getD().bitLength();
069: }
070:
071: throw new IllegalArgumentException("not an IE key!");
072: }
073:
074: protected int engineGetOutputSize(int inputLen) {
075: if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE) {
076: return buffer.size() + inputLen + 20; /* SHA1 MAC size */
077: } else if (state == Cipher.DECRYPT_MODE
078: || state == Cipher.UNWRAP_MODE) {
079: return buffer.size() + inputLen - 20;
080: } else {
081: throw new IllegalStateException("cipher not initialised");
082: }
083: }
084:
085: protected AlgorithmParameters engineGetParameters() {
086: if (engineParam == null) {
087: if (engineParams != null) {
088: String name = "IES";
089:
090: try {
091: engineParam = AlgorithmParameters.getInstance(name,
092: "BC");
093: engineParam.init(engineParams);
094: } catch (Exception e) {
095: throw new RuntimeException(e.toString());
096: }
097: }
098: }
099:
100: return engineParam;
101: }
102:
103: protected void engineSetMode(String mode) {
104: throw new IllegalArgumentException("can't support mode " + mode);
105: }
106:
107: protected void engineSetPadding(String padding)
108: throws NoSuchPaddingException {
109: throw new NoSuchPaddingException(padding
110: + " unavailable with RSA.");
111: }
112:
113: protected void engineInit(int opmode, Key key,
114: AlgorithmParameterSpec params, SecureRandom random)
115: throws InvalidKeyException,
116: InvalidAlgorithmParameterException {
117: if (!(key instanceof IESKey)) {
118: throw new InvalidKeyException("must be passed IE key");
119: }
120:
121: if (params == null
122: && (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)) {
123: //
124: // if nothing is specified we set up for a 128 bit mac, with
125: // 128 bit derivation vectors.
126: //
127: byte[] d = new byte[16];
128: byte[] e = new byte[16];
129:
130: if (random == null) {
131: random = new SecureRandom();
132: }
133:
134: random.nextBytes(d);
135: random.nextBytes(e);
136:
137: params = new IESParameterSpec(d, e, 128);
138: } else if (!(params instanceof IESParameterSpec)) {
139: throw new InvalidAlgorithmParameterException(
140: "must be passed IES parameters");
141: }
142:
143: IESKey ieKey = (IESKey) key;
144:
145: CipherParameters pubKey;
146: CipherParameters privKey;
147:
148: if (ieKey.getPublic() instanceof ECPublicKey) {
149: pubKey = ECUtil.generatePublicKeyParameter(ieKey
150: .getPublic());
151: privKey = ECUtil.generatePrivateKeyParameter(ieKey
152: .getPrivate());
153: } else {
154: pubKey = DHUtil.generatePublicKeyParameter(ieKey
155: .getPublic());
156: privKey = DHUtil.generatePrivateKeyParameter(ieKey
157: .getPrivate());
158: }
159:
160: this .engineParams = (IESParameterSpec) params;
161:
162: IESParameters p = new IESParameters(engineParams
163: .getDerivationV(), engineParams.getEncodingV(),
164: engineParams.getMacKeySize());
165:
166: this .state = opmode;
167:
168: buffer.reset();
169:
170: switch (opmode) {
171: case Cipher.ENCRYPT_MODE:
172: case Cipher.WRAP_MODE:
173: cipher.init(true, privKey, pubKey, p);
174: break;
175: case Cipher.DECRYPT_MODE:
176: case Cipher.UNWRAP_MODE:
177: cipher.init(false, privKey, pubKey, p);
178: break;
179: default:
180: System.out.println("eeek!");
181: }
182: }
183:
184: protected void engineInit(int opmode, Key key,
185: AlgorithmParameters params, SecureRandom random)
186: throws InvalidKeyException,
187: InvalidAlgorithmParameterException {
188: AlgorithmParameterSpec paramSpec = null;
189:
190: if (params != null) {
191: for (int i = 0; i != availableSpecs.length; i++) {
192: try {
193: paramSpec = params
194: .getParameterSpec(availableSpecs[i]);
195: break;
196: } catch (Exception e) {
197: continue;
198: }
199: }
200:
201: if (paramSpec == null) {
202: throw new InvalidAlgorithmParameterException(
203: "can't handle parameter " + params.toString());
204: }
205: }
206:
207: engineParam = params;
208: engineInit(opmode, key, paramSpec, random);
209: }
210:
211: protected void engineInit(int opmode, Key key, SecureRandom random)
212: throws InvalidKeyException {
213: if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) {
214: try {
215: engineInit(opmode, key, (AlgorithmParameterSpec) null,
216: random);
217: return;
218: } catch (InvalidAlgorithmParameterException e) {
219: // fall through...
220: }
221: }
222:
223: throw new IllegalArgumentException(
224: "can't handle null parameter spec in IES");
225: }
226:
227: protected byte[] engineUpdate(byte[] input, int inputOffset,
228: int inputLen) {
229: buffer.write(input, inputOffset, inputLen);
230: return null;
231: }
232:
233: protected int engineUpdate(byte[] input, int inputOffset,
234: int inputLen, byte[] output, int outputOffset) {
235: buffer.write(input, inputOffset, inputLen);
236: return 0;
237: }
238:
239: protected byte[] engineDoFinal(byte[] input, int inputOffset,
240: int inputLen) throws IllegalBlockSizeException,
241: BadPaddingException {
242: if (inputLen != 0) {
243: buffer.write(input, inputOffset, inputLen);
244: }
245:
246: try {
247: byte[] buf = buffer.toByteArray();
248:
249: buffer.reset();
250:
251: return cipher.processBlock(buf, 0, buf.length);
252: } catch (InvalidCipherTextException e) {
253: throw new BadPaddingException(e.getMessage());
254: }
255: }
256:
257: protected int engineDoFinal(byte[] input, int inputOffset,
258: int inputLen, byte[] output, int outputOffset)
259: throws IllegalBlockSizeException, BadPaddingException {
260: if (inputLen != 0) {
261: buffer.write(input, inputOffset, inputLen);
262: }
263:
264: try {
265: byte[] buf = buffer.toByteArray();
266:
267: buffer.reset();
268:
269: buf = cipher.processBlock(buf, 0, buf.length);
270:
271: System.arraycopy(buf, 0, output, outputOffset, buf.length);
272:
273: return buf.length;
274: } catch (InvalidCipherTextException e) {
275: throw new BadPaddingException(e.getMessage());
276: }
277: }
278:
279: /**
280: * classes that inherit from us.
281: */
282: static public class BrokenECIES extends JCEIESCipher {
283: public BrokenECIES() {
284: super (new IESEngine(new ECDHBasicAgreement(),
285: new BrokenKDF2BytesGenerator(new SHA1Digest()),
286: new HMac(new SHA1Digest())));
287: }
288: }
289:
290: static public class BrokenIES extends JCEIESCipher {
291: public BrokenIES() {
292: super (new IESEngine(new DHBasicAgreement(),
293: new BrokenKDF2BytesGenerator(new SHA1Digest()),
294: new HMac(new SHA1Digest())));
295: }
296: }
297:
298: static public class ECIES extends JCEIESCipher {
299: public ECIES() {
300: super (new IESEngine(new ECDHBasicAgreement(),
301: new KDF2BytesGenerator(new SHA1Digest()), new HMac(
302: new SHA1Digest())));
303: }
304: }
305:
306: static public class IES extends JCEIESCipher {
307: public IES() {
308: super (new IESEngine(new DHBasicAgreement(),
309: new KDF2BytesGenerator(new SHA1Digest()), new HMac(
310: new SHA1Digest())));
311: }
312: }
313: }
|