aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java16
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java2
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java94
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java47
-rw-r--r--OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java3
m---------extern/openpgp-api-lib0
6 files changed, 118 insertions, 44 deletions
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
index 57daf3430..c336f8502 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/operations/results/SignEncryptResult.java
@@ -37,6 +37,7 @@ public class SignEncryptResult extends OperationResult {
int mNfcAlgo;
Date mNfcTimestamp;
String mNfcPassphrase;
+ byte[] mDetachedSignature;
public long getKeyIdPassphraseNeeded() {
return mKeyIdPassphraseNeeded;
@@ -54,6 +55,10 @@ public class SignEncryptResult extends OperationResult {
mNfcPassphrase = passphrase;
}
+ public void setDetachedSignature(byte[] detachedSignature) {
+ mDetachedSignature = detachedSignature;
+ }
+
public long getNfcKeyId() {
return mNfcKeyId;
}
@@ -74,6 +79,10 @@ public class SignEncryptResult extends OperationResult {
return mNfcPassphrase;
}
+ public byte[] getDetachedSignature() {
+ return mDetachedSignature;
+ }
+
public boolean isPending() {
return (mResult & RESULT_PENDING) == RESULT_PENDING;
}
@@ -87,6 +96,7 @@ public class SignEncryptResult extends OperationResult {
mNfcHash = source.readInt() != 0 ? source.createByteArray() : null;
mNfcAlgo = source.readInt();
mNfcTimestamp = source.readInt() != 0 ? new Date(source.readLong()) : null;
+ mDetachedSignature = source.readInt() != 0 ? source.createByteArray() : null;
}
public int describeContents() {
@@ -108,6 +118,12 @@ public class SignEncryptResult extends OperationResult {
} else {
dest.writeInt(0);
}
+ if (mDetachedSignature != null) {
+ dest.writeInt(1);
+ dest.writeByteArray(mDetachedSignature);
+ } else {
+ dest.writeInt(0);
+ }
}
public static final Creator<SignEncryptResult> CREATOR = new Creator<SignEncryptResult>() {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
index 6ccadac2e..cffb09420 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/CanonicalizedSecretKey.java
@@ -247,7 +247,7 @@ public class CanonicalizedSecretKey extends CanonicalizedPublicKey {
int signatureType;
if (cleartext) {
- // for sign-only ascii text
+ // for sign-only ascii text (cleartext signature)
signatureType = PGPSignature.CANONICAL_TEXT_DOCUMENT;
} else {
signatureType = PGPSignature.BINARY_DOCUMENT;
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 3c3bcc890..5151667ed 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/pgp/PgpSignEncrypt.java
@@ -50,6 +50,7 @@ import org.sufficientlysecure.keychain.util.Log;
import org.sufficientlysecure.keychain.util.ProgressScaler;
import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
@@ -78,7 +79,8 @@ public class PgpSignEncrypt extends BaseOperation {
private int mSignatureHashAlgorithm;
private String mSignaturePassphrase;
private long mAdditionalEncryptId;
- private boolean mCleartextInput;
+ private boolean mCleartextSignature;
+ private boolean mDetachedSignature;
private String mOriginalFilename;
private boolean mFailOnMissingEncryptionKeyIds;
@@ -113,7 +115,8 @@ public class PgpSignEncrypt extends BaseOperation {
this.mSignatureHashAlgorithm = builder.mSignatureHashAlgorithm;
this.mSignaturePassphrase = builder.mSignaturePassphrase;
this.mAdditionalEncryptId = builder.mAdditionalEncryptId;
- this.mCleartextInput = builder.mCleartextInput;
+ this.mCleartextSignature = builder.mCleartextSignature;
+ this.mDetachedSignature = builder.mDetachedSignature;
this.mNfcSignedHash = builder.mNfcSignedHash;
this.mNfcCreationTimestamp = builder.mNfcCreationTimestamp;
this.mOriginalFilename = builder.mOriginalFilename;
@@ -140,7 +143,8 @@ public class PgpSignEncrypt extends BaseOperation {
private int mSignatureHashAlgorithm = 0;
private String mSignaturePassphrase = null;
private long mAdditionalEncryptId = Constants.key.none;
- private boolean mCleartextInput = false;
+ private boolean mCleartextSignature = false;
+ private boolean mDetachedSignature = false;
private String mOriginalFilename = "";
private byte[] mNfcSignedHash = null;
private Date mNfcCreationTimestamp = null;
@@ -222,14 +226,13 @@ public class PgpSignEncrypt extends BaseOperation {
return this;
}
- /**
- * TODO: test this option!
- *
- * @param cleartextInput
- * @return
- */
- public Builder setCleartextInput(boolean cleartextInput) {
- mCleartextInput = cleartextInput;
+ public Builder setCleartextSignature(boolean cleartextSignature) {
+ mCleartextSignature = cleartextSignature;
+ return this;
+ }
+
+ public Builder setDetachedSignature(boolean detachedSignature) {
+ mDetachedSignature = detachedSignature;
return this;
}
@@ -408,7 +411,7 @@ public class PgpSignEncrypt extends BaseOperation {
updateProgress(R.string.progress_preparing_signature, 4, 100);
try {
- boolean cleartext = mCleartextInput && mEnableAsciiArmorOutput && !enableEncryption;
+ boolean cleartext = mCleartextSignature && mEnableAsciiArmorOutput && !enableEncryption;
signatureGenerator = signingKey.getSignatureGenerator(
mSignatureHashAlgorithm, cleartext, mNfcSignedHash, mNfcCreationTimestamp);
} catch (PgpGeneralException e) {
@@ -424,6 +427,9 @@ public class PgpSignEncrypt extends BaseOperation {
OutputStream encryptionOut = null;
BCPGOutputStream bcpgOut;
+ ByteArrayOutputStream detachedByteOut = null;
+ BCPGOutputStream detachedBcpgOut = null;
+
try {
if (enableEncryption) {
@@ -452,7 +458,7 @@ public class PgpSignEncrypt extends BaseOperation {
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
char literalDataFormatTag;
- if (mCleartextInput) {
+ if (mCleartextSignature) {
literalDataFormatTag = PGPLiteralData.UTF8;
} else {
literalDataFormatTag = PGPLiteralData.BINARY;
@@ -482,7 +488,7 @@ public class PgpSignEncrypt extends BaseOperation {
literalGen.close();
indent -= 1;
- } else if (enableSignature && mCleartextInput && mEnableAsciiArmorOutput) {
+ } else if (enableSignature && mCleartextSignature && mEnableAsciiArmorOutput) {
/* cleartext signature: sign-only of ascii text */
updateProgress(R.string.progress_signing, 8, 100);
@@ -517,11 +523,44 @@ public class PgpSignEncrypt extends BaseOperation {
armorOut.endClearText();
pOut = new BCPGOutputStream(armorOut);
- } else if (enableSignature && !mCleartextInput) {
+ } else if (enableSignature && mDetachedSignature) {
+ /* detached signature */
+
+ updateProgress(R.string.progress_signing, 8, 100);
+ log.add(LogType.MSG_SE_SIGNING, indent);
+
+ InputStream in = mData.getInputStream();
+
+ // handle output stream separately for detached signatures
+ detachedByteOut = new ByteArrayOutputStream();
+ OutputStream detachedOut = detachedByteOut;
+ if (mEnableAsciiArmorOutput) {
+ detachedOut = new ArmoredOutputStream(detachedOut);
+ }
+ detachedBcpgOut = new BCPGOutputStream(detachedOut);
+
+ long alreadyWritten = 0;
+ int length;
+ byte[] buffer = new byte[1 << 16];
+ while ((length = in.read(buffer)) > 0) {
+ // pipe input stream directly into output stream, no changes to data
+ mOutStream.write(buffer, 0, length);
+
+ signatureGenerator.update(buffer, 0, length);
+
+ alreadyWritten += length;
+ if (mData.getSize() > 0) {
+ long progress = 100 * alreadyWritten / mData.getSize();
+ progressScaler.setProgress((int) progress, 100);
+ }
+ }
+
+ pOut = null;
+ } else if (enableSignature && !mCleartextSignature && !mDetachedSignature) {
/* sign-only binary (files/data stream) */
updateProgress(R.string.progress_signing, 8, 100);
- log.add(LogType.MSG_SE_ENCRYPTING, indent);
+ log.add(LogType.MSG_SE_SIGNING, indent);
InputStream in = mData.getInputStream();
@@ -556,13 +595,18 @@ public class PgpSignEncrypt extends BaseOperation {
literalGen.close();
} else {
pOut = null;
+ // TODO: Is this log right?
log.add(LogType.MSG_SE_CLEARSIGN_ONLY, indent);
}
if (enableSignature) {
updateProgress(R.string.progress_generating_signature, 95, 100);
try {
- signatureGenerator.generate().encode(pOut);
+ if (detachedBcpgOut != null) {
+ signatureGenerator.generate().encode(detachedBcpgOut);
+ } else {
+ signatureGenerator.generate().encode(pOut);
+ }
} catch (NfcSyncPGPContentSignerBuilder.NfcInteractionNeeded e) {
// this secret key diverts to a OpenPGP card, throw exception with hash that will be signed
log.add(LogType.MSG_SE_PENDING_NFC, indent);
@@ -607,10 +651,22 @@ public class PgpSignEncrypt extends BaseOperation {
updateProgress(R.string.progress_done, 100, 100);
log.add(LogType.MSG_SE_OK, indent);
- return new SignEncryptResult(SignEncryptResult.RESULT_OK, log);
-
+ SignEncryptResult result = new SignEncryptResult(SignEncryptResult.RESULT_OK, log);
+ if (detachedByteOut != null) {
+ try {
+ detachedByteOut.flush();
+ detachedByteOut.close();
+ } catch (IOException e) {
+ // silently catch
+ }
+ result.setDetachedSignature(detachedByteOut.toByteArray());
+ }
+ return result;
}
+ /**
+ * Remove whitespaces on line endings
+ */
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
final PGPSignatureGenerator pSignatureGenerator)
throws IOException, SignatureException {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
index a5813567a..478013f55 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/remote/OpenPgpService.java
@@ -222,9 +222,10 @@ public class OpenPgpService extends RemoteService {
}
private Intent signImpl(Intent data, ParcelFileDescriptor input,
- ParcelFileDescriptor output, AccountSettings accSettings) {
+ ParcelFileDescriptor output, AccountSettings accSettings,
+ boolean cleartextSign) {
try {
- boolean asciiArmor = data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
+ boolean asciiArmor = cleartextSign || data.getBooleanExtra(OpenPgpApi.EXTRA_REQUEST_ASCII_ARMOR, true);
byte[] nfcSignedHash = data.getByteArrayExtra(OpenPgpApi.EXTRA_NFC_SIGNED_HASH);
if (nfcSignedHash != null) {
@@ -284,6 +285,8 @@ public class OpenPgpService extends RemoteService {
inputData, os
);
builder.setEnableAsciiArmorOutput(asciiArmor)
+ .setCleartextSignature(cleartextSign)
+ .setDetachedSignature(!cleartextSign)
.setVersionHeader(PgpHelper.getVersionForHeader(this))
.setSignatureHashAlgorithm(accSettings.getHashAlgorithm())
.setSignatureMasterKeyId(accSettings.getKeyId())
@@ -291,9 +294,6 @@ public class OpenPgpService extends RemoteService {
.setSignaturePassphrase(passphrase)
.setNfcState(nfcSignedHash, nfcCreationDate);
- // TODO: currently always assume cleartext input, no sign-only of binary currently!
- builder.setCleartextInput(true);
-
// execute PGP operation!
SignEncryptResult pgpResult = builder.build().execute();
@@ -313,20 +313,20 @@ public class OpenPgpService extends RemoteService {
"Encountered unhandled type of pending action not supported by API!");
}
} else if (pgpResult.success()) {
- // see end of method
+ Intent result = new Intent();
+ if (!cleartextSign) {
+ result.putExtra(OpenPgpApi.RESULT_DETACHED_SIGNATURE, pgpResult.getDetachedSignature());
+ }
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
} else {
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
throw new Exception(getString(errorMsg.mType.getMsgId()));
}
-
} finally {
is.close();
os.close();
}
-
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
} catch (Exception e) {
Log.d(Constants.TAG, "signImpl", e);
Intent result = new Intent();
@@ -444,7 +444,9 @@ public class OpenPgpService extends RemoteService {
"Encountered unhandled type of pending action not supported by API!");
}
} else if (pgpResult.success()) {
- // see end of method
+ Intent result = new Intent();
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
} else {
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
throw new Exception(getString(errorMsg.mType.getMsgId()));
@@ -454,10 +456,6 @@ public class OpenPgpService extends RemoteService {
is.close();
os.close();
}
-
- Intent result = new Intent();
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
} catch (Exception e) {
Log.d(Constants.TAG, "encryptAndSignImpl", e);
Intent result = new Intent();
@@ -482,7 +480,6 @@ public class OpenPgpService extends RemoteService {
os = new ParcelFileDescriptor.AutoCloseOutputStream(output);
}
- Intent result = new Intent();
try {
String passphrase = data.getStringExtra(OpenPgpApi.EXTRA_PASSPHRASE);
long inputLength = is.available();
@@ -522,6 +519,7 @@ public class OpenPgpService extends RemoteService {
"Encountered unhandled type of pending action not supported by API!");
}
} else if (pgpResult.success()) {
+ Intent result = new Intent();
OpenPgpSignatureResult signatureResult = pgpResult.getSignatureResult();
if (signatureResult != null) {
@@ -557,6 +555,9 @@ public class OpenPgpService extends RemoteService {
result.putExtra(OpenPgpApi.RESULT_METADATA, metadata);
}
}
+
+ result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
+ return result;
} else {
LogEntryParcel errorMsg = pgpResult.getLog().getLast();
throw new Exception(getString(errorMsg.mType.getMsgId()));
@@ -567,9 +568,6 @@ public class OpenPgpService extends RemoteService {
os.close();
}
}
-
- result.putExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_SUCCESS);
- return result;
} catch (Exception e) {
Log.d(Constants.TAG, "decryptAndVerifyImpl", e);
Intent result = new Intent();
@@ -718,8 +716,13 @@ public class OpenPgpService extends RemoteService {
}
String action = data.getAction();
- if (OpenPgpApi.ACTION_SIGN.equals(action)) {
- return signImpl(data, input, output, accSettings);
+ if (OpenPgpApi.ACTION_CLEARTEXT_SIGN.equals(action)) {
+ return signImpl(data, input, output, accSettings, true);
+ } else if (OpenPgpApi.ACTION_SIGN.equals(action)) {
+ // DEPRECATED: same as ACTION_CLEARTEXT_SIGN
+ return signImpl(data, input, output, accSettings, true);
+ } else if (OpenPgpApi.ACTION_DETACHED_SIGN.equals(action)) {
+ return signImpl(data, input, output, accSettings, false);
} else if (OpenPgpApi.ACTION_ENCRYPT.equals(action)) {
return encryptAndSignImpl(data, input, output, accSettings, false);
} else if (OpenPgpApi.ACTION_SIGN_AND_ENCRYPT.equals(action)) {
diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
index 479810203..2dc057941 100644
--- a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
+++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/service/KeychainIntentService.java
@@ -33,7 +33,6 @@ import org.sufficientlysecure.keychain.operations.EditKeyOperation;
import org.sufficientlysecure.keychain.operations.results.DeleteResult;
import org.sufficientlysecure.keychain.operations.results.EditKeyResult;
import org.sufficientlysecure.keychain.operations.results.ExportResult;
-import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
import org.sufficientlysecure.keychain.pgp.exception.PgpKeyNotFoundException;
import org.sufficientlysecure.keychain.operations.results.CertifyResult;
import org.sufficientlysecure.keychain.util.FileHelper;
@@ -474,7 +473,7 @@ public class KeychainIntentService extends IntentService implements Progressable
// this assumes that the bytes are cleartext (valid for current implementation!)
if (source == IO_BYTES) {
- builder.setCleartextInput(true);
+ builder.setCleartextSignature(true);
}
SignEncryptResult result = builder.build().execute();
diff --git a/extern/openpgp-api-lib b/extern/openpgp-api-lib
-Subproject 89b0a3bd140dd178595c031beaa27747575d7ac
+Subproject f712a26ab68eb0f978722cfa69a7e9b5d05c80c