PgpSignEncrypt: merge generateSignature() into main method

This commit is contained in:
Dominik Schürmann 2014-04-11 18:53:24 +02:00
parent e39b081927
commit 5346d2e878

View File

@ -56,6 +56,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException; import java.security.NoSuchProviderException;
import java.security.SignatureException; import java.security.SignatureException;
@ -82,6 +83,18 @@ public class PgpSignEncrypt {
private boolean mSignatureForceV3; private boolean mSignatureForceV3;
private String mSignaturePassphrase; private String mSignaturePassphrase;
private boolean mEncryptToSigner; private boolean mEncryptToSigner;
private boolean mBinaryInput;
private static byte[] NEW_LINE;
static {
try {
NEW_LINE = "\r\n".getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(Constants.TAG, "UnsupportedEncodingException", e);
}
}
private PgpSignEncrypt(Builder builder) { private PgpSignEncrypt(Builder builder) {
// private Constructor can only be called from Builder // private Constructor can only be called from Builder
@ -101,6 +114,7 @@ public class PgpSignEncrypt {
this.mSignatureForceV3 = builder.mSignatureForceV3; this.mSignatureForceV3 = builder.mSignatureForceV3;
this.mSignaturePassphrase = builder.mSignaturePassphrase; this.mSignaturePassphrase = builder.mSignaturePassphrase;
this.mEncryptToSigner = builder.mEncryptToSigner; this.mEncryptToSigner = builder.mEncryptToSigner;
this.mBinaryInput = builder.mBinaryInput;
} }
public static class Builder { public static class Builder {
@ -121,6 +135,7 @@ public class PgpSignEncrypt {
private boolean mSignatureForceV3 = false; private boolean mSignatureForceV3 = false;
private String mSignaturePassphrase = null; private String mSignaturePassphrase = null;
private boolean mEncryptToSigner = false; private boolean mEncryptToSigner = false;
private boolean mBinaryInput = false;
public Builder(Context context, InputData data, OutputStream outStream) { public Builder(Context context, InputData data, OutputStream outStream) {
this.mContext = context; this.mContext = context;
@ -178,11 +193,28 @@ public class PgpSignEncrypt {
return this; return this;
} }
/**
* TODO: test this option!
*
* @param encryptToSigner
* @return
*/
public Builder encryptToSigner(boolean encryptToSigner) { public Builder encryptToSigner(boolean encryptToSigner) {
this.mEncryptToSigner = encryptToSigner; this.mEncryptToSigner = encryptToSigner;
return this; return this;
} }
/**
* TODO: test this option!
*
* @param binaryInput
* @return
*/
public Builder binaryInput(boolean binaryInput) {
this.mBinaryInput = binaryInput;
return this;
}
public PgpSignEncrypt build() { public PgpSignEncrypt build() {
return new PgpSignEncrypt(this); return new PgpSignEncrypt(this);
} }
@ -394,21 +426,20 @@ public class PgpSignEncrypt {
} }
literalGen.close(); literalGen.close();
} else if (mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) { } else if (!mBinaryInput && mEnableAsciiArmorOutput && enableSignature && !enableEncryption && !enableCompression) {
/* sign-only of ascii text */ /* cleartext signature: sign-only of ascii text */
updateProgress(R.string.progress_signing, 40, 100); updateProgress(R.string.progress_signing, 40, 100);
// write directly on armor output stream // write -----BEGIN PGP SIGNED MESSAGE-----
armorOut.beginClearText(mSignatureHashAlgorithm); armorOut.beginClearText(mSignatureHashAlgorithm);
InputStream in = mData.getInputStream(); InputStream in = mData.getInputStream();
final BufferedReader reader = new BufferedReader(new InputStreamReader(in)); final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
final byte[] newline = "\r\n".getBytes("UTF-8"); // update signature buffer with first line
if (mSignatureForceV3) { if (mSignatureForceV3) {
processLine(reader.readLine(), armorOut, signatureV3Generator); processLineV3(reader.readLine(), armorOut, signatureV3Generator);
} else { } else {
processLine(reader.readLine(), armorOut, signatureGenerator); processLine(reader.readLine(), armorOut, signatureGenerator);
} }
@ -416,28 +447,62 @@ public class PgpSignEncrypt {
while (true) { while (true) {
String line = reader.readLine(); String line = reader.readLine();
// end cleartext signature with newline, see http://tools.ietf.org/html/rfc4880#section-7
if (line == null) { if (line == null) {
armorOut.write(newline); armorOut.write(NEW_LINE);
break; break;
} }
armorOut.write(newline); armorOut.write(NEW_LINE);
// update signature buffer with input line // update signature buffer with input line
if (mSignatureForceV3) { if (mSignatureForceV3) {
signatureV3Generator.update(newline); signatureV3Generator.update(NEW_LINE);
processLine(line, armorOut, signatureV3Generator); processLineV3(line, armorOut, signatureV3Generator);
} else { } else {
signatureGenerator.update(newline); signatureGenerator.update(NEW_LINE);
processLine(line, armorOut, signatureGenerator); processLine(line, armorOut, signatureGenerator);
} }
} }
armorOut.endClearText(); armorOut.endClearText();
pOut = new BCPGOutputStream(armorOut); pOut = new BCPGOutputStream(armorOut);
} else if (mBinaryInput && enableSignature && !enableEncryption && !enableCompression) {
// TODO: This part of the code is not tested!!!
/* sign-only binaries (files) */
updateProgress(R.string.progress_signing, 40, 100);
InputStream in = mData.getInputStream();
if (mEnableAsciiArmorOutput) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(in));
String line;
while ((line = reader.readLine()) != null) {
if (mSignatureForceV3) {
processLineV3(line, null, signatureV3Generator);
signatureV3Generator.update(NEW_LINE);
} else {
processLine(line, null, signatureGenerator);
signatureGenerator.update(NEW_LINE);
}
}
} else {
byte[] buffer = new byte[1 << 16];
int n;
while ((n = in.read(buffer)) > 0) {
if (mSignatureForceV3) {
signatureV3Generator.update(buffer, 0, n);
} else {
signatureGenerator.update(buffer, 0, n);
}
}
}
pOut = new BCPGOutputStream(out);
} else { } else {
// TODO: implement sign-only for files!
pOut = null; pOut = null;
Log.e(Constants.TAG, "not supported!"); Log.e(Constants.TAG, "not supported!");
} }
@ -471,119 +536,6 @@ public class PgpSignEncrypt {
updateProgress(R.string.progress_done, 100, 100); updateProgress(R.string.progress_done, 100, 100);
} }
// TODO: merge this into execute method!
// TODO: allow binary input for this class
public void generateSignature()
throws PgpGeneralException, PGPException, IOException, NoSuchAlgorithmException,
SignatureException {
OutputStream out;
if (mEnableAsciiArmorOutput) {
// Ascii Armor (Radix-64)
ArmoredOutputStream armorOut = new ArmoredOutputStream(mOutStream);
armorOut.setHeader("Version", PgpHelper.getFullVersion(mContext));
out = armorOut;
} else {
out = mOutStream;
}
if (mSignatureMasterKeyId == 0) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_key));
}
PGPSecretKeyRing signingKeyRing;
try {
signingKeyRing = mProviderHelper.getPGPSecretKeyRing(mSignatureMasterKeyId);
} catch (ProviderHelper.NotFoundException e) {
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
PGPSecretKey signingKey = PgpKeyHelper.getSigningKey(signingKeyRing);
if (signingKey == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_signature_failed));
}
if (mSignaturePassphrase == null) {
throw new PgpGeneralException(mContext.getString(R.string.error_no_signature_passphrase));
}
PBESecretKeyDecryptor keyDecryptor = new JcePBESecretKeyDecryptorBuilder().setProvider(
Constants.BOUNCY_CASTLE_PROVIDER_NAME).build(mSignaturePassphrase.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(), mSignatureHashAlgorithm)
.setProvider(Constants.BOUNCY_CASTLE_PROVIDER_NAME);
PGPSignatureGenerator signatureGenerator = null;
PGPV3SignatureGenerator signatureV3Generator = null;
if (mSignatureForceV3) {
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(signingKeyRing.getSecretKey());
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 (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 (mSignatureForceV3) {
processLine(line, null, signatureV3Generator);
signatureV3Generator.update(newline);
} else {
processLine(line, null, signatureGenerator);
signatureGenerator.update(newline);
}
}
// }
BCPGOutputStream bOut = new BCPGOutputStream(out);
if (mSignatureForceV3) {
signatureV3Generator.generate().encode(bOut);
} else {
signatureGenerator.generate().encode(bOut);
}
out.close();
mOutStream.close();
updateProgress(R.string.progress_done, 100, 100);
}
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput,
final PGPSignatureGenerator pSignatureGenerator) final PGPSignatureGenerator pSignatureGenerator)
throws IOException, SignatureException { throws IOException, SignatureException {
@ -610,8 +562,8 @@ public class PgpSignEncrypt {
pSignatureGenerator.update(data); pSignatureGenerator.update(data);
} }
private static void processLine(final String pLine, final ArmoredOutputStream pArmoredOutput, private static void processLineV3(final String pLine, final ArmoredOutputStream pArmoredOutput,
final PGPV3SignatureGenerator pSignatureGenerator) final PGPV3SignatureGenerator pSignatureGenerator)
throws IOException, SignatureException { throws IOException, SignatureException {
if (pLine == null) { if (pLine == null) {