diff options
author | Vincent Breitmoser <valodim@mugenguild.com> | 2016-02-10 17:36:02 +0100 |
---|---|---|
committer | Vincent Breitmoser <valodim@mugenguild.com> | 2016-02-10 17:36:02 +0100 |
commit | da6dfb57a0aa816919cd23752e1707ba6a2e8cae (patch) | |
tree | d6ede03785491d4c56b10cad9062b8bcac3ea78b /OpenKeychain/src/main/java/org/bouncycastle/openpgp | |
parent | 01b165ea88a032f31b8c2ff07351d3f893f6413d (diff) | |
parent | 751298a4d832f316244fd6345c46ba806dcfc860 (diff) | |
download | open-keychain-da6dfb57a0aa816919cd23752e1707ba6a2e8cae.tar.gz open-keychain-da6dfb57a0aa816919cd23752e1707ba6a2e8cae.tar.bz2 open-keychain-da6dfb57a0aa816919cd23752e1707ba6a2e8cae.zip |
Merge branch 'master' into performance
Diffstat (limited to 'OpenKeychain/src/main/java/org/bouncycastle/openpgp')
4 files changed, 368 insertions, 0 deletions
diff --git a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java new file mode 100644 index 000000000..72d6036ab --- /dev/null +++ b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java @@ -0,0 +1,32 @@ +package org.bouncycastle.openpgp.jcajce; + + +import java.io.IOException; +import java.io.InputStream; + +import org.bouncycastle.openpgp.PGPMarker; + +/** This class wraps the regular PGPObjectFactory, changing its behavior to + * ignore all PGPMarker packets it encounters while reading. These packets + * carry no semantics of their own, and should be ignored according to + * RFC 4880. + * + * @see https://tools.ietf.org/html/rfc4880#section-5.8 + * @see org.bouncycastle.openpgp.PGPMarker + * + */ +public class JcaSkipMarkerPGPObjectFactory extends JcaPGPObjectFactory { + + public JcaSkipMarkerPGPObjectFactory(InputStream in) { + super(in); + } + + @Override + public Object nextObject() throws IOException { + Object o = super.nextObject(); + while (o instanceof PGPMarker) { + o = super.nextObject(); + } + return o; + } +} diff --git a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java new file mode 100644 index 000000000..703af94f4 --- /dev/null +++ b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2013-2014 Philipp Jakubeit, Signe Rüsch, Dominik Schürmann + * + * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. + */ + +package org.bouncycastle.openpgp.operator.jcajce; + +import org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKeyEncryptedData; +import org.bouncycastle.openpgp.operator.PGPDataDecryptor; +import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; + +import java.nio.ByteBuffer; +import java.util.Map; + +public class CachingDataDecryptorFactory implements PublicKeyDataDecryptorFactory +{ + private final PublicKeyDataDecryptorFactory mWrappedDecryptor; + private final Map<ByteBuffer, byte[]> mSessionKeyCache; + + private OperatorHelper mOperatorHelper; + + public CachingDataDecryptorFactory(String providerName, + final Map<ByteBuffer,byte[]> sessionKeyCache) + { + mWrappedDecryptor = null; + mSessionKeyCache = sessionKeyCache; + + mOperatorHelper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + } + + public CachingDataDecryptorFactory(PublicKeyDataDecryptorFactory wrapped, + final Map<ByteBuffer,byte[]> sessionKeyCache) + { + mWrappedDecryptor = wrapped; + mSessionKeyCache = sessionKeyCache; + + } + + public boolean hasCachedSessionData(PGPPublicKeyEncryptedData encData) throws PGPException { + ByteBuffer bi = ByteBuffer.wrap(encData.getSessionKey()[0]); + return mSessionKeyCache.containsKey(bi); + } + + public Map<ByteBuffer, byte[]> getCachedSessionKeys() { + return mSessionKeyCache; + } + + public boolean canDecrypt() { + return mWrappedDecryptor != null; + } + + @Override + public byte[] recoverSessionData(int keyAlgorithm, byte[][] secKeyData) throws PGPException { + ByteBuffer bi = ByteBuffer.wrap(secKeyData[0]); // encoded MPI + if (mSessionKeyCache.containsKey(bi)) { + return mSessionKeyCache.get(bi); + } + + byte[] sessionData = mWrappedDecryptor.recoverSessionData(keyAlgorithm, secKeyData); + mSessionKeyCache.put(bi, sessionData); + return sessionData; + } + + @Override + public PGPDataDecryptor createDataDecryptor(boolean withIntegrityPacket, int encAlgorithm, byte[] key) + throws PGPException { + if (mWrappedDecryptor != null) { + return mWrappedDecryptor.createDataDecryptor(withIntegrityPacket, encAlgorithm, key); + } + return mOperatorHelper.createDataDecryptor(withIntegrityPacket, encAlgorithm, key); + } + +} diff --git a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java new file mode 100644 index 000000000..584d86891 --- /dev/null +++ b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java @@ -0,0 +1,144 @@ +/** + * Copyright (c) 2013-2014 Philipp Jakubeit, Signe Rüsch, Dominik Schürmann + * Copyright (c) 2000-2013 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) + * + * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. + */ + +package org.bouncycastle.openpgp.operator.jcajce; + +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPrivateKey; +import org.bouncycastle.openpgp.operator.PGPContentSigner; +import org.bouncycastle.openpgp.operator.PGPContentSignerBuilder; +import org.bouncycastle.openpgp.operator.PGPDigestCalculator; + +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.security.Provider; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + + +/** + * This class is based on JcaPGPContentSignerBuilder. + * + * Instead of using a Signature object based on a privateKey, this class only calculates the digest + * of the output stream and gives the result back using a RuntimeException. + */ +public class NfcSyncPGPContentSignerBuilder + implements PGPContentSignerBuilder +{ + private JcaPGPDigestCalculatorProviderBuilder digestCalculatorProviderBuilder = new JcaPGPDigestCalculatorProviderBuilder(); + private int hashAlgorithm; + private int keyAlgorithm; + private long keyID; + + private Map signedHashes; + + public static class NfcInteractionNeeded extends RuntimeException + { + public byte[] hashToSign; + public int hashAlgo; + + public NfcInteractionNeeded(byte[] hashToSign, int hashAlgo) + { + super("NFC interaction required!"); + this.hashToSign = hashToSign; + this.hashAlgo = hashAlgo; + } + } + + public NfcSyncPGPContentSignerBuilder(int keyAlgorithm, int hashAlgorithm, long keyID, Map signedHashes) + { + this.keyAlgorithm = keyAlgorithm; + this.hashAlgorithm = hashAlgorithm; + this.keyID = keyID; + this.signedHashes = signedHashes; + } + + public NfcSyncPGPContentSignerBuilder setProvider(Provider provider) + { + digestCalculatorProviderBuilder.setProvider(provider); + + return this; + } + + public NfcSyncPGPContentSignerBuilder setProvider(String providerName) + { + digestCalculatorProviderBuilder.setProvider(providerName); + + return this; + } + + public NfcSyncPGPContentSignerBuilder setDigestProvider(Provider provider) + { + digestCalculatorProviderBuilder.setProvider(provider); + + return this; + } + + public NfcSyncPGPContentSignerBuilder setDigestProvider(String providerName) + { + digestCalculatorProviderBuilder.setProvider(providerName); + + return this; + } + + public PGPContentSigner build(final int signatureType, PGPPrivateKey privateKey) + throws PGPException { + // NOTE: privateKey is null in this case! + return build(signatureType, keyID); + } + + public PGPContentSigner build(final int signatureType, final long keyID) + throws PGPException + { + final PGPDigestCalculator digestCalculator = digestCalculatorProviderBuilder.build().get(hashAlgorithm); + + return new PGPContentSigner() + { + public int getType() + { + return signatureType; + } + + public int getHashAlgorithm() + { + return hashAlgorithm; + } + + public int getKeyAlgorithm() + { + return keyAlgorithm; + } + + public long getKeyID() + { + return keyID; + } + + public OutputStream getOutputStream() + { + return digestCalculator.getOutputStream(); + } + + public byte[] getSignature() { + byte[] digest = digestCalculator.getDigest(); + ByteBuffer buf = ByteBuffer.wrap(digest); + if (signedHashes.containsKey(buf)) { + return (byte[]) signedHashes.get(buf); + } + // catch this when signatureGenerator.generate() is executed and divert digest to card, + // when doing the operation again reuse creationTimestamp (this will be hashed) + throw new NfcInteractionNeeded(digest, getHashAlgorithm()); + } + + public byte[] getDigest() + { + return digestCalculator.getDigest(); + } + }; + } +} diff --git a/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java new file mode 100644 index 000000000..6f1b6f5ef --- /dev/null +++ b/OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2016 Vincent Breitmoser + * + * Licensed under the Bouncy Castle License (MIT license). See LICENSE file for details. + */ + +package org.bouncycastle.openpgp.operator.jcajce; + + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Provider; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.spec.IvParameterSpec; +import org.bouncycastle.bcpg.S2K; +import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import org.bouncycastle.jcajce.util.NamedJcaJceHelper; +import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; +import org.bouncycastle.openpgp.operator.PGPDigestCalculatorProvider; + + +/** This is a builder for a special PBESecretKeyDecryptor which is parametrized by a + * fixed session key, which is used in place of the one obtained from a passphrase. + */ +public class SessionKeySecretKeyDecryptorBuilder +{ + private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper()); + private PGPDigestCalculatorProvider calculatorProvider; + + private JcaPGPDigestCalculatorProviderBuilder calculatorProviderBuilder; + + public SessionKeySecretKeyDecryptorBuilder() + { + this.calculatorProviderBuilder = new JcaPGPDigestCalculatorProviderBuilder(); + } + + public SessionKeySecretKeyDecryptorBuilder(PGPDigestCalculatorProvider calculatorProvider) + { + this.calculatorProvider = calculatorProvider; + } + + public SessionKeySecretKeyDecryptorBuilder setProvider(Provider provider) + { + this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider)); + + if (calculatorProviderBuilder != null) + { + calculatorProviderBuilder.setProvider(provider); + } + + return this; + } + + public SessionKeySecretKeyDecryptorBuilder setProvider(String providerName) + { + this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName)); + + if (calculatorProviderBuilder != null) + { + calculatorProviderBuilder.setProvider(providerName); + } + + return this; + } + + public PBESecretKeyDecryptor build(final byte[] sessionKey) + throws PGPException + { + if (calculatorProvider == null) + { + calculatorProvider = calculatorProviderBuilder.build(); + } + + return new PBESecretKeyDecryptor(null, calculatorProvider) + { + @Override + public byte[] makeKeyFromPassPhrase(int keyAlgorithm, S2K s2k) throws PGPException { + return sessionKey; + } + + public byte[] recoverKeyData(int encAlgorithm, byte[] key, byte[] iv, byte[] keyData, int keyOff, int keyLen) + throws PGPException + { + try + { + Cipher c = helper.createCipher(PGPUtil.getSymmetricCipherName(encAlgorithm) + "/CFB/NoPadding"); + + c.init(Cipher.DECRYPT_MODE, PGPUtil.makeSymmetricKey(encAlgorithm, key), new IvParameterSpec(iv)); + + return c.doFinal(keyData, keyOff, keyLen); + } + catch (IllegalBlockSizeException e) + { + throw new PGPException("illegal block size: " + e.getMessage(), e); + } + catch (BadPaddingException e) + { + throw new PGPException("bad padding: " + e.getMessage(), e); + } + catch (InvalidAlgorithmParameterException e) + { + throw new PGPException("invalid parameter: " + e.getMessage(), e); + } + catch (InvalidKeyException e) + { + throw new PGPException("invalid key: " + e.getMessage(), e); + } + } + }; + } +} |