merge internal signText and signAndEncrypt methods
This commit is contained in:
@@ -98,7 +98,7 @@ public class PgpOperation {
|
|||||||
private OutputStream mOutStream;
|
private OutputStream mOutStream;
|
||||||
|
|
||||||
public PgpOperation(Context context, ProgressDialogUpdater progress, InputData data,
|
public PgpOperation(Context context, ProgressDialogUpdater progress, InputData data,
|
||||||
OutputStream outStream) {
|
OutputStream outStream) {
|
||||||
super();
|
super();
|
||||||
this.mContext = context;
|
this.mContext = context;
|
||||||
this.mProgress = progress;
|
this.mProgress = progress;
|
||||||
@@ -118,9 +118,10 @@ public class PgpOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void signAndEncrypt(boolean useAsciiArmor, int compression, long[] encryptionKeyIds,
|
public void signAndEncrypt(boolean enableAsciiArmor, int compressionId, long[] encryptionKeyIds,
|
||||||
String encryptionPassphrase, int symmetricEncryptionAlgorithm, long signatureKeyId,
|
String encryptionPassphrase, int symmetricEncryptionAlgorithm,
|
||||||
int signatureHashAlgorithm, boolean signatureForceV3, String signaturePassphrase)
|
long signatureKeyId, int signatureHashAlgorithm,
|
||||||
|
boolean signatureForceV3, String signaturePassphrase)
|
||||||
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
|
throws IOException, PgpGeneralException, PGPException, NoSuchProviderException,
|
||||||
NoSuchAlgorithmException, SignatureException {
|
NoSuchAlgorithmException, SignatureException {
|
||||||
|
|
||||||
@@ -128,26 +129,34 @@ public class PgpOperation {
|
|||||||
encryptionKeyIds = new long[0];
|
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;
|
ArmoredOutputStream armorOut = null;
|
||||||
OutputStream out = null;
|
OutputStream out;
|
||||||
OutputStream encryptOut = null;
|
OutputStream encryptionOut = null;
|
||||||
if (useAsciiArmor) {
|
if (enableAsciiArmor) {
|
||||||
armorOut = new ArmoredOutputStream(mOutStream);
|
armorOut = new ArmoredOutputStream(mOutStream);
|
||||||
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
|
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
|
||||||
out = armorOut;
|
out = armorOut;
|
||||||
} else {
|
} else {
|
||||||
out = mOutStream;
|
out = mOutStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
PGPSecretKey signingKey = null;
|
PGPSecretKey signingKey = null;
|
||||||
PGPSecretKeyRing signingKeyRing = null;
|
PGPSecretKeyRing signingKeyRing = null;
|
||||||
PGPPrivateKey signaturePrivateKey = null;
|
PGPPrivateKey signaturePrivateKey = null;
|
||||||
|
if (enableSignature) {
|
||||||
if (encryptionKeyIds.length == 0 && encryptionPassphrase == null) {
|
|
||||||
throw new PgpGeneralException(
|
|
||||||
mContext.getString(R.string.error_no_encryption_keys_or_passphrase));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (signatureKeyId != Id.key.none) {
|
|
||||||
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
|
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
|
||||||
signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
|
signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
|
||||||
if (signingKey == null) {
|
if (signingKey == null) {
|
||||||
@@ -172,50 +181,51 @@ public class PgpOperation {
|
|||||||
updateProgress(R.string.progress_preparing_streams, 5, 100);
|
updateProgress(R.string.progress_preparing_streams, 5, 100);
|
||||||
|
|
||||||
// encrypt and compress input file content
|
// encrypt and compress input file content
|
||||||
JcePGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(
|
if (enableEncryption) {
|
||||||
symmetricEncryptionAlgorithm).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
|
JcePGPDataEncryptorBuilder encryptorBuilder = new JcePGPDataEncryptorBuilder(
|
||||||
.setWithIntegrityPacket(true);
|
symmetricEncryptionAlgorithm).setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME)
|
||||||
|
.setWithIntegrityPacket(true);
|
||||||
|
|
||||||
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
|
PGPEncryptedDataGenerator cPk = new PGPEncryptedDataGenerator(encryptorBuilder);
|
||||||
|
|
||||||
if (encryptionKeyIds.length == 0) {
|
if (encryptionKeyIds.length == 0) {
|
||||||
// Symmetric encryption
|
// Symmetric encryption
|
||||||
Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
|
Log.d(Constants.TAG, "encryptionKeyIds length is 0 -> symmetric encryption");
|
||||||
|
|
||||||
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = new JcePBEKeyEncryptionMethodGenerator(
|
JcePBEKeyEncryptionMethodGenerator symmetricEncryptionGenerator = new JcePBEKeyEncryptionMethodGenerator(
|
||||||
encryptionPassphrase.toCharArray());
|
encryptionPassphrase.toCharArray());
|
||||||
cPk.addMethod(symmetricEncryptionGenerator);
|
cPk.addMethod(symmetricEncryptionGenerator);
|
||||||
} else {
|
} else {
|
||||||
// Asymmetric encryption
|
// Asymmetric encryption
|
||||||
for (long id : encryptionKeyIds) {
|
for (long id : encryptionKeyIds) {
|
||||||
PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
|
PGPPublicKey key = PgpKeyHelper.getEncryptPublicKey(mContext, id);
|
||||||
if (key != null) {
|
if (key != null) {
|
||||||
|
|
||||||
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator = new JcePublicKeyKeyEncryptionMethodGenerator(
|
JcePublicKeyKeyEncryptionMethodGenerator pubKeyEncryptionGenerator = new JcePublicKeyKeyEncryptionMethodGenerator(
|
||||||
key);
|
key);
|
||||||
cPk.addMethod(pubKeyEncryptionGenerator);
|
cPk.addMethod(pubKeyEncryptionGenerator);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
encryptionOut = cPk.open(out, new byte[1 << 16]);
|
||||||
}
|
}
|
||||||
encryptOut = cPk.open(out, new byte[1 << 16]);
|
|
||||||
|
|
||||||
PGPSignatureGenerator signatureGenerator = null;
|
PGPSignatureGenerator signatureGenerator = null;
|
||||||
PGPV3SignatureGenerator signatureV3Generator = null;
|
PGPV3SignatureGenerator signatureV3Generator = null;
|
||||||
|
if (enableSignature) {
|
||||||
if (signatureKeyId != Id.key.none) {
|
|
||||||
updateProgress(R.string.progress_preparing_signature, 10, 100);
|
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(
|
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(
|
||||||
signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
|
signingKey.getPublicKey().getAlgorithm(), signatureHashAlgorithm)
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
|
||||||
if (signatureForceV3) {
|
if (signatureForceV3) {
|
||||||
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
|
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
|
||||||
signatureV3Generator.init(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
|
signatureV3Generator.init(signatureType, signaturePrivateKey);
|
||||||
} else {
|
} else {
|
||||||
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
signatureGenerator = new PGPSignatureGenerator(contentSignerBuilder);
|
||||||
signatureGenerator.init(PGPSignature.BINARY_DOCUMENT, signaturePrivateKey);
|
signatureGenerator.init(signatureType, signaturePrivateKey);
|
||||||
|
|
||||||
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper
|
String userId = PgpKeyHelper.getMainUserId(PgpKeyHelper
|
||||||
.getMasterKey(signingKeyRing));
|
.getMasterKey(signingKeyRing));
|
||||||
@@ -226,49 +236,100 @@ public class PgpOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
PGPCompressedDataGenerator compressGen = null;
|
PGPCompressedDataGenerator compressGen = null;
|
||||||
BCPGOutputStream bcpgOut = null;
|
OutputStream pOut;
|
||||||
if (compression == Id.choice.compression.none) {
|
if (enableEncryption) {
|
||||||
bcpgOut = new BCPGOutputStream(encryptOut);
|
BCPGOutputStream bcpgOut;
|
||||||
} else {
|
if (enableCompression) {
|
||||||
compressGen = new PGPCompressedDataGenerator(compression);
|
compressGen = new PGPCompressedDataGenerator(compressionId);
|
||||||
bcpgOut = new BCPGOutputStream(compressGen.open(encryptOut));
|
bcpgOut = new BCPGOutputStream(compressGen.open(encryptionOut));
|
||||||
}
|
|
||||||
if (signatureKeyId != Id.key.none) {
|
|
||||||
if (signatureForceV3) {
|
|
||||||
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
|
|
||||||
} else {
|
} else {
|
||||||
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
|
bcpgOut = new BCPGOutputStream(encryptionOut);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
|
if (enableSignature) {
|
||||||
// file name not needed, so empty string
|
|
||||||
OutputStream 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;
|
|
||||||
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) {
|
|
||||||
if (signatureForceV3) {
|
if (signatureForceV3) {
|
||||||
signatureV3Generator.update(buffer, 0, n);
|
signatureV3Generator.generateOnePassVersion(false).encode(bcpgOut);
|
||||||
} else {
|
} else {
|
||||||
signatureGenerator.update(buffer, 0, n);
|
signatureGenerator.generateOnePassVersion(false).encode(bcpgOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
done += n;
|
|
||||||
if (mData.getSize() != 0) {
|
PGPLiteralDataGenerator literalGen = new PGPLiteralDataGenerator();
|
||||||
updateProgress((int) (20 + (95 - 20) * done / mData.getSize()), 100);
|
// 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 (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 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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
literalGen.close();
|
if (enableSignature) {
|
||||||
|
|
||||||
if (signatureKeyId != Id.key.none) {
|
|
||||||
updateProgress(R.string.progress_generating_signature, 95, 100);
|
updateProgress(R.string.progress_generating_signature, 95, 100);
|
||||||
if (signatureForceV3) {
|
if (signatureForceV3) {
|
||||||
signatureV3Generator.generate().encode(pOut);
|
signatureV3Generator.generate().encode(pOut);
|
||||||
@@ -276,11 +337,16 @@ public class PgpOperation {
|
|||||||
signatureGenerator.generate().encode(pOut);
|
signatureGenerator.generate().encode(pOut);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (compressGen != null) {
|
|
||||||
compressGen.close();
|
// closing outputs...
|
||||||
|
if (enableEncryption) {
|
||||||
|
encryptionOut.close();
|
||||||
|
|
||||||
|
if (enableCompression) {
|
||||||
|
compressGen.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
encryptOut.close();
|
if (enableAsciiArmor) {
|
||||||
if (useAsciiArmor) {
|
|
||||||
armorOut.close();
|
armorOut.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,138 +354,38 @@ public class PgpOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void signText(long signatureKeyId, String signaturePassphrase,
|
public void signText(long signatureKeyId, String signaturePassphrase,
|
||||||
int signatureHashAlgorithm, boolean forceV3Signature) throws PgpGeneralException,
|
int signatureHashAlgorithm, boolean forceV3Signature)
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
updateProgress(R.string.progress_signing, 40, 100);
|
|
||||||
|
|
||||||
armorOut.beginClearText(signatureHashAlgorithm);
|
|
||||||
|
|
||||||
InputStream inStream = mData.getInputStream();
|
|
||||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
|
|
||||||
|
|
||||||
final byte[] newline = "\r\n".getBytes("UTF-8");
|
|
||||||
|
|
||||||
if (forceV3Signature) {
|
|
||||||
processLine(reader.readLine(), armorOut, signatureV3Generator);
|
|
||||||
} else {
|
|
||||||
processLine(reader.readLine(), armorOut, signatureGenerator);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
final String line = reader.readLine();
|
|
||||||
|
|
||||||
if (line == null) {
|
|
||||||
armorOut.write(newline);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
armorOut.write(newline);
|
|
||||||
if (forceV3Signature) {
|
|
||||||
signatureV3Generator.update(newline);
|
|
||||||
processLine(line, armorOut, signatureV3Generator);
|
|
||||||
} else {
|
|
||||||
signatureGenerator.update(newline);
|
|
||||||
processLine(line, armorOut, signatureGenerator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
armorOut.endClearText();
|
|
||||||
|
|
||||||
BCPGOutputStream bOut = new BCPGOutputStream(armorOut);
|
|
||||||
if (forceV3Signature) {
|
|
||||||
signatureV3Generator.generate().encode(bOut);
|
|
||||||
} else {
|
|
||||||
signatureGenerator.generate().encode(bOut);
|
|
||||||
}
|
|
||||||
armorOut.close();
|
|
||||||
|
|
||||||
updateProgress(R.string.progress_done, 100, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void generateSignature(boolean armored, boolean binary, long signatureKeyId,
|
|
||||||
String signaturePassPhrase, int hashAlgorithm, boolean forceV3Signature)
|
|
||||||
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
|
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
|
||||||
SignatureException {
|
SignatureException {
|
||||||
|
|
||||||
OutputStream out = null;
|
try {
|
||||||
|
signAndEncrypt(true, 0, null, null, 0, signatureKeyId, signatureHashAlgorithm, forceV3Signature, signaturePassphrase);
|
||||||
|
} catch (NoSuchProviderException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ascii Armor (Base64)
|
public void generateSignature(boolean armored, boolean binary, long signatureKeyId,
|
||||||
ArmoredOutputStream armorOut = null;
|
String signaturePassPhrase, int hashAlgorithm, boolean forceV3Signature)
|
||||||
|
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
|
||||||
|
SignatureException {
|
||||||
|
|
||||||
|
OutputStream out;
|
||||||
if (armored) {
|
if (armored) {
|
||||||
armorOut = new ArmoredOutputStream(mOutStream);
|
// Ascii Armor (Radix-64)
|
||||||
|
ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
|
||||||
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
|
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
|
||||||
out = armorOut;
|
out = armorOut;
|
||||||
} else {
|
} else {
|
||||||
out = mOutStream;
|
out = mOutStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
PGPSecretKey signingKey = null;
|
|
||||||
PGPSecretKeyRing signingKeyRing = null;
|
|
||||||
PGPPrivateKey signaturePrivateKey = null;
|
|
||||||
|
|
||||||
if (signatureKeyId == 0) {
|
if (signatureKeyId == 0) {
|
||||||
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
|
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
|
||||||
}
|
}
|
||||||
|
|
||||||
signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
|
PGPSecretKeyRing signingKeyRing = ProviderHelper.getPGPSecretKeyRingByKeyId(mContext, signatureKeyId);
|
||||||
signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
|
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(mContext, signatureKeyId);
|
||||||
if (signingKey == null) {
|
if (signingKey == null) {
|
||||||
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
|
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
|
||||||
}
|
}
|
||||||
@@ -430,7 +396,7 @@ public class PgpOperation {
|
|||||||
|
|
||||||
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
|
||||||
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassPhrase.toCharArray());
|
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(signaturePassPhrase.toCharArray());
|
||||||
signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
|
PGPPrivateKey signaturePrivateKey = signingKey.extractPrivateKey(keyDecryptor);
|
||||||
if (signaturePrivateKey == null) {
|
if (signaturePrivateKey == null) {
|
||||||
throw new PgpGeneralException(
|
throw new PgpGeneralException(
|
||||||
mContext.getString(R.string.error_could_not_extract_private_key));
|
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);
|
updateProgress(R.string.progress_preparing_signature, 30, 100);
|
||||||
|
|
||||||
PGPSignatureGenerator signatureGenerator = null;
|
|
||||||
PGPV3SignatureGenerator signatureV3Generator = null;
|
|
||||||
|
|
||||||
int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
||||||
if (binary) {
|
if (binary) {
|
||||||
type = PGPSignature.BINARY_DOCUMENT;
|
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
|
JcaPGPContentSignerBuilder contentSignerBuilder = new JcaPGPContentSignerBuilder(signingKey
|
||||||
.getPublicKey().getAlgorithm(), hashAlgorithm)
|
.getPublicKey().getAlgorithm(), hashAlgorithm)
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
|
|
||||||
|
PGPSignatureGenerator signatureGenerator = null;
|
||||||
|
PGPV3SignatureGenerator signatureV3Generator = null;
|
||||||
if (forceV3Signature) {
|
if (forceV3Signature) {
|
||||||
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
|
signatureV3Generator = new PGPV3SignatureGenerator(contentSignerBuilder);
|
||||||
signatureV3Generator.init(type, signaturePrivateKey);
|
signatureV3Generator.init(type, signaturePrivateKey);
|
||||||
@@ -482,13 +447,8 @@ public class PgpOperation {
|
|||||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
|
final BufferedReader reader = new BufferedReader(new InputStreamReader(inStream));
|
||||||
final byte[] newline = "\r\n".getBytes("UTF-8");
|
final byte[] newline = "\r\n".getBytes("UTF-8");
|
||||||
|
|
||||||
while (true) {
|
String line;
|
||||||
final String line = reader.readLine();
|
while ((line = reader.readLine()) != null) {
|
||||||
|
|
||||||
if (line == null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forceV3Signature) {
|
if (forceV3Signature) {
|
||||||
processLine(line, null, signatureV3Generator);
|
processLine(line, null, signatureV3Generator);
|
||||||
signatureV3Generator.update(newline);
|
signatureV3Generator.update(newline);
|
||||||
@@ -508,8 +468,7 @@ public class PgpOperation {
|
|||||||
out.close();
|
out.close();
|
||||||
mOutStream.close();
|
mOutStream.close();
|
||||||
|
|
||||||
if (mProgress != null)
|
updateProgress(R.string.progress_done, 100, 100);
|
||||||
mProgress.setProgress(R.string.progress_done, 100, 100);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
|
public static boolean hasSymmetricEncryption(Context context, InputStream inputStream)
|
||||||
@@ -548,11 +507,11 @@ public class PgpOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Bundle returnData = new Bundle();
|
Bundle returnData = new Bundle();
|
||||||
|
// automatically works with ascii armor input and binary
|
||||||
InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
|
InputStream in = PGPUtil.getDecoderStream(mData.getInputStream());
|
||||||
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
PGPObjectFactory pgpF = new PGPObjectFactory(in);
|
||||||
PGPEncryptedDataList enc;
|
PGPEncryptedDataList enc;
|
||||||
Object o = pgpF.nextObject();
|
Object o = pgpF.nextObject();
|
||||||
long signatureKeyId = 0;
|
|
||||||
|
|
||||||
int currentProgress = 0;
|
int currentProgress = 0;
|
||||||
updateProgress(R.string.progress_reading_data, currentProgress, 100);
|
updateProgress(R.string.progress_reading_data, currentProgress, 100);
|
||||||
@@ -669,6 +628,7 @@ public class PgpOperation {
|
|||||||
currentProgress += 10;
|
currentProgress += 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
long signatureKeyId = 0;
|
||||||
if (dataChunk instanceof PGPOnePassSignatureList) {
|
if (dataChunk instanceof PGPOnePassSignatureList) {
|
||||||
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
|
updateProgress(R.string.progress_processing_signature, currentProgress, 100);
|
||||||
|
|
||||||
@@ -798,7 +758,7 @@ public class PgpOperation {
|
|||||||
|
|
||||||
updateProgress(R.string.progress_done, 0, 100);
|
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();
|
ByteArrayOutputStream lineOut = new ByteArrayOutputStream();
|
||||||
int lookAhead = readInputLine(lineOut, aIn);
|
int lookAhead = readInputLine(lineOut, aIn);
|
||||||
byte[] lineSep = getLineSeparator();
|
byte[] lineSep = getLineSeparator();
|
||||||
@@ -895,8 +855,7 @@ public class PgpOperation {
|
|||||||
return returnData;
|
return returnData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean verifyKeyBinding(Context mContext, PGPSignature signature, PGPPublicKey signatureKey)
|
public boolean verifyKeyBinding(Context mContext, PGPSignature signature, PGPPublicKey signatureKey) {
|
||||||
{
|
|
||||||
long signatureKeyId = signature.getKeyID();
|
long signatureKeyId = signature.getKeyID();
|
||||||
boolean keyBinding_isok = false;
|
boolean keyBinding_isok = false;
|
||||||
String userId = null;
|
String userId = null;
|
||||||
@@ -914,8 +873,7 @@ public class PgpOperation {
|
|||||||
return keyBinding_isok;
|
return keyBinding_isok;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey)
|
public boolean verifyKeyBinding(PGPPublicKey masterPublicKey, PGPPublicKey signingPublicKey) {
|
||||||
{
|
|
||||||
boolean subkeyBinding_isok = false;
|
boolean subkeyBinding_isok = false;
|
||||||
boolean tmp_subkeyBinding_isok = false;
|
boolean tmp_subkeyBinding_isok = false;
|
||||||
boolean primkeyBinding_isok = false;
|
boolean primkeyBinding_isok = false;
|
||||||
@@ -935,8 +893,8 @@ public class PgpOperation {
|
|||||||
if (sig.getKeyID() == masterPublicKey.getKeyID() && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
|
if (sig.getKeyID() == masterPublicKey.getKeyID() && sig.getSignatureType() == PGPSignature.SUBKEY_BINDING) {
|
||||||
//check and if ok, check primary key binding.
|
//check and if ok, check primary key binding.
|
||||||
try {
|
try {
|
||||||
sig.init(contentVerifierBuilderProvider, masterPublicKey);
|
sig.init(contentVerifierBuilderProvider, masterPublicKey);
|
||||||
tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey);
|
tmp_subkeyBinding_isok = sig.verifyCertification(masterPublicKey, signingPublicKey);
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
continue;
|
continue;
|
||||||
} catch (SignatureException e) {
|
} catch (SignatureException e) {
|
||||||
@@ -958,42 +916,41 @@ public class PgpOperation {
|
|||||||
return (subkeyBinding_isok & primkeyBinding_isok);
|
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;
|
boolean primkeyBinding_isok = false;
|
||||||
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
|
JcaPGPContentVerifierBuilderProvider contentVerifierBuilderProvider = new JcaPGPContentVerifierBuilderProvider()
|
||||||
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
|
||||||
PGPSignatureList eSigList;
|
PGPSignatureList eSigList;
|
||||||
|
|
||||||
if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
|
if (Pkts.hasSubpacket(SignatureSubpacketTags.EMBEDDED_SIGNATURE)) {
|
||||||
try {
|
try {
|
||||||
eSigList = Pkts.getEmbeddedSignatures();
|
eSigList = Pkts.getEmbeddedSignatures();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
return false;
|
return false;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < eSigList.size(); ++j) {
|
for (int j = 0; j < eSigList.size(); ++j) {
|
||||||
PGPSignature emSig = eSigList.get(j);
|
PGPSignature emSig = eSigList.get(j);
|
||||||
if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
|
if (emSig.getSignatureType() == PGPSignature.PRIMARYKEY_BINDING) {
|
||||||
try {
|
try {
|
||||||
emSig.init(contentVerifierBuilderProvider, signingPublicKey);
|
emSig.init(contentVerifierBuilderProvider, signingPublicKey);
|
||||||
primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey);
|
primkeyBinding_isok = emSig.verifyCertification(masterPublicKey, signingPublicKey);
|
||||||
if (primkeyBinding_isok)
|
if (primkeyBinding_isok)
|
||||||
break;
|
break;
|
||||||
} catch (PGPException e) {
|
} catch (PGPException e) {
|
||||||
continue;
|
continue;
|
||||||
} catch (SignatureException e) {
|
} catch (SignatureException e) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return primkeyBinding_isok;
|
return primkeyBinding_isok;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
|
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
|
||||||
final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException {
|
final PGPSignatureGenerator pSignatureGenerator) throws IOException, SignatureException {
|
||||||
|
|
||||||
if (pLine == null) {
|
if (pLine == null) {
|
||||||
return;
|
return;
|
||||||
@@ -1018,7 +975,7 @@ public class PgpOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
|
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
|
||||||
final PGPV3SignatureGenerator pSignatureGenerator) throws IOException,
|
final PGPV3SignatureGenerator pSignatureGenerator) throws IOException,
|
||||||
SignatureException {
|
SignatureException {
|
||||||
|
|
||||||
if (pLine == null) {
|
if (pLine == null) {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.openintents.openpgp.IOpenPgpService;
|
|||||||
import org.openintents.openpgp.OpenPgpError;
|
import org.openintents.openpgp.OpenPgpError;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.openintents.openpgp.util.OpenPgpConstants;
|
import org.openintents.openpgp.util.OpenPgpConstants;
|
||||||
|
import org.spongycastle.openpgp.PGPUtil;
|
||||||
import org.spongycastle.util.Arrays;
|
import org.spongycastle.util.Arrays;
|
||||||
import org.sufficientlysecure.keychain.Constants;
|
import org.sufficientlysecure.keychain.Constants;
|
||||||
import org.sufficientlysecure.keychain.Id;
|
import org.sufficientlysecure.keychain.Id;
|
||||||
@@ -237,10 +238,12 @@ public class OpenPgpService extends RemoteService {
|
|||||||
return passphraseBundle;
|
return passphraseBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sign and encrypt
|
||||||
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
|
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
|
||||||
appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
|
appSettings.getEncryptionAlgorithm(), appSettings.getKeyId(),
|
||||||
appSettings.getHashAlgorithm(), true, passphrase);
|
appSettings.getHashAlgorithm(), true, passphrase);
|
||||||
} else {
|
} else {
|
||||||
|
// encrypt only
|
||||||
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
|
operation.signAndEncrypt(asciiArmor, appSettings.getCompression(), keyIds, null,
|
||||||
appSettings.getEncryptionAlgorithm(), Id.key.none,
|
appSettings.getEncryptionAlgorithm(), Id.key.none,
|
||||||
appSettings.getHashAlgorithm(), true, null);
|
appSettings.getHashAlgorithm(), true, null);
|
||||||
@@ -271,7 +274,7 @@ public class OpenPgpService extends RemoteService {
|
|||||||
OpenPgpSignatureResult sigResult = null;
|
OpenPgpSignatureResult sigResult = null;
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
// PGPUtil.getDecoderStream(is)
|
||||||
// TODOs API 2.0:
|
// TODOs API 2.0:
|
||||||
// implement verify-only!
|
// implement verify-only!
|
||||||
// fix the mess: http://stackoverflow.com/questions/148130/how-do-i-peek-at-the-first-two-bytes-in-an-inputstream
|
// 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);
|
// 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;
|
String passphrase;
|
||||||
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
|
if (params.containsKey(OpenPgpConstants.PARAMS_PASSPHRASE)) {
|
||||||
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
|
passphrase = params.getString(OpenPgpConstants.PARAMS_PASSPHRASE);
|
||||||
@@ -375,8 +378,10 @@ public class OpenPgpService extends RemoteService {
|
|||||||
if (signedOnly) {
|
if (signedOnly) {
|
||||||
outputBundle = operation.verifyText();
|
outputBundle = operation.verifyText();
|
||||||
} else {
|
} else {
|
||||||
// BIG TODO: instead of trying to get the passphrase before
|
// Do we want to do this: instead of trying to get the passphrase before
|
||||||
// pause stream when passphrase is missing and then resume
|
// pause stream when passphrase is missing and then resume???
|
||||||
|
|
||||||
|
// TODO: this also decrypts with other secret keys without passphrase!!!
|
||||||
outputBundle = operation.decryptAndVerify(passphrase, false);
|
outputBundle = operation.decryptAndVerify(passphrase, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
<string name="label_passphrase_cache_ttl">Passphrase Cache</string>
|
<string name="label_passphrase_cache_ttl">Passphrase Cache</string>
|
||||||
<string name="label_message_compression">Message Compression</string>
|
<string name="label_message_compression">Message Compression</string>
|
||||||
<string name="label_file_compression">File 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_servers">Keyservers</string>
|
||||||
<string name="label_key_id">Key ID</string>
|
<string name="label_key_id">Key ID</string>
|
||||||
<string name="label_creation">Creation</string>
|
<string name="label_creation">Creation</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user