Use builder pattern for sign and encrypt

This commit is contained in:
Dominik Schürmann 2014-02-19 00:18:52 +01:00
parent d23950f799
commit 1710f4416f
5 changed files with 672 additions and 485 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2012-2013 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -17,37 +17,16 @@
package org.sufficientlysecure.keychain.pgp;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.util.Date;
import java.util.Iterator;
import android.content.Context;
import android.os.Bundle;
import org.spongycastle.bcpg.ArmoredInputStream;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGInputStream;
import org.spongycastle.bcpg.BCPGOutputStream;
import org.spongycastle.bcpg.SignaturePacket;
import org.spongycastle.bcpg.SignatureSubpacket;
import org.spongycastle.bcpg.SignatureSubpacketTags;
import org.spongycastle.openpgp.PGPCompressedData;
import org.spongycastle.openpgp.PGPCompressedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedData;
import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedDataList;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPLiteralData;
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
import org.spongycastle.openpgp.PGPObjectFactory;
import org.spongycastle.openpgp.PGPOnePassSignature;
import org.spongycastle.openpgp.PGPOnePassSignatureList;
@ -57,29 +36,20 @@ import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPPublicKeyEncryptedData;
import org.spongycastle.openpgp.PGPPublicKeyRing;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureList;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketVector;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
import org.spongycastle.openpgp.operator.PBEDataDecryptorFactory;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.PGPDigestCalculatorProvider;
import org.spongycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentVerifierBuilderProvider;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPDigestCalculatorProviderBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEDataDecryptorFactoryBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyDataDecryptorFactoryBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@ -88,17 +58,26 @@ import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import android.content.Context;
import android.os.Bundle;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.SignatureException;
import java.util.Iterator;
public class PgpOperation {
/**
* TODO: make builder pattern like in PgpOperationOutgoing
*/
public class PgpOperationIncoming {
private Context mContext;
private ProgressDialogUpdater mProgress;
private InputData mData;
private OutputStream mOutStream;
public PgpOperation(Context context, ProgressDialogUpdater progress, InputData data,
OutputStream outStream) {
public PgpOperationIncoming(Context context, ProgressDialogUpdater progress, InputData data,
OutputStream outStream) {
super();
this.mContext = context;
this.mProgress = progress;
@ -118,361 +97,6 @@ public class PgpOperation {
}
}
public void signAndEncrypt(boolean enableAsciiArmorOutput, int compressionId, long[] encryptionKeyIds,
String encryptionPassphrase, int symmetricEncryptionAlgorithm,
long signatureKeyId, int signatureHashAlgorithm,
boolean signatureForceV3, String signaturePassphrase)
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
if (encryptionKeyIds == null) {
encryptionKeyIds = new long[0];
}
boolean enableSignature = signatureKeyId != Id.key.none;
boolean enableCompression = compressionId == Id.choice.compression.none;
boolean enableEncryption = encryptionKeyIds.length != 0 || encryptionPassphrase != null;
int signatureType;
// TODO: disable when encrypting???
if (enableAsciiArmorOutput && enableSignature && !enableEncryption) {
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
} else {
signatureType = PGPSignature.BINARY_DOCUMENT;
}
ArmoredOutputStream armorOut = null;
OutputStream out;
OutputStream encryptionOut = null;
if (enableAsciiArmorOutput) {
armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut;
} else {
out = mOutStream;
}
PGPSecretKey signingKey = null;
PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null;
if (enableSignature) {
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
if (signingKey == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
if (signaturePassphrase == null) {
throw new PgpGeneralException(
mContext.getString(R.string.error_no_signature_passphrase));
}
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
mContext.getString(R.string.error_could_not_extract_private_key));
}
}
updateProgress(R.string.progress_preparing_streams, 5, 100);
// encrypt and compress input file content
if (enableEncryption) {
// has Integrity packet enabled!
JcePGPDataEncryptorBuilder encryptorBuilder =
new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
.setWithIntegrityPacket(true);
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
if (encryptionKeyIds.length == 0) {
// Symmetric encryption
Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray());
cPk.addMethod(symmetricEncryptionGenerator);
} else {
// Asymmetric encryption
for (long id : encryptionKeyIds) {
PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
if (key != null) {
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
new JcePublicKeyKeyEncryptionMethodGenerator(key);
cPk.addMethod(pubKeyEncryptionGenerator);
}
}
}
encryptionOut = cPk.open(out, new byte[1 << 16]);
}
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
if (enableSignature) {
updateProgress(R.string.progress_preparing_signature, 10, 100);
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
if (signatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(signatureType, signaturePrivateKey);
} else {
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(signatureType, signaturePrivateKey);
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, userId);
signatureGenerator.setHashedSubpackets(spGen.generate());
}
}
PGPCompressedDataGenerator compressGen = null;
OutputStream pOut;
if (enableEncryption) {
BCPGOutputStream bcpgOut;
if (enableCompression) {
compressGen = new PGPCompressedDataGenerator(compressionId);
bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
} else {
bcpgOut = new BCPGOutputStream(encryptionOut);
}
if (enableSignature) {
if (signatureForceV3) {
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
} else {
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
}
}
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
// file name not needed, so empty string
pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
new byte[1 << 16]);
updateProgress(R.string.progress_encrypting, 20, 100);
long progress = 0;
int n;
byte[] buffer = new byte[1 << 16];
InputStream in = mData.getInputStream();
while ((n = in.read(buffer)) > 0) {
pOut.write(buffer, 0, n);
// update signature buffer if signature is requested
if (enableSignature) {
if (signatureForceV3) {
signatureV3Generator.update(buffer, 0, n);
} else {
signatureGenerator.update(buffer, 0, n);
}
}
progress += n;
if (mData.getSize() != 0) {
updateProgress((int) (20 + (95 - 20) * progress / mData.getSize()), 100);
}
}
literalGen.close();
} else if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
/* sign-only of ascii text */
updateProgress(R.string.progress_signing, 40, 100);
// write directly on armor output stream
armorOut.beginClearText(signatureHashAlgorithm);
InputStream in = mData.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
final byte[] newline = "\r\n".getBytes("UTF-8");
if (signatureForceV3) {
processLine(reader.readLine(), armorOut, signatureV3Generator);
} else {
processLine(reader.readLine(), armorOut, signatureGenerator);
}
while (true) {
String line = reader.readLine();
if (line == null) {
armorOut.write(newline);
break;
}
armorOut.write(newline);
if (signatureForceV3) {
signatureV3Generator.update(newline);
processLine(line, armorOut, signatureV3Generator);
} else {
signatureGenerator.update(newline);
processLine(line, armorOut, signatureGenerator);
}
}
armorOut.endClearText();
pOut = new BCPGOutputStream(armorOut);
} else {
// TODO: implement sign-only for files!
pOut = null;
Log.e(Constants.TAG, "not supported!");
}
if (enableSignature) {
updateProgress(R.string.progress_generating_signature, 95, 100);
if (signatureForceV3) {
signatureV3Generator.generate().encode(pOut);
} else {
signatureGenerator.generate().encode(pOut);
}
}
// closing outputs...
if (enableEncryption) {
encryptionOut.close();
if (enableCompression) {
compressGen.close();
}
}
if (enableAsciiArmorOutput) {
armorOut.close();
}
updateProgress(R.string.progress_done, 100, 100);
}
public void signText(long signatureKeyId, String signaturePassphrase,
int signatureHashAlgorithm, boolean forceV3Signature)
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException {
try {
signAndEncrypt(true, 0, null, null, 0, signatureKeyId, signatureHashAlgorithm, forceV3Signature, signaturePassphrase);
} catch (NoSuchProviderException e) {
e.printStackTrace();
}
}
// TODO: merge this into signAndEncrypt method!
public void generateSignature(boolean armored, boolean binary, long signatureKeyId,
String signaturePassPhrase, int hashAlgorithm, boolean forceV3Signature)
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException {
OutputStream out;
if (armored) {
// Ascii Armor (Radix-64)
ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut;
} else {
out = mOutStream;
}
if (signatureKeyId == 0) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
}
PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
if (signingKey == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
if (signaturePassPhrase == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassPhrase.toCharArray());
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
mContext.getString(R.string.error_could_not_extract_private_key));
}
updateProgress(R.string.progress_preparing_streams, 0, 100);
updateProgress(R.string.progress_preparing_signature, 30, 100);
int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
if (binary) {
type = PGPSignature.BINARY_DOCUMENT;
}
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
.getPublicKey().getAlgorithm(), hashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
if (forceV3Signature) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(type, signaturePrivateKey);
} else {
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(type, signaturePrivateKey);
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
spGen.setSignerUserID(false, userId);
signatureGenerator.setHashedSubpackets(spGen.generate());
}
updateProgress(R.string.progress_signing, 40, 100);
InputStream inStream = mData.getInputStream();
if (binary) {
byte[] buffer = new byte[1 << 16];
int n = 0;
while ((n = inStream.read(buffer)) > 0) {
if (forceV3Signature) {
signatureV3Generator.update(buffer, 0, n);
} else {
signatureGenerator.update(buffer, 0, n);
}
}
} else {
final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
final byte[] newline = "\r\n".getBytes("UTF-8");
String line;
while ((line = reader.readLine()) != null) {
if (forceV3Signature) {
processLine(line, null, signatureV3Generator);
signatureV3Generator.update(newline);
} else {
processLine(line, null, signatureGenerator);
signatureGenerator.update(newline);
}
}
}
BCPGOutputStream bOut = new BCPGOutputStream(out);
if (forceV3Signature) {
signatureV3Generator.generate().encode(bOut);
} else {
signatureGenerator.generate().encode(bOut);
}
out.close();
mOutStream.close();
updateProgress(R.string.progress_done, 100, 100);
}
public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
throws PgpGeneralException, IOException {
InputStream in = PGPUtil.getDecoderStream(inputStream);
@ -528,8 +152,8 @@ public class PgpOperation {
throw new PgpGeneralException(mContext.getString(R.string.error_invalid_data));
}
InputStream clear = null;
PGPEncryptedData encryptedData = null;
InputStream clear;
PGPEncryptedData encryptedData;
currentProgress += 5;
@ -694,12 +318,13 @@ public class PgpOperation {
} else if (encryptedData.isIntegrityProtected()) {
endProgress = 95;
}
int n = 0;
int done = 0;
int n;
// int progress = 0;
long startPos = mData.getStreamPosition();
while ((n = dataIn.read(buffer)) > 0) {
out.write(buffer, 0, n);
done += n;
// progress += n;
if (signature != null) {
try {
signature.update(buffer, 0, n);
@ -709,9 +334,10 @@ public class PgpOperation {
signature = null;
}
}
// TODO: dead code?!
// unknown size, but try to at least have a moving, slowing down progress bar
currentProgress = startProgress + (endProgress - startProgress) * done
/ (done + 100000);
// currentProgress = startProgress + (endProgress - startProgress) * progress
// / (progress + 100000);
if (mData.getSize() - startPos == 0) {
currentProgress = endProgress;
} else {
@ -740,13 +366,15 @@ public class PgpOperation {
if (encryptedData.verify()) {
// passed
Log.d(Constants.TAG, "Integrity verification: success!");
} else {
// failed
Log.d(Constants.TAG, "Integrity verification: failed!");
throw new PgpGeneralException(mContext.getString(R.string.error_integrity_check_failed));
}
} else {
// no integrity check
Log.e(Constants.TAG, "No integrity check!");
Log.e(Constants.TAG, "Encrypted data was not integrity protected!");
}
updateProgress(R.string.progress_done, 100, 100);
@ -953,56 +581,6 @@ public class PgpOperation {
return primkeyBinding_isok;
}
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException {
if (pLine == null) {
return;
}
final char[] chars = pLine.toCharArray();
int len = chars.length;
while (len > 0) {
if (!Character.isWhitespace(chars[len - 1])) {
break;
}
len--;
}
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
if (pArmoredOutput != null) {
pArmoredOutput.write(data);
}
pSignatureGenerator.update(data);
}
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
final PGPV3SignatureGenerator pSignatureGenerator) throws IOException,
SignatureException {
if (pLine == null) {
return;
}
final char[] chars = pLine.toCharArray();
int len = chars.length;
while (len > 0) {
if (!Character.isWhitespace(chars[len - 1])) {
break;
}
len--;
}
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
if (pArmoredOutput != null) {
pArmoredOutput.write(data);
}
pSignatureGenerator.update(data);
}
// taken from ClearSignedFileProcessor in BC
private static void processLine(PGPSignature sig, byte[] line) throws SignatureException,

View File

@ -0,0 +1,584 @@
/*
* Copyright (C) 2012-2014 Dominik Schürmann <dominik@dominikschuermann.de>
* Copyright (C) 2010 Thialfihar <thi@thialfihar.org>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sufficientlysecure.keychain.pgp;
import android.content.Context;
import org.spongycastle.bcpg.ArmoredOutputStream;
import org.spongycastle.bcpg.BCPGOutputStream;
import org.spongycastle.openpgp.PGPCompressedDataGenerator;
import org.spongycastle.openpgp.PGPEncryptedDataGenerator;
import org.spongycastle.openpgp.PGPException;
import org.spongycastle.openpgp.PGPLiteralData;
import org.spongycastle.openpgp.PGPLiteralDataGenerator;
import org.spongycastle.openpgp.PGPPrivateKey;
import org.spongycastle.openpgp.PGPPublicKey;
import org.spongycastle.openpgp.PGPSecretKey;
import org.spongycastle.openpgp.PGPSecretKeyRing;
import org.spongycastle.openpgp.PGPSignature;
import org.spongycastle.openpgp.PGPSignatureGenerator;
import org.spongycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.spongycastle.openpgp.PGPV3SignatureGenerator;
import org.spongycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.spongycastle.openpgp.operator.jcajce.JcaPGPContentSignerBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePBEKeyEncryptionMethodGenerator;
import org.spongycastle.openpgp.operator.jcajce.JcePBESecretKeyDecryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePGPDataEncryptorBuilder;
import org.spongycastle.openpgp.operator.jcajce.JcePublicKeyKeyEncryptionMethodGenerator;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.R;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
import org.sufficientlysecure.keychain.util.InputData;
import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressDialogUpdater;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SignatureException;
import java.util.Date;
/**
* This class uses a Builder pattern!
*/
public class PgpOperationOutgoing {
private Context context;
private InputData data;
private OutputStream outStream;
private ProgressDialogUpdater progress;
private boolean enableAsciiArmorOutput;
private int compressionId;
private long[] encryptionKeyIds;
private String encryptionPassphrase;
private int symmetricEncryptionAlgorithm;
private long signatureKeyId;
private int signatureHashAlgorithm;
private boolean signatureForceV3;
private String signaturePassphrase;
private PgpOperationOutgoing(Builder builder) {
// private Constructor can only be called from Builder
this.context = builder.context;
this.data = builder.data;
this.outStream = builder.outStream;
this.progress = builder.progress;
this.enableAsciiArmorOutput = builder.enableAsciiArmorOutput;
this.compressionId = builder.compressionId;
this.encryptionKeyIds = builder.encryptionKeyIds;
this.encryptionPassphrase = builder.encryptionPassphrase;
this.symmetricEncryptionAlgorithm = builder.symmetricEncryptionAlgorithm;
this.signatureKeyId = builder.signatureKeyId;
this.signatureHashAlgorithm = builder.signatureHashAlgorithm;
this.signatureForceV3 = builder.signatureForceV3;
this.signaturePassphrase = builder.signaturePassphrase;
}
public static class Builder {
// mandatory parameter
private Context context;
private InputData data;
private OutputStream outStream;
// optional
private ProgressDialogUpdater progress = null;
private boolean enableAsciiArmorOutput = false;
private int compressionId = Id.choice.compression.none;
private long[] encryptionKeyIds = new long[0];
private String encryptionPassphrase = null;
private int symmetricEncryptionAlgorithm = 0;
private long signatureKeyId = Id.key.none;
private int signatureHashAlgorithm = 0;
private boolean signatureForceV3 = false;
private String signaturePassphrase = null;
public Builder(Context context, InputData data, OutputStream outStream) {
this.context = context;
this.data = data;
this.outStream = outStream;
}
public Builder progress(ProgressDialogUpdater progress) {
this.progress = progress;
return this;
}
public Builder enableAsciiArmorOutput(boolean enableAsciiArmorOutput) {
this.enableAsciiArmorOutput = enableAsciiArmorOutput;
return this;
}
public Builder compressionId(int compressionId) {
this.compressionId = compressionId;
return this;
}
public Builder encryptionKeyIds(long[] encryptionKeyIds) {
this.encryptionKeyIds = encryptionKeyIds;
return this;
}
public Builder encryptionPassphrase(String encryptionPassphrase) {
this.encryptionPassphrase = encryptionPassphrase;
return this;
}
public Builder symmetricEncryptionAlgorithm(int symmetricEncryptionAlgorithm) {
this.symmetricEncryptionAlgorithm = symmetricEncryptionAlgorithm;
return this;
}
public Builder signatureKeyId(long signatureKeyId) {
this.signatureKeyId = signatureKeyId;
return this;
}
public Builder signatureHashAlgorithm(int signatureHashAlgorithm) {
this.signatureHashAlgorithm = signatureHashAlgorithm;
return this;
}
public Builder signatureForceV3(boolean signatureForceV3) {
this.signatureForceV3 = signatureForceV3;
return this;
}
public Builder signaturePassphrase(String signaturePassphrase) {
this.signaturePassphrase = signaturePassphrase;
return this;
}
public PgpOperationOutgoing build() {
return new PgpOperationOutgoing(this);
}
}
public void updateProgress(int message, int current, int total) {
if (progress != null) {
progress.setProgress(message, current, total);
}
}
public void updateProgress(int current, int total) {
if (progress != null) {
progress.setProgress(current, total);
}
}
public void signAndEncrypt()
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
if (encryptionKeyIds == null) {
encryptionKeyIds = new long[0];
}
boolean enableSignature = signatureKeyId != Id.key.none;
boolean enableCompression = compressionId != Id.choice.compression.none;
boolean enableEncryption = encryptionKeyIds.length != 0 || encryptionPassphrase != null;
int signatureType;
if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
} else {
signatureType = PGPSignature.BINARY_DOCUMENT;
}
ArmoredOutputStream armorOut = null;
OutputStream out;
OutputStream encryptionOut = null;
if (enableAsciiArmorOutput) {
armorOut = new ArmoredOutputStream(outStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
out = armorOut;
} else {
out = outStream;
}
PGPSecretKey signingKey = null;
PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null;
if (enableSignature) {
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
if (signingKey == null) {
throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
}
if (signaturePassphrase == null) {
throw new PgpGeneralException(
context.getString(R.string.error_no_signature_passphrase));
}
updateProgress(R.string.progress_extracting_signature_key, 0, 100);
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
context.getString(R.string.error_could_not_extract_private_key));
}
}
updateProgress(R.string.progress_preparing_streams, 5, 100);
// encrypt and compress input file content
if (enableEncryption) {
// has Integrity packet enabled!
JcePGPDataEncryptorBuilder encryptorBuilder =
new JcePGPDataEncryptorBuilder(symmetricEncryptionAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
.setWithIntegrityPacket(true);
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
if (encryptionKeyIds.length == 0) {
// Symmetric encryption
Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator =
new JcePBEKeyEncryptionMethodGenerator(encryptionPassphrase.toCharArray());
cPk.addMethod(symmetricEncryptionGenerator);
} else {
// Asymmetric encryption
for (long id : encryptionKeyIds) {
PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(context, id);
if (key != null) {
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator =
new JcePublicKeyKeyEncryptionMethodGenerator(key);
cPk.addMethod(pubKeyEncryptionGenerator);
}
}
}
encryptionOut = cPk.open(out, new byte[1 << 16]);
}
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
if (enableSignature) {
updateProgress(R.string.progress_preparing_signature, 10, 100);
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
if (signatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(signatureType, signaturePrivateKey);
} else {
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(signatureType, signaturePrivateKey);
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
spGen.setSignerUserID(false, userId);
signatureGenerator.setHashedSubpackets(spGen.generate());
}
}
PGPCompressedDataGenerator compressGen = null;
OutputStream pOut;
if (enableEncryption) {
BCPGOutputStream bcpgOut;
if (enableCompression) {
compressGen = new PGPCompressedDataGenerator(compressionId);
bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
} else {
bcpgOut = new BCPGOutputStream(encryptionOut);
}
if (enableSignature) {
if (signatureForceV3) {
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
} else {
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
}
}
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
// file name not needed, so empty string
pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
new byte[1 << 16]);
updateProgress(R.string.progress_encrypting, 20, 100);
long progress = 0;
int n;
byte[] buffer = new byte[1 << 16];
InputStream in = data.getInputStream();
while ((n = in.read(buffer)) > 0) {
pOut.write(buffer, 0, n);
// update signature buffer if signature is requested
if (enableSignature) {
if (signatureForceV3) {
signatureV3Generator.update(buffer, 0, n);
} else {
signatureGenerator.update(buffer, 0, n);
}
}
progress += n;
if (data.getSize() != 0) {
updateProgress((int) (20 + (95 - 20) * progress / data.getSize()), 100);
}
}
literalGen.close();
} else if (enableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
/* sign-only of ascii text */
updateProgress(R.string.progress_signing, 40, 100);
// write directly on armor output stream
armorOut.beginClearText(signatureHashAlgorithm);
InputStream in = data.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
final byte[] newline = "\r\n".getBytes("UTF-8");
if (signatureForceV3) {
processLine(reader.readLine(), armorOut, signatureV3Generator);
} else {
processLine(reader.readLine(), armorOut, signatureGenerator);
}
while (true) {
String line = reader.readLine();
if (line == null) {
armorOut.write(newline);
break;
}
armorOut.write(newline);
if (signatureForceV3) {
signatureV3Generator.update(newline);
processLine(line, armorOut, signatureV3Generator);
} else {
signatureGenerator.update(newline);
processLine(line, armorOut, signatureGenerator);
}
}
armorOut.endClearText();
pOut = new BCPGOutputStream(armorOut);
} else {
// TODO: implement sign-only for files!
pOut = null;
Log.e(Constants.TAG, "not supported!");
}
if (enableSignature) {
updateProgress(R.string.progress_generating_signature, 95, 100);
if (signatureForceV3) {
signatureV3Generator.generate().encode(pOut);
} else {
signatureGenerator.generate().encode(pOut);
}
}
// closing outputs...
if (enableEncryption) {
encryptionOut.close();
if (enableCompression) {
compressGen.close();
}
}
if (enableAsciiArmorOutput) {
armorOut.close();
}
updateProgress(R.string.progress_done, 100, 100);
}
// TODO: merge this into signAndEncrypt method!
public void generateSignature()
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException {
OutputStream out;
if (enableAsciiArmorOutput) {
// Ascii Armor (Radix-64)
ArmoredOutputStream armorOut = new ArmoredOutputStream(outStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(context));
out = armorOut;
} else {
out = outStream;
}
if (signatureKeyId == 0) {
throw new PgpGeneralException(context.getString(R.string.error_no_signature_key));
}
PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(context, signatureKeyId);
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(context, signatureKeyId);
if (signingKey == null) {
throw new PgpGeneralException(context.getString(R.string.error_signature_failed));
}
if (signaturePassphrase == null) {
throw new PgpGeneralException(context.getString(R.string.error_no_signature_passphrase));
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
context.getString(R.string.error_could_not_extract_private_key));
}
updateProgress(R.string.progress_preparing_streams, 0, 100);
updateProgress(R.string.progress_preparing_signature, 30, 100);
int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
// if (binary) {
// type = PGPSignature.BINARY_DOCUMENT;
// }
// content signer based on signing key algorithm and chosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
if (signatureForceV3) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(type, signaturePrivateKey);
} else {
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(type, signaturePrivateKey);
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
spGen.setSignerUserID(false, userId);
signatureGenerator.setHashedSubpackets(spGen.generate());
}
updateProgress(R.string.progress_signing, 40, 100);
InputStream inStream = data.getInputStream();
// if (binary) {
// byte[] buffer = new byte[1 << 16];
// int n = 0;
// while ((n = inStream.read(buffer)) > 0) {
// if (signatureForceV3) {
// signatureV3Generator.update(buffer, 0, n);
// } else {
// signatureGenerator.update(buffer, 0, n);
// }
// }
// } else {
final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
final byte[] newline = "\r\n".getBytes("UTF-8");
String line;
while ((line = reader.readLine()) != null) {
if (signatureForceV3) {
processLine(line, null, signatureV3Generator);
signatureV3Generator.update(newline);
} else {
processLine(line, null, signatureGenerator);
signatureGenerator.update(newline);
}
}
// }
BCPGOutputStream bOut = new BCPGOutputStream(out);
if (signatureForceV3) {
signatureV3Generator.generate().encode(bOut);
} else {
signatureGenerator.generate().encode(bOut);
}
out.close();
outStream.close();
updateProgress(R.string.progress_done, 100, 100);
}
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException {
if (pLine == null) {
return;
}
final char[] chars = pLine.toCharArray();
int len = chars.length;
while (len > 0) {
if (!Character.isWhitespace(chars[len - 1])) {
break;
}
len--;
}
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
if (pArmoredOutput != null) {
pArmoredOutput.write(data);
}
pSignatureGenerator.update(data);
}
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
final PGPV3SignatureGenerator pSignatureGenerator) throws IOException,
SignatureException {
if (pLine == null) {
return;
}
final char[] chars = pLine.toCharArray();
int len = chars.length;
while (len > 0) {
if (!Character.isWhitespace(chars[len - 1])) {
break;
}
len--;
}
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
if (pArmoredOutput != null) {
pArmoredOutput.write(data);
}
pSignatureGenerator.update(data);
}
private static boolean isWhiteSpace(byte b) {
return b == '\r' || b == '\n' || b == '\t' || b == ' ';
}
}

