diff options
Diffstat (limited to 'prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java')
-rw-r--r-- | prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java | 363 |
1 files changed, 363 insertions, 0 deletions
diff --git a/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java new file mode 100644 index 00000000..9337df04 --- /dev/null +++ b/prov/src/main/java/org/spongycastle/jcajce/provider/asymmetric/ies/CipherSpi.java @@ -0,0 +1,363 @@ +package org.spongycastle.jcajce.provider.asymmetric.ies; + +import java.io.ByteArrayOutputStream; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.interfaces.DHPrivateKey; + +import org.spongycastle.crypto.CipherParameters; +import org.spongycastle.crypto.InvalidCipherTextException; +import org.spongycastle.crypto.agreement.DHBasicAgreement; +import org.spongycastle.crypto.digests.SHA1Digest; +import org.spongycastle.crypto.engines.IESEngine; +import org.spongycastle.crypto.generators.KDF2BytesGenerator; +import org.spongycastle.crypto.macs.HMac; +import org.spongycastle.crypto.params.IESParameters; +import org.spongycastle.jce.provider.BouncyCastleProvider; +import org.spongycastle.jcajce.provider.asymmetric.util.DHUtil; +import org.spongycastle.jcajce.provider.asymmetric.util.ECUtil; +import org.spongycastle.jce.interfaces.ECPrivateKey; +import org.spongycastle.jce.interfaces.ECPublicKey; +import org.spongycastle.jce.interfaces.IESKey; +import org.spongycastle.jce.spec.IESParameterSpec; + +public class CipherSpi + extends javax.crypto.CipherSpi +{ + private IESEngine cipher; + private int state = -1; + private ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + private AlgorithmParameters engineParam = null; + private IESParameterSpec engineParams = null; + + // + // specs we can handle. + // + private Class[] availableSpecs = + { + IESParameterSpec.class + }; + + public CipherSpi( + IESEngine engine) + { + cipher = engine; + } + + protected int engineGetBlockSize() + { + return 0; + } + + protected byte[] engineGetIV() + { + return null; + } + + protected int engineGetKeySize( + Key key) + { + if (!(key instanceof IESKey)) + { + throw new IllegalArgumentException("must be passed IE key"); + } + + IESKey ieKey = (IESKey)key; + + if (ieKey.getPrivate() instanceof DHPrivateKey) + { + DHPrivateKey k = (DHPrivateKey)ieKey.getPrivate(); + + return k.getX().bitLength(); + } + else if (ieKey.getPrivate() instanceof ECPrivateKey) + { + ECPrivateKey k = (ECPrivateKey)ieKey.getPrivate(); + + return k.getD().bitLength(); + } + + throw new IllegalArgumentException("not an IE key!"); + } + + protected int engineGetOutputSize( + int inputLen) + { + if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE) + { + return buffer.size() + inputLen + 20; /* SHA1 MAC size */ + } + else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE) + { + return buffer.size() + inputLen - 20; + } + else + { + throw new IllegalStateException("cipher not initialised"); + } + } + + protected AlgorithmParameters engineGetParameters() + { + if (engineParam == null) + { + if (engineParams != null) + { + String name = "IES"; + + try + { + engineParam = AlgorithmParameters.getInstance(name, BouncyCastleProvider.PROVIDER_NAME); + engineParam.init(engineParams); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } + } + + return engineParam; + } + + protected void engineSetMode( + String mode) + { + throw new IllegalArgumentException("can't support mode " + mode); + } + + protected void engineSetPadding( + String padding) + throws NoSuchPaddingException + { + throw new NoSuchPaddingException(padding + " unavailable with RSA."); + } + + protected void engineInit( + int opmode, + Key key, + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + if (!(key instanceof IESKey)) + { + throw new InvalidKeyException("must be passed IES key"); + } + + if (params == null && (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE)) + { + // + // if nothing is specified we set up for a 128 bit mac, with + // 128 bit derivation vectors. + // + byte[] d = new byte[16]; + byte[] e = new byte[16]; + + if (random == null) + { + random = new SecureRandom(); + } + + random.nextBytes(d); + random.nextBytes(e); + + params = new IESParameterSpec(d, e, 128); + } + else if (!(params instanceof IESParameterSpec)) + { + throw new InvalidAlgorithmParameterException("must be passed IES parameters"); + } + + IESKey ieKey = (IESKey)key; + + CipherParameters pubKey; + CipherParameters privKey; + + if (ieKey.getPublic() instanceof ECPublicKey) + { + pubKey = ECUtil.generatePublicKeyParameter(ieKey.getPublic()); + privKey = ECUtil.generatePrivateKeyParameter(ieKey.getPrivate()); + } + else + { + pubKey = DHUtil.generatePublicKeyParameter(ieKey.getPublic()); + privKey = DHUtil.generatePrivateKeyParameter(ieKey.getPrivate()); + } + + this.engineParams = (IESParameterSpec)params; + + IESParameters p = new IESParameters(engineParams.getDerivationV(), engineParams.getEncodingV(), engineParams.getMacKeySize()); + + this.state = opmode; + + buffer.reset(); + + switch (opmode) + { + case Cipher.ENCRYPT_MODE: + case Cipher.WRAP_MODE: + cipher.init(true, privKey, pubKey, p); + break; + case Cipher.DECRYPT_MODE: + case Cipher.UNWRAP_MODE: + cipher.init(false, privKey, pubKey, p); + break; + default: + System.out.println("eeek!"); + } + } + + protected void engineInit( + int opmode, + Key key, + AlgorithmParameters params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + AlgorithmParameterSpec paramSpec = null; + + if (params != null) + { + for (int i = 0; i != availableSpecs.length; i++) + { + try + { + paramSpec = params.getParameterSpec(availableSpecs[i]); + break; + } + catch (Exception e) + { + continue; + } + } + + if (paramSpec == null) + { + throw new InvalidAlgorithmParameterException("can't handle parameter " + params.toString()); + } + } + + engineParam = params; + engineInit(opmode, key, paramSpec, random); + } + + protected void engineInit( + int opmode, + Key key, + SecureRandom random) + throws InvalidKeyException + { + if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) + { + try + { + engineInit(opmode, key, (AlgorithmParameterSpec)null, random); + return; + } + catch (InvalidAlgorithmParameterException e) + { + // fall through... + } + } + + throw new IllegalArgumentException("can't handle null parameter spec in IES"); + } + + protected byte[] engineUpdate( + byte[] input, + int inputOffset, + int inputLen) + { + buffer.write(input, inputOffset, inputLen); + return null; + } + + protected int engineUpdate( + byte[] input, + int inputOffset, + int inputLen, + byte[] output, + int outputOffset) + { + buffer.write(input, inputOffset, inputLen); + return 0; + } + + protected byte[] engineDoFinal( + byte[] input, + int inputOffset, + int inputLen) + throws IllegalBlockSizeException, BadPaddingException + { + if (inputLen != 0) + { + buffer.write(input, inputOffset, inputLen); + } + + try + { + byte[] buf = buffer.toByteArray(); + + buffer.reset(); + + return cipher.processBlock(buf, 0, buf.length); + } + catch (InvalidCipherTextException e) + { + throw new BadPaddingException(e.getMessage()); + } + } + + protected int engineDoFinal( + byte[] input, + int inputOffset, + int inputLen, + byte[] output, + int outputOffset) + throws IllegalBlockSizeException, BadPaddingException + { + if (inputLen != 0) + { + buffer.write(input, inputOffset, inputLen); + } + + try + { + byte[] buf = buffer.toByteArray(); + + buffer.reset(); + + buf = cipher.processBlock(buf, 0, buf.length); + + System.arraycopy(buf, 0, output, outputOffset, buf.length); + + return buf.length; + } + catch (InvalidCipherTextException e) + { + throw new BadPaddingException(e.getMessage()); + } + } + + static public class IES + extends CipherSpi + { + public IES() + { + super(new IESEngine( + new DHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()))); + } + } +} |