added an Intent and functionality to generate detached signatures
This commit is contained in:
@@ -124,6 +124,7 @@
|
|||||||
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT" />
|
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT" />
|
||||||
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT_FILE" />
|
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT_FILE" />
|
||||||
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT_AND_RETURN" />
|
<action android:name="org.thialfihar.android.apg.intent.ENCRYPT_AND_RETURN" />
|
||||||
|
<action android:name="org.thialfihar.android.apg.intent.GENERATE_SIGNATURE" />
|
||||||
<category android:name="android.intent.category.DEFAULT"/>
|
<category android:name="android.intent.category.DEFAULT"/>
|
||||||
<data android:mimeType="*/*"/>
|
<data android:mimeType="*/*"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
|||||||
@@ -118,6 +118,7 @@ public class Apg {
|
|||||||
public static final String IMPORT = "org.thialfihar.android.apg.intent.IMPORT";
|
public static final String IMPORT = "org.thialfihar.android.apg.intent.IMPORT";
|
||||||
public static final String LOOK_UP_KEY_ID = "org.thialfihar.android.apg.intent.LOOK_UP_KEY_ID";
|
public static final String LOOK_UP_KEY_ID = "org.thialfihar.android.apg.intent.LOOK_UP_KEY_ID";
|
||||||
public static final String LOOK_UP_KEY_ID_AND_RETURN = "org.thialfihar.android.apg.intent.LOOK_UP_KEY_ID_AND_RETURN";
|
public static final String LOOK_UP_KEY_ID_AND_RETURN = "org.thialfihar.android.apg.intent.LOOK_UP_KEY_ID_AND_RETURN";
|
||||||
|
public static final String GENERATE_SIGNATURE = "org.thialfihar.android.apg.intent.GENERATE_SIGNATURE";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String EXTRA_TEXT = "text";
|
public static final String EXTRA_TEXT = "text";
|
||||||
@@ -133,6 +134,8 @@ public class Apg {
|
|||||||
public static final String EXTRA_SIGNATURE_USER_ID = "signatureUserId";
|
public static final String EXTRA_SIGNATURE_USER_ID = "signatureUserId";
|
||||||
public static final String EXTRA_SIGNATURE_SUCCESS = "signatureSuccess";
|
public static final String EXTRA_SIGNATURE_SUCCESS = "signatureSuccess";
|
||||||
public static final String EXTRA_SIGNATURE_UNKNOWN = "signatureUnknown";
|
public static final String EXTRA_SIGNATURE_UNKNOWN = "signatureUnknown";
|
||||||
|
public static final String EXTRA_SIGNATURE_DATA = "signatureData";
|
||||||
|
public static final String EXTRA_SIGNATURE_TEXT = "signatureText";
|
||||||
public static final String EXTRA_USER_ID = "userId";
|
public static final String EXTRA_USER_ID = "userId";
|
||||||
public static final String EXTRA_USER_IDS = "userIds";
|
public static final String EXTRA_USER_IDS = "userIds";
|
||||||
public static final String EXTRA_KEY_ID = "keyId";
|
public static final String EXTRA_KEY_ID = "keyId";
|
||||||
@@ -1426,6 +1429,127 @@ public class Apg {
|
|||||||
progress.setProgress(R.string.progress_done, 100, 100);
|
progress.setProgress(R.string.progress_done, 100, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void generateSignature(Context context,
|
||||||
|
InputData data, OutputStream outStream,
|
||||||
|
boolean armored, boolean binary,
|
||||||
|
long signatureKeyId, String signaturePassPhrase,
|
||||||
|
int hashAlgorithm,
|
||||||
|
boolean forceV3Signature,
|
||||||
|
ProgressDialogUpdater progress)
|
||||||
|
throws GeneralException, PGPException, IOException, NoSuchAlgorithmException,
|
||||||
|
SignatureException {
|
||||||
|
Security.addProvider(new BouncyCastleProvider());
|
||||||
|
|
||||||
|
ArmoredOutputStream armorOut = null;
|
||||||
|
OutputStream out = null;
|
||||||
|
if (armored) {
|
||||||
|
armorOut = new ArmoredOutputStream(outStream);
|
||||||
|
armorOut.setHeader("Version", getFullVersion(context));
|
||||||
|
out = armorOut;
|
||||||
|
} else {
|
||||||
|
out = outStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPSecretKey signingKey = null;
|
||||||
|
PGPSecretKeyRing signingKeyRing = null;
|
||||||
|
PGPPrivateKey signaturePrivateKey = null;
|
||||||
|
|
||||||
|
if (signatureKeyId == 0) {
|
||||||
|
throw new GeneralException(context.getString(R.string.error_noSignatureKey));
|
||||||
|
}
|
||||||
|
|
||||||
|
signingKeyRing = getSecretKeyRing(signatureKeyId);
|
||||||
|
signingKey = getSigningKey(signatureKeyId);
|
||||||
|
if (signingKey == null) {
|
||||||
|
throw new GeneralException(context.getString(R.string.error_signatureFailed));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (signaturePassPhrase == null) {
|
||||||
|
throw new GeneralException(context.getString(R.string.error_noSignaturePassPhrase));
|
||||||
|
}
|
||||||
|
signaturePrivateKey =
|
||||||
|
signingKey.extractPrivateKey(signaturePassPhrase.toCharArray(),
|
||||||
|
new BouncyCastleProvider());
|
||||||
|
if (signaturePrivateKey == null) {
|
||||||
|
throw new GeneralException(context.getString(R.string.error_couldNotExtractPrivateKey));
|
||||||
|
}
|
||||||
|
progress.setProgress(R.string.progress_preparingStreams, 0, 100);
|
||||||
|
|
||||||
|
progress.setProgress(R.string.progress_preparingSignature, 30, 100);
|
||||||
|
|
||||||
|
PGPSignatureGenerator signatureGenerator = null;
|
||||||
|
PGPV3SignatureGenerator signatureV3Generator = null;
|
||||||
|
|
||||||
|
int type = PGPSignature.CANONICAL_TEXT_DOCUMENT;
|
||||||
|
if (binary) {
|
||||||
|
type = PGPSignature.BINARY_DOCUMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (forceV3Signature) {
|
||||||
|
signatureV3Generator =
|
||||||
|
new PGPV3SignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
|
||||||
|
hashAlgorithm,
|
||||||
|
new BouncyCastleProvider());
|
||||||
|
signatureV3Generator.initSign(type, signaturePrivateKey);
|
||||||
|
} else {
|
||||||
|
signatureGenerator =
|
||||||
|
new PGPSignatureGenerator(signingKey.getPublicKey().getAlgorithm(),
|
||||||
|
hashAlgorithm,
|
||||||
|
new BouncyCastleProvider());
|
||||||
|
signatureGenerator.initSign(type, signaturePrivateKey);
|
||||||
|
|
||||||
|
PGPSignatureSubpacketGenerator spGen = new PGPSignatureSubpacketGenerator();
|
||||||
|
String userId = getMainUserId(getMasterKey(signingKeyRing));
|
||||||
|
spGen.setSignerUserID(false, userId);
|
||||||
|
signatureGenerator.setHashedSubpackets(spGen.generate());
|
||||||
|
}
|
||||||
|
|
||||||
|
progress.setProgress(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 (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");
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
final String line = reader.readLine();
|
||||||
|
|
||||||
|
if (line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
outStream.close();
|
||||||
|
|
||||||
|
progress.setProgress(R.string.progress_done, 100, 100);
|
||||||
|
}
|
||||||
|
|
||||||
public static long getDecryptionKeyId(Context context, InputData data)
|
public static long getDecryptionKeyId(Context context, InputData data)
|
||||||
throws GeneralException, NoAsymmetricEncryptionException, IOException {
|
throws GeneralException, NoAsymmetricEncryptionException, IOException {
|
||||||
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
|
InputStream in = PGPUtil.getDecoderStream(data.getInputStream());
|
||||||
@@ -1867,7 +1991,9 @@ public class Apg {
|
|||||||
|
|
||||||
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
|
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
|
||||||
|
|
||||||
pArmoredOutput.write(data);
|
if (pArmoredOutput != null) {
|
||||||
|
pArmoredOutput.write(data);
|
||||||
|
}
|
||||||
pSignatureGenerator.update(data);
|
pSignatureGenerator.update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1892,7 +2018,9 @@ public class Apg {
|
|||||||
|
|
||||||
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
|
final byte[] data = pLine.substring(0, len).getBytes("UTF-8");
|
||||||
|
|
||||||
pArmoredOutput.write(data);
|
if (pArmoredOutput != null) {
|
||||||
|
pArmoredOutput.write(data);
|
||||||
|
}
|
||||||
pSignatureGenerator.update(data);
|
pSignatureGenerator.update(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,10 +36,20 @@ public class DataSource {
|
|||||||
|
|
||||||
public void setText(String text) {
|
public void setText(String text) {
|
||||||
mText = text;
|
mText = text;
|
||||||
|
mData = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setData(byte[] data) {
|
public void setData(byte[] data) {
|
||||||
mData = data;
|
mData = data;
|
||||||
|
mText = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isText() {
|
||||||
|
return mText != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isBinary() {
|
||||||
|
return mData != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputData getInputData(Context context, boolean withSize)
|
public InputData getInputData(Context context, boolean withSize)
|
||||||
|
|||||||
@@ -101,11 +101,15 @@ public class EncryptActivity extends BaseActivity {
|
|||||||
private DataSource mDataSource = null;
|
private DataSource mDataSource = null;
|
||||||
private DataDestination mDataDestination = null;
|
private DataDestination mDataDestination = null;
|
||||||
|
|
||||||
|
private boolean mGenerateSignature = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.encrypt);
|
setContentView(R.layout.encrypt);
|
||||||
|
|
||||||
|
mGenerateSignature = false;
|
||||||
|
|
||||||
mSource = (ViewFlipper) findViewById(R.id.source);
|
mSource = (ViewFlipper) findViewById(R.id.source);
|
||||||
mSourceLabel = (TextView) findViewById(R.id.sourceLabel);
|
mSourceLabel = (TextView) findViewById(R.id.sourceLabel);
|
||||||
mSourcePrevious = (ImageView) findViewById(R.id.sourcePrevious);
|
mSourcePrevious = (ImageView) findViewById(R.id.sourcePrevious);
|
||||||
@@ -271,17 +275,25 @@ public class EncryptActivity extends BaseActivity {
|
|||||||
mIntent = getIntent();
|
mIntent = getIntent();
|
||||||
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
|
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
|
||||||
Apg.Intent.ENCRYPT_FILE.equals(mIntent.getAction()) ||
|
Apg.Intent.ENCRYPT_FILE.equals(mIntent.getAction()) ||
|
||||||
Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
|
Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction()) ||
|
||||||
|
Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
|
||||||
mContentUri = mIntent.getData();
|
mContentUri = mIntent.getData();
|
||||||
Bundle extras = mIntent.getExtras();
|
Bundle extras = mIntent.getExtras();
|
||||||
if (extras == null) {
|
if (extras == null) {
|
||||||
extras = new Bundle();
|
extras = new Bundle();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
|
if (Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction()) ||
|
||||||
|
Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
|
||||||
mReturnResult = true;
|
mReturnResult = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
|
||||||
|
mGenerateSignature = true;
|
||||||
|
mOverrideAsciiArmour = true;
|
||||||
|
mAsciiArmourDemand = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (extras.containsKey(Apg.EXTRA_ASCII_ARMOUR)) {
|
if (extras.containsKey(Apg.EXTRA_ASCII_ARMOUR)) {
|
||||||
mAsciiArmourDemand = extras.getBoolean(Apg.EXTRA_ASCII_ARMOUR, true);
|
mAsciiArmourDemand = extras.getBoolean(Apg.EXTRA_ASCII_ARMOUR, true);
|
||||||
mOverrideAsciiArmour = true;
|
mOverrideAsciiArmour = true;
|
||||||
@@ -338,7 +350,8 @@ public class EncryptActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
|
if (Apg.Intent.ENCRYPT.equals(mIntent.getAction()) ||
|
||||||
Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction())) {
|
Apg.Intent.ENCRYPT_AND_RETURN.equals(mIntent.getAction()) ||
|
||||||
|
Apg.Intent.GENERATE_SIGNATURE.equals(mIntent.getAction())) {
|
||||||
if (textData != null) {
|
if (textData != null) {
|
||||||
mMessage.setText(textData);
|
mMessage.setText(textData);
|
||||||
}
|
}
|
||||||
@@ -660,7 +673,14 @@ public class EncryptActivity extends BaseActivity {
|
|||||||
useAsciiArmour = mAsciiArmourDemand;
|
useAsciiArmour = mAsciiArmourDemand;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (signOnly) {
|
if (mGenerateSignature) {
|
||||||
|
Apg.generateSignature(this, in, out, useAsciiArmour, mDataSource.isBinary(),
|
||||||
|
getSecretKeyId(),
|
||||||
|
Apg.getCachedPassPhrase(getSecretKeyId()),
|
||||||
|
mPreferences.getDefaultHashAlgorithm(),
|
||||||
|
mPreferences.getForceV3Signatures(),
|
||||||
|
this);
|
||||||
|
} else if (signOnly) {
|
||||||
Apg.signText(this, in, out, getSecretKeyId(),
|
Apg.signText(this, in, out, getSecretKeyId(),
|
||||||
Apg.getCachedPassPhrase(getSecretKeyId()),
|
Apg.getCachedPassPhrase(getSecretKeyId()),
|
||||||
mPreferences.getDefaultHashAlgorithm(),
|
mPreferences.getDefaultHashAlgorithm(),
|
||||||
@@ -680,11 +700,19 @@ public class EncryptActivity extends BaseActivity {
|
|||||||
out.close();
|
out.close();
|
||||||
if (mEncryptTarget != Id.target.file) {
|
if (mEncryptTarget != Id.target.file) {
|
||||||
if (useAsciiArmour) {
|
if (useAsciiArmour) {
|
||||||
data.putString(Apg.EXTRA_ENCRYPTED_MESSAGE,
|
String extraData = new String(((ByteArrayOutputStream)out).toByteArray());
|
||||||
new String(((ByteArrayOutputStream)out).toByteArray()));
|
if (mGenerateSignature) {
|
||||||
|
data.putString(Apg.EXTRA_SIGNATURE_TEXT, extraData);
|
||||||
|
} else {
|
||||||
|
data.putString(Apg.EXTRA_ENCRYPTED_MESSAGE, extraData);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data.putByteArray(Apg.EXTRA_ENCRYPTED_DATA,
|
byte extraData[] = ((ByteArrayOutputStream)out).toByteArray();
|
||||||
((ByteArrayOutputStream)out).toByteArray());
|
if (mGenerateSignature) {
|
||||||
|
data.putByteArray(Apg.EXTRA_SIGNATURE_DATA, extraData);
|
||||||
|
} else {
|
||||||
|
data.putByteArray(Apg.EXTRA_ENCRYPTED_DATA, extraData);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|||||||
Reference in New Issue
Block a user