001: package org.bouncycastle.jce.provider;
002:
003: import java.security.AlgorithmParameters;
004: import java.security.InvalidAlgorithmParameterException;
005: import java.security.InvalidKeyException;
006: import java.security.InvalidParameterException;
007: import java.security.Key;
008: import java.security.NoSuchAlgorithmException;
009: import java.security.PrivateKey;
010: import java.security.PublicKey;
011: import java.security.SecureRandom;
012: import java.security.spec.AlgorithmParameterSpec;
013: import java.security.spec.MGF1ParameterSpec;
014:
015: import javax.crypto.BadPaddingException;
016: import javax.crypto.Cipher;
017: import javax.crypto.IllegalBlockSizeException;
018: import javax.crypto.NoSuchPaddingException;
019: import javax.crypto.interfaces.DHKey;
020: import javax.crypto.spec.OAEPParameterSpec;
021: import javax.crypto.spec.PSource;
022:
023: import org.bouncycastle.crypto.AsymmetricBlockCipher;
024: import org.bouncycastle.crypto.BufferedAsymmetricBlockCipher;
025: import org.bouncycastle.crypto.CipherParameters;
026: import org.bouncycastle.crypto.Digest;
027: import org.bouncycastle.crypto.InvalidCipherTextException;
028: import org.bouncycastle.crypto.encodings.ISO9796d1Encoding;
029: import org.bouncycastle.crypto.encodings.OAEPEncoding;
030: import org.bouncycastle.crypto.encodings.PKCS1Encoding;
031: import org.bouncycastle.crypto.engines.ElGamalEngine;
032: import org.bouncycastle.crypto.params.ParametersWithRandom;
033: import org.bouncycastle.jce.interfaces.ElGamalKey;
034: import org.bouncycastle.jce.interfaces.ElGamalPrivateKey;
035: import org.bouncycastle.jce.interfaces.ElGamalPublicKey;
036: import org.bouncycastle.util.Strings;
037:
038: public class JCEElGamalCipher extends WrapCipherSpi {
039: private BufferedAsymmetricBlockCipher cipher;
040: private AlgorithmParameterSpec paramSpec;
041: private AlgorithmParameters engineParams;
042:
043: public JCEElGamalCipher(AsymmetricBlockCipher engine) {
044: cipher = new BufferedAsymmetricBlockCipher(engine);
045: }
046:
047: private void initFromSpec(OAEPParameterSpec pSpec)
048: throws NoSuchPaddingException {
049: MGF1ParameterSpec mgfParams = (MGF1ParameterSpec) pSpec
050: .getMGFParameters();
051: Digest digest = JCEDigestUtil.getDigest(mgfParams
052: .getDigestAlgorithm());
053:
054: if (digest == null) {
055: throw new NoSuchPaddingException(
056: "no match on OAEP constructor for digest algorithm: "
057: + mgfParams.getDigestAlgorithm());
058: }
059:
060: cipher = new BufferedAsymmetricBlockCipher(new OAEPEncoding(
061: new ElGamalEngine(), digest,
062: ((PSource.PSpecified) pSpec.getPSource()).getValue()));
063: paramSpec = pSpec;
064: }
065:
066: protected int engineGetBlockSize() {
067: return cipher.getInputBlockSize();
068: }
069:
070: protected byte[] engineGetIV() {
071: return null;
072: }
073:
074: protected int engineGetKeySize(Key key) {
075: if (key instanceof ElGamalKey) {
076: ElGamalKey k = (ElGamalKey) key;
077:
078: return k.getParameters().getP().bitLength();
079: } else if (key instanceof DHKey) {
080: DHKey k = (DHKey) key;
081:
082: return k.getParams().getP().bitLength();
083: }
084:
085: throw new IllegalArgumentException("not an ElGamal key!");
086: }
087:
088: protected int engineGetOutputSize(int inputLen) {
089: return cipher.getOutputBlockSize();
090: }
091:
092: protected AlgorithmParameters engineGetParameters() {
093: if (engineParams == null) {
094: if (paramSpec != null) {
095: try {
096: engineParams = AlgorithmParameters.getInstance(
097: "OAEP", "BC");
098: engineParams.init(paramSpec);
099: } catch (Exception e) {
100: throw new RuntimeException(e.toString());
101: }
102: }
103: }
104:
105: return engineParams;
106: }
107:
108: protected void engineSetMode(String mode)
109: throws NoSuchAlgorithmException {
110: String md = Strings.toUpperCase(mode);
111:
112: if (md.equals("NONE") || md.equals("ECB")) {
113: return;
114: }
115:
116: throw new NoSuchAlgorithmException("can't support mode " + mode);
117: }
118:
119: protected void engineSetPadding(String padding)
120: throws NoSuchPaddingException {
121: String pad = Strings.toUpperCase(padding);
122:
123: if (pad.equals("NOPADDING")) {
124: cipher = new BufferedAsymmetricBlockCipher(
125: new ElGamalEngine());
126: } else if (pad.equals("PKCS1PADDING")) {
127: cipher = new BufferedAsymmetricBlockCipher(
128: new PKCS1Encoding(new ElGamalEngine()));
129: } else if (pad.equals("ISO9796-1PADDING")) {
130: cipher = new BufferedAsymmetricBlockCipher(
131: new ISO9796d1Encoding(new ElGamalEngine()));
132: } else if (pad.equals("OAEPPADDING")) {
133: initFromSpec(OAEPParameterSpec.DEFAULT);
134: } else if (pad.equals("OAEPWITHMD5ANDMGF1PADDING")) {
135: initFromSpec(new OAEPParameterSpec("MD5", "MGF1",
136: new MGF1ParameterSpec("MD5"),
137: PSource.PSpecified.DEFAULT));
138: } else if (pad.equals("OAEPWITHSHA1ANDMGF1PADDING")) {
139: initFromSpec(OAEPParameterSpec.DEFAULT);
140: } else if (pad.equals("OAEPWITHSHA224ANDMGF1PADDING")) {
141: initFromSpec(new OAEPParameterSpec("SHA-224", "MGF1",
142: new MGF1ParameterSpec("SHA-224"),
143: PSource.PSpecified.DEFAULT));
144: } else if (pad.equals("OAEPWITHSHA256ANDMGF1PADDING")) {
145: initFromSpec(new OAEPParameterSpec("SHA-256", "MGF1",
146: MGF1ParameterSpec.SHA256,
147: PSource.PSpecified.DEFAULT));
148: } else if (pad.equals("OAEPWITHSHA384ANDMGF1PADDING")) {
149: initFromSpec(new OAEPParameterSpec("SHA-384", "MGF1",
150: MGF1ParameterSpec.SHA384,
151: PSource.PSpecified.DEFAULT));
152: } else if (pad.equals("OAEPWITHSHA512ANDMGF1PADDING")) {
153: initFromSpec(new OAEPParameterSpec("SHA-512", "MGF1",
154: MGF1ParameterSpec.SHA512,
155: PSource.PSpecified.DEFAULT));
156: } else {
157: throw new NoSuchPaddingException(padding
158: + " unavailable with ElGamal.");
159: }
160: }
161:
162: protected void engineInit(int opmode, Key key,
163: AlgorithmParameterSpec params, SecureRandom random)
164: throws InvalidKeyException {
165: CipherParameters param;
166:
167: if (params == null) {
168: if (key instanceof ElGamalPublicKey) {
169: param = ElGamalUtil
170: .generatePublicKeyParameter((PublicKey) key);
171: } else if (key instanceof ElGamalPrivateKey) {
172: param = ElGamalUtil
173: .generatePrivateKeyParameter((PrivateKey) key);
174: } else {
175: throw new InvalidKeyException(
176: "unknown key type passed to ElGamal");
177: }
178: } else {
179: throw new IllegalArgumentException(
180: "unknown parameter type.");
181: }
182:
183: if (random != null) {
184: param = new ParametersWithRandom(param, random);
185: }
186:
187: switch (opmode) {
188: case Cipher.ENCRYPT_MODE:
189: case Cipher.WRAP_MODE:
190: cipher.init(true, param);
191: break;
192: case Cipher.DECRYPT_MODE:
193: case Cipher.UNWRAP_MODE:
194: cipher.init(false, param);
195: break;
196: default:
197: throw new InvalidParameterException("unknown opmode "
198: + opmode + " passed to ElGamal");
199: }
200: }
201:
202: protected void engineInit(int opmode, Key key,
203: AlgorithmParameters params, SecureRandom random)
204: throws InvalidKeyException,
205: InvalidAlgorithmParameterException {
206: throw new InvalidAlgorithmParameterException(
207: "can't handle parameters in ElGamal");
208: }
209:
210: protected void engineInit(int opmode, Key key, SecureRandom random)
211: throws InvalidKeyException {
212: engineInit(opmode, key, (AlgorithmParameterSpec) null, random);
213: }
214:
215: protected byte[] engineUpdate(byte[] input, int inputOffset,
216: int inputLen) {
217: cipher.processBytes(input, inputOffset, inputLen);
218: return null;
219: }
220:
221: protected int engineUpdate(byte[] input, int inputOffset,
222: int inputLen, byte[] output, int outputOffset) {
223: cipher.processBytes(input, inputOffset, inputLen);
224: return 0;
225: }
226:
227: protected byte[] engineDoFinal(byte[] input, int inputOffset,
228: int inputLen) throws IllegalBlockSizeException,
229: BadPaddingException {
230: cipher.processBytes(input, inputOffset, inputLen);
231: try {
232: return cipher.doFinal();
233: } catch (InvalidCipherTextException e) {
234: throw new BadPaddingException(e.getMessage());
235: }
236: }
237:
238: protected int engineDoFinal(byte[] input, int inputOffset,
239: int inputLen, byte[] output, int outputOffset)
240: throws IllegalBlockSizeException, BadPaddingException {
241: byte[] out;
242:
243: cipher.processBytes(input, inputOffset, inputLen);
244:
245: try {
246: out = cipher.doFinal();
247: } catch (InvalidCipherTextException e) {
248: throw new BadPaddingException(e.getMessage());
249: }
250:
251: for (int i = 0; i != out.length; i++) {
252: output[outputOffset + i] = out[i];
253: }
254:
255: return out.length;
256: }
257:
258: /**
259: * classes that inherit from us.
260: */
261: static public class NoPadding extends JCEElGamalCipher {
262: public NoPadding() {
263: super (new ElGamalEngine());
264: }
265: }
266:
267: static public class PKCS1v1_5Padding extends JCEElGamalCipher {
268: public PKCS1v1_5Padding() {
269: super (new PKCS1Encoding(new ElGamalEngine()));
270: }
271: }
272: }
|