aboutsummaryrefslogtreecommitdiffstats
path: root/OpenKeychain/src/main/java/org/bouncycastle
diff options
context:
space:
mode:
authorVincent Breitmoser <valodim@mugenguild.com>2016-02-10 17:36:02 +0100
committerVincent Breitmoser <valodim@mugenguild.com>2016-02-10 17:36:02 +0100
commitda6dfb57a0aa816919cd23752e1707ba6a2e8cae (patch)
treed6ede03785491d4c56b10cad9062b8bcac3ea78b /OpenKeychain/src/main/java/org/bouncycastle
parent01b165ea88a032f31b8c2ff07351d3f893f6413d (diff)
parent751298a4d832f316244fd6345c46ba806dcfc860 (diff)
downloadopen-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')
-rw-r--r--OpenKeychain/src/main/java/org/bouncycastle/openpgp/jcajce/JcaSkipMarkerPGPObjectFactory.java32
-rw-r--r--OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/CachingDataDecryptorFactory.java76
-rw-r--r--OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/NfcSyncPGPContentSignerBuilder.java144
-rw-r--r--OpenKeychain/src/main/java/org/bouncycastle/openpgp/operator/jcajce/SessionKeySecretKeyDecryptorBuilder.java116
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);
+ }
+ }
+ };
+ }
+}