merge internal signText and signAndEncrypt methods

This commit is contained in:
Dominik Schürmann 2014-02-18 22:47:26 +01:00
parent 708d0c9a5a
commit 9b4245739e
3 changed files with 201 additions and 239 deletions

View File

@ -118,9 +118,10 @@ public class PgpOperation {
}
}
public void signAndEncrypt(boolean useAsciiArmor, int compression, long[] encryptionKeyIds,
String encryptionPassphrase, int symmetricEncryptionAlgorithm, long signatureKeyId,
int signatureHashAlgorithm, boolean signatureForceV3, String signaturePassphrase)
public void signAndEncrypt(boolean enableAsciiArmor, int compressionId, long[] encryptionKeyIds,
String encryptionPassphrase, int symmetricEncryptionAlgorithm,
long signatureKeyId, int signatureHashAlgorithm,
boolean signatureForceV3, String signaturePassphrase)
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
NoSuchAlgorithmException, SignatureException {
@ -128,26 +129,34 @@ public class PgpOperation {
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 (enableAsciiArmor && enableSignature && !enableEncryption) {
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
} else {
signatureType = PGPSignature.BINARY_DOCUMENT;
}
ArmoredOutputStream armorOut = null;
OutputStream out = null;
OutputStream encryptOut = null;
if (useAsciiArmor) {
OutputStream out;
OutputStream encryptionOut = null;
if (enableAsciiArmor) {
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 (encryptionKeyIds.length == 0 && encryptionPassphrase == null) {
throw new PgpGeneralException(
mContext.getString(R.string.error_no_encryption_keys_or_passphrase));
}
if (signatureKeyId != Id.key.none) {
if (enableSignature) {
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
if (signingKey == null) {
@ -172,6 +181,7 @@ public class PgpOperation {
updateProgress(R.string.progress_preparing_streams, 5, 100);
// encrypt and compress input file content
if (enableEncryption) {
JcePGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(
symmetricEncryptionAlgorithm).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
.setWithIntegrityPacket(true);
@ -197,25 +207,25 @@ public class PgpOperation {
}
}
}
encryptOut = cPk.open(out, new byte[1 << 16]);
encryptionOut = cPk.open(out, new byte[1 << 16]);
}
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
if (signatureKeyId != Id.key.none) {
if (enableSignature) {
updateProgress(R.string.progress_preparing_signature, 10, 100);
// content signer based on signing key algorithm and choosen hash algorithm
// 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(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
signatureV3Generator.init(signatureType, signaturePrivateKey);
} else {
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
signatureGenerator.init(signatureType, signaturePrivateKey);
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper
.getMasterKey(signingKeyRing));
@ -226,14 +236,17 @@ public class PgpOperation {
}
PGPCompressedDataGenerator compressGen = null;
BCPGOutputStream bcpgOut = null;
if (compression == Id.choice.compression.none) {
bcpgOut = new BCPGOutputStream(encryptOut);
OutputStream pOut;
if (enableEncryption) {
BCPGOutputStream bcpgOut;
if (enableCompression) {
compressGen = new PGPCompressedDataGenerator(compressionId);
bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
} else {
compressGen = new PGPCompressedDataGenerator(compression);
bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
bcpgOut = new BCPGOutputStream(encryptionOut);
}
if (signatureKeyId != Id.key.none) {
if (enableSignature) {
if (signatureForceV3) {
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
} else {
@ -243,127 +256,54 @@ public class PgpOperation {
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
// file name not needed, so empty string
OutputStream pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
pOut = literalGen.open(bcpgOut, PGPLiteralData.BINARY, "", new Date(),
new byte[1 << 16]);
updateProgress(R.string.progress_encrypting, 20, 100);
long done = 0;
int n = 0;
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);
if (signatureKeyId != Id.key.none) {
// update signature buffer if signature is requested
if (enableSignature) {
if (signatureForceV3) {
signatureV3Generator.update(buffer, 0, n);
} else {
signatureGenerator.update(buffer, 0, n);
}
}
done += n;
progress += n;
if (mData.getSize() != 0) {
updateProgress((int) (20 + (95 - 20) * done / mData.getSize()), 100);
updateProgress((int) (20 + (95 - 20) * progress / mData.getSize()), 100);
}
}
literalGen.close();
if (signatureKeyId != Id.key.none) {
updateProgress(R.string.progress_generating_signature, 95, 100);
if (signatureForceV3) {
signatureV3Generator.generate().encode(pOut);
} else {
signatureGenerator.generate().encode(pOut);
}
}
if (compressGen != null) {
compressGen.close();
}
encryptOut.close();
if (useAsciiArmor) {
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 {
ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
PGPSecretKey signingKey = null;
PGPSecretKeyRing signingKeyRing = null;
PGPPrivateKey signaturePrivateKey = null;
if (signatureKeyId == 0) {
armorOut.close();
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
}
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
if (signingKey == null) {
armorOut.close();
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
if (signaturePassphrase == null) {
armorOut.close();
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassphrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
armorOut.close();
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);
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
// content signer based on signing key algorithm and choosen hash algorithm
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
if (forceV3Signature) {
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
signatureV3Generator.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
} else {
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
signatureGenerator.init(PGPSignature.CANONICAL_TEXT_DOCUMENT, signaturePrivateKey);
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper.getMasterKey(signingKeyRing));
spGen.setSignerUserID(false, userId);
signatureGenerator.setHashedSubpackets(spGen.generate());
}
} else if (enableAsciiArmor && 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 inStream = mData.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
InputStream in = mData.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
final byte[] newline = "\r\n".getBytes("UTF-8");
if (forceV3Signature) {
if (signatureForceV3) {
processLine(reader.readLine(), armorOut, signatureV3Generator);
} else {
processLine(reader.readLine(), armorOut, signatureGenerator);
}
while (true) {
final String line = reader.readLine();
String line = reader.readLine();
if (line == null) {
armorOut.write(newline);
@ -371,7 +311,7 @@ public class PgpOperation {
}
armorOut.write(newline);
if (forceV3Signature) {
if (signatureForceV3) {
signatureV3Generator.update(newline);
processLine(line, armorOut, signatureV3Generator);
} else {
@ -382,44 +322,70 @@ public class PgpOperation {
armorOut.endClearText();
BCPGOutputStream bOut = new BCPGOutputStream(armorOut);
if (forceV3Signature) {
signatureV3Generator.generate().encode(bOut);
pOut = new BCPGOutputStream(armorOut);
} else {
signatureGenerator.generate().encode(bOut);
// 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 (enableAsciiArmor) {
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();
}
}
public void generateSignature(boolean armored, boolean binary, long signatureKeyId,
String signaturePassPhrase, int hashAlgorithm, boolean forceV3Signature)
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException {
OutputStream out = null;
// Ascii Armor (Base64)
ArmoredOutputStream armorOut = null;
OutputStream out;
if (armored) {
armorOut = new ArmoredOutputStream(mOutStream);
// Ascii Armor (Radix-64)
ArmoredOutputStream 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 (signatureKeyId == 0) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
}
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
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));
}
@ -430,7 +396,7 @@ public class PgpOperation {
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassPhrase.toCharArray());
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
if (signaturePrivateKey == null) {
throw new PgpGeneralException(
mContext.getString(R.string.error_could_not_extract_private_key));
@ -439,19 +405,18 @@ public class PgpOperation {
updateProgress(R.string.progress_preparing_signature, 30, 100);
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
if (binary) {
type = PGPSignature.BINARY_DOCUMENT;
}
// content signer based on signing key algorithm and choosen hash algorithm
// 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);
@ -482,13 +447,8 @@ public class PgpOperation {
final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
final byte[] newline = "\r\n".getBytes("UTF-8");
while (true) {
final String line = reader.readLine();
if (line == null) {
break;
}
String line;
while ((line = reader.readLine()) != null) {
if (forceV3Signature) {
processLine(line, null, signatureV3Generator);
signatureV3Generator.update(newline);
@ -508,8 +468,7 @@ public class PgpOperation {
out.close();
mOutStream.close();
if (mProgress != null)
mProgress.setProgress(R.string.progress_done, 100, 100);
updateProgress(R.string.progress_done, 100, 100);
}
public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
@ -548,11 +507,11 @@ public class PgpOperation {
}
Bundle returnData = new Bundle();
// automatically works with ascii armor input and binary
InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
PGPObjectFactory pgpF = new PGPObjectFactory(in);
PGPEncryptedDataList enc;
Object o = pgpF.nextObject();
long signatureKeyId = 0;
int currentProgress = 0;
updateProgress(R.string.progress_reading_data, currentProgress, 100);
@ -669,6 +628,7 @@ public class PgpOperation {
currentProgress += 10;
}
long signatureKeyId = 0;
if (dataChunk instanceof PGPOnePassSignatureList) {
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
@ -798,7 +758,7 @@ public class PgpOperation {
updateProgress(R.string.progress_done, 0, 100);
// mostly taken from ClearSignedFileProcessor
// mostly taken from pg/src/main/java/org/spongycastle/openpgp/examples/ClearSignedFileProcessor.java
ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
int lookAhead = readInputLine(lineOut, aIn);
byte[] lineSep = getLineSeparator();
@ -895,8 +855,7 @@ public class PgpOperation {
return returnData;
}
public boolean verifyKeyBinding(Context mContext, PGPSignature signature, PGPPublicKey signatureKey)
{
public boolean verifyKeyBinding(Context mContext, PGPSignature signature, PGPPublicKey signatureKey) {
long signatureKeyId = signature.getKeyID();
boolean keyBinding_isok = false;
String userId = null;
@ -914,8 +873,7 @@ public class PgpOperation {
return keyBinding_isok;
}
public boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey)
{
public boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
boolean subkeyBinding_isok = false;
boolean tmp_subkeyBinding_isok = false;
boolean primkeyBinding_isok = false;
@ -958,8 +916,7 @@ public class PgpOperation {
return (subkeyBinding_isok & primkeyBinding_isok);
}
private boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey)
{
private boolean verifyPrimaryBinding(PGPSignatureSubpacketVector Pkts, PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
boolean primkeyBinding_isok = false;
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);

View File

@ -29,6 +29,7 @@ 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;
@ -237,10 +238,12 @@ public class OpenPgpService extends RemoteService {
return passphraseBundle;
}
// sign and encrypt
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
appSettings.getHashAlgorithm(), true, passphrase);
} else {
// encrypt only
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
appSettings.getEncryptionAlgorithm(), Id.key.none,
appSettings.getHashAlgorithm(), true, null);
@ -271,7 +274,7 @@ public class OpenPgpService extends RemoteService {
OpenPgpSignatureResult sigResult = null;
try {
// PGPUtil.getDecoderStream(is)
// TODOs API 2.0:
// implement verify-only!
// fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream
@ -351,7 +354,7 @@ public class OpenPgpService extends RemoteService {
//
// Log.d(Constants.TAG, "secretKeyId " + secretKeyId);
// NOTE: currently this only gets the passphrase for the saved key
// NOTE: currently this only gets the passphrase for the key set for this client
String passphrase;
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
@ -375,8 +378,10 @@ public class OpenPgpService extends RemoteService {
if (signedOnly) {
outputBundle = operation.verifyText();
} else {
// BIG TODO: instead of trying to get the passphrase before
// pause stream when passphrase is missing and then resume
// Do we want to do this: instead of trying to get the passphrase before
// pause stream when passphrase is missing and then resume???
// TODO: this also decrypts with other secret keys without passphrase!!!
outputBundle = operation.decryptAndVerify(passphrase, false);
}

View File

@ -116,7 +116,7 @@
<string name="label_passphrase_cache_ttl">Passphrase Cache</string>
<string name="label_message_compression">Message Compression</string>
<string name="label_file_compression">File Compression</string>
<string name="label_force_v3_signature">Force V3 Signatures</string>
<string name="label_force_v3_signature">Force old OpenPGPv3 Signatures</string>
<string name="label_key_servers">Keyservers</string>
<string name="label_key_id">Key ID</string>
<string name="label_creation">Creation</string>