diff options
Diffstat (limited to 'OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java')
-rw-r--r-- | OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java | 91 |
1 files changed, 73 insertions, 18 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java index 4cb92c368..cc34e8737 100644 --- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java @@ -18,8 +18,10 @@ package org.sufficientlysecure.keychain.pgp; +import org.openkeychain.nfc.NfcHandler; import org.spongycastle.bcpg.ArmoredOutputStream; import org.spongycastle.bcpg.BCPGOutputStream; +import org.spongycastle.bcpg.S2K; import org.spongycastle.openpgp.PGPCompressedDataGenerator; import org.spongycastle.openpgp.PGPEncryptedDataGenerator; import org.spongycastle.openpgp.PGPException; @@ -29,6 +31,7 @@ import org.spongycastle.openpgp.PGPSignatureGenerator; import org.spongycastle.openpgp.PGPV3SignatureGenerator; import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator; import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder; +import org.spongycastle.openpgp.operator.jcajce.NfcSyncPGPContentSignerBuilder; import org.sufficientlysecure.keychain.Constants; import org.sufficientlysecure.keychain.R; import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException; @@ -38,16 +41,20 @@ import org.sufficientlysecure.keychain.util.InputData; import org.sufficientlysecure.keychain.util.Log; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SignatureException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Date; +import java.util.LinkedList; /** * This class uses a Builder pattern! @@ -70,6 +77,7 @@ public class PgpSignEncrypt { private String mSignaturePassphrase; private boolean mEncryptToSigner; private boolean mCleartextInput; + private byte[] mNfcData; private static byte[] NEW_LINE; @@ -100,6 +108,7 @@ public class PgpSignEncrypt { this.mSignaturePassphrase = builder.mSignaturePassphrase; this.mEncryptToSigner = builder.mEncryptToSigner; this.mCleartextInput = builder.mCleartextInput; + this.mNfcData = builder.mNfcData; } public static class Builder { @@ -122,6 +131,7 @@ public class PgpSignEncrypt { private String mSignaturePassphrase = null; private boolean mEncryptToSigner = false; private boolean mCleartextInput = false; + private byte[] mNfcData = null; public Builder(ProviderHelper providerHelper, String versionHeader, InputData data, OutputStream outStream) { this.mProviderHelper = providerHelper; @@ -130,7 +140,7 @@ public class PgpSignEncrypt { this.mOutStream = outStream; } - public Builder setProgressable(Progressable progressable) { + public Builder setProgressable(Progressable progressable) { mProgressable = progressable; return this; } @@ -170,6 +180,12 @@ public class PgpSignEncrypt { return this; } + /** + * Generate old V3 signatures + * + * @param signatureForceV3 + * @return + */ public Builder setSignatureForceV3(boolean signatureForceV3) { mSignatureForceV3 = signatureForceV3; return this; @@ -200,6 +216,11 @@ public class PgpSignEncrypt { return this; } + public Builder setNfcData(byte[] nfcData) { + mNfcData = nfcData; + return this; + } + public PgpSignEncrypt build() { return new PgpSignEncrypt(this); } @@ -227,17 +248,36 @@ public class PgpSignEncrypt { } } + public static class WrongPassphraseException extends Exception { + public WrongPassphraseException() { + } + } + public static class NoSigningKeyException extends Exception { public NoSigningKeyException() { } } + public static class NeedNfcDataException extends Exception { + public byte[] mData; + + public NeedNfcDataException(byte[] data) { + mData = data; + } + } + + // TODO: remove later + static String convertStreamToString(java.io.InputStream is) { + java.util.Scanner s = new java.util.Scanner(is).useDelimiter("\\A"); + return s.hasNext() ? s.next() : ""; + } + /** * Signs and/or encrypts data based on parameters of class */ public void execute() throws IOException, PGPException, NoSuchProviderException, - NoSuchAlgorithmException, SignatureException, KeyExtractionException, NoSigningKeyException, NoPassphraseException { + NoSuchAlgorithmException, SignatureException, KeyExtractionException, NoSigningKeyException, NoPassphraseException, NeedNfcDataException, WrongPassphraseException { boolean enableSignature = mSignatureMasterKeyId != Constants.key.none; boolean enableEncryption = ((mEncryptionMasterKeyIds != null && mEncryptionMasterKeyIds.length > 0) @@ -255,16 +295,6 @@ public class PgpSignEncrypt { mEncryptionMasterKeyIds[mEncryptionMasterKeyIds.length - 1] = mSignatureMasterKeyId; } - ArmoredOutputStream armorOut = null; - OutputStream out; - if (mEnableAsciiArmorOutput) { - armorOut = new ArmoredOutputStream(mOutStream); - armorOut.setHeader("Version", mVersionHeader); - out = armorOut; - } else { - out = mOutStream; - } - /* Get keys for signature generation for later usage */ WrappedSecretKey signingKey = null; if (enableSignature) { @@ -276,7 +306,7 @@ public class PgpSignEncrypt { } try { signingKey = signingKeyRing.getSigningSubKey(); - } catch(PgpGeneralException e) { + } catch (PgpGeneralException e) { throw new NoSigningKeyException(); } @@ -287,10 +317,19 @@ public class PgpSignEncrypt { updateProgress(R.string.progress_extracting_signature_key, 0, 100); try { - signingKey.unlock(mSignaturePassphrase); + if (!signingKey.unlock(mSignaturePassphrase)) { + throw new WrongPassphraseException(); + } } catch (PgpGeneralException e) { throw new KeyExtractionException(); } + + // check if hash algo is supported + LinkedList<Integer> supported = signingKey.getSupportedHashAlgorithms(); + if (!supported.contains(mSignatureHashAlgorithm)) { + // get most preferred + mSignatureHashAlgorithm = supported.getLast(); + } } updateProgress(R.string.progress_preparing_streams, 5, 100); @@ -339,10 +378,10 @@ public class PgpSignEncrypt { boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption; if (mSignatureForceV3) { signatureV3Generator = signingKey.getV3SignatureGenerator( - mSignatureHashAlgorithm,cleartext); + mSignatureHashAlgorithm, cleartext); } else { signatureGenerator = signingKey.getSignatureGenerator( - mSignatureHashAlgorithm, cleartext); + mSignatureHashAlgorithm, cleartext, mNfcData); } } catch (PgpGeneralException e) { // TODO throw correct type of exception (which shouldn't be PGPException) @@ -350,10 +389,21 @@ public class PgpSignEncrypt { } } + ArmoredOutputStream armorOut = null; + OutputStream out; + if (mEnableAsciiArmorOutput) { + armorOut = new ArmoredOutputStream(mOutStream); + armorOut.setHeader("Version", mVersionHeader); + out = armorOut; + } else { + out = mOutStream; + } + PGPCompressedDataGenerator compressGen = null; - OutputStream pOut; + OutputStream pOut = null; OutputStream encryptionOut = null; BCPGOutputStream bcpgOut; + if (enableEncryption) { /* actual encryption */ @@ -493,7 +543,12 @@ public class PgpSignEncrypt { if (mSignatureForceV3) { signatureV3Generator.generate().encode(pOut); } else { - signatureGenerator.generate().encode(pOut); + try { + signatureGenerator.generate().encode(pOut); + } catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) { + // this secret key diverts to a OpenPGP card, throw exception with to-be-signed hash + throw new NeedNfcDataException(e.hashToSign); + } } } |