View File

@ -46,7 +46,8 @@ import org.sufficientlysecure.keychain.pgp.PgpConversionHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpImportExport;
import org.sufficientlysecure.keychain.pgp.PgpKeyOperation;
import org.sufficientlysecure.keychain.pgp.PgpOperation;
import org.sufficientlysecure.keychain.pgp.PgpOperationIncoming;
import org.sufficientlysecure.keychain.pgp.PgpOperationOutgoing;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.KeychainContract.DataStream;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@ -316,27 +317,41 @@ public class KeychainIntentService extends IntentService implements ProgressDial
}
/* Operation */
PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
PgpOperationOutgoing.Builder builder =
new PgpOperationOutgoing.Builder(this, inputData, outStream);
builder.progress(this);
if (generateSignature) {
Log.d(Constants.TAG, "generating signature...");
operation.generateSignature(useAsciiArmor, false, secretKeyId,
PassphraseCacheService.getCachedPassphrase(this, secretKeyId),
Preferences.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures());
builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().generateSignature();
} else if (signOnly) {
Log.d(Constants.TAG, "sign only...");
operation.signText(secretKeyId, PassphraseCacheService.getCachedPassphrase(
this, secretKeyId), Preferences.getPreferences(this)
.getDefaultHashAlgorithm(), Preferences.getPreferences(this)
.getForceV3Signatures());
builder.enableAsciiArmorOutput(useAsciiArmor)
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().signAndEncrypt();
} else {
Log.d(Constants.TAG, "encrypt...");
operation.signAndEncrypt(useAsciiArmor, compressionId, encryptionKeyIds,
encryptionPassphrase, Preferences.getPreferences(this)
.getDefaultEncryptionAlgorithm(), secretKeyId, Preferences
.getPreferences(this).getDefaultHashAlgorithm(), Preferences
.getPreferences(this).getForceV3Signatures(),
PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.enableAsciiArmorOutput(useAsciiArmor)
.compressionId(compressionId)
.symmetricEncryptionAlgorithm(Preferences.getPreferences(this).getDefaultEncryptionAlgorithm())
.signatureForceV3(Preferences.getPreferences(this).getForceV3Signatures())
.encryptionKeyIds(encryptionKeyIds)
.encryptionPassphrase(encryptionPassphrase)
.signatureKeyId(secretKeyId)
.signatureHashAlgorithm(Preferences.getPreferences(this).getDefaultHashAlgorithm())
.signaturePassphrase(PassphraseCacheService.getCachedPassphrase(this, secretKeyId));
builder.build().signAndEncrypt();
}
outStream.close();
@ -466,7 +481,7 @@ public class KeychainIntentService extends IntentService implements ProgressDial
// verifyText and decrypt returning additional resultData values for the
// verification of signatures
PgpOperation operation = new PgpOperation(this, this, inputData, outStream);
PgpOperationIncoming operation = new PgpOperationIncoming(this, this, inputData, outStream);
if (signedOnly) {
resultData = operation.verifyText();
} else {

View File

@ -29,12 +29,11 @@ import org.openintents.openpgp.IOpenPgpService;
import org.openintents.openpgp.OpenPgpError;
import org.openintents.openpgp.OpenPgpSignatureResult;
import org.openintents.openpgp.util.OpenPgpConstants;
import org.spongycastle.openpgp.PGPUtil;
import org.spongycastle.util.Arrays;
import org.sufficientlysecure.keychain.Constants;
import org.sufficientlysecure.keychain.Id;
import org.sufficientlysecure.keychain.helper.Preferences;
import org.sufficientlysecure.keychain.pgp.PgpOperation;
import org.sufficientlysecure.keychain.pgp.PgpOperationOutgoing;
import org.sufficientlysecure.keychain.pgp.PgpOperationIncoming;
import org.sufficientlysecure.keychain.provider.KeychainContract;
import org.sufficientlysecure.keychain.service.KeychainIntentService;
import org.sufficientlysecure.keychain.service.PassphraseCacheService;
@ -162,9 +161,14 @@ public class OpenPgpService extends RemoteService {
long inputLength = is.available();
InputData inputData = new InputData(is, inputLength);
PgpOperation operation = new PgpOperation(getContext(), null, inputData, os);
operation.signText(appSettings.getKeyId(), passphrase, appSettings.getHashAlgorithm(),
Preferences.getPreferences(this).getForceV3Signatures());
// sign-only
PgpOperationOutgoing.Builder builder = new PgpOperationOutgoing.Builder(getContext(), inputData, os);
builder.enableAsciiArmorOutput(true)
.signatureHashAlgorithm(appSettings.getHashAlgorithm())
.signatureForceV3(false)
.signatureKeyId(appSettings.getKeyId())
.signaturePassphrase(passphrase);
builder.build().signAndEncrypt();
} finally {
is.close();
os.close();
@ -223,7 +227,14 @@ public class OpenPgpService extends RemoteService {
long inputLength = is.available();
InputData inputData = new InputData(is, inputLength);
PgpOperation operation = new PgpOperation(getContext(), null, inputData, os);
PgpOperationOutgoing.Builder builder = new PgpOperationOutgoing.Builder(getContext(), inputData, os);
builder.enableAsciiArmorOutput(asciiArmor)
.compressionId(appSettings.getCompression())
.symmetricEncryptionAlgorithm(appSettings.getEncryptionAlgorithm())
.signatureHashAlgorithm(appSettings.getHashAlgorithm())
.signatureForceV3(false)
.encryptionKeyIds(keyIds);
if (sign) {
String passphrase;
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
@ -239,15 +250,14 @@ public class OpenPgpService extends RemoteService {
}
// sign and encrypt
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
appSettings.getHashAlgorithm(), true, passphrase);
builder.signatureKeyId(appSettings.getKeyId())
.signaturePassphrase(passphrase);
} else {
// encrypt only
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
appSettings.getEncryptionAlgorithm(), Id.key.none,
appSettings.getHashAlgorithm(), true, null);
builder.signatureKeyId(Id.key.none);
}
// execute PGP operation!
builder.build().signAndEncrypt();
} finally {
is.close();
os.close();
@ -344,7 +354,7 @@ public class OpenPgpService extends RemoteService {
// inputStream2.reset();
// }
// secretKeyId = Id.key.symmetric;
// if (!PgpOperation.hasSymmetricEncryption(this, inputStream2)) {
// if (!PgpOperationIncoming.hasSymmetricEncryption(this, inputStream2)) {
// throw new PgpGeneralException(
// getString(R.string.error_no_known_encryption_found));
// }
@ -374,7 +384,7 @@ public class OpenPgpService extends RemoteService {
Bundle outputBundle;
PgpOperation operation = new PgpOperation(getContext(), null, inputData, os);
PgpOperationIncoming operation = new PgpOperationIncoming(getContext(), null, inputData, os);
if (signedOnly) {
outputBundle = operation.verifyText();
} else {

View File

@ -34,7 +34,7 @@ import org.sufficientlysecure.keychain.helper.ActionBarHelper;
import org.sufficientlysecure.keychain.helper.FileHelper;
import org.sufficientlysecure.keychain.pgp.PgpHelper;
import org.sufficientlysecure.keychain.pgp.PgpKeyHelper;
import org.sufficientlysecure.keychain.pgp.PgpOperation;
import org.sufficientlysecure.keychain.pgp.PgpOperationIncoming;
import org.sufficientlysecure.keychain.pgp.exception.NoAsymmetricEncryptionException;
import org.sufficientlysecure.keychain.pgp.exception.PgpGeneralException;
import org.sufficientlysecure.keychain.provider.ProviderHelper;
@ -546,7 +546,7 @@ public class DecryptActivity extends DrawerActivity {
inStream.reset();
}
mSecretKeyId = Id.key.symmetric;
if (!PgpOperation.hasSymmetricEncryption(this, inStream)) {
if (!PgpOperationIncoming.hasSymmetricEncryption(this, inStream)) {
throw new PgpGeneralException(
getString(R.string.error_no_known_encryption_found));
}