mirror of
https://github.com/moparisthebest/open-keychain
synced 2024-11-27 11:12:15 -05:00
tests: add multi key encryption/decryption test, new way for fake passphrase cache
This commit is contained in:
parent
bf537c4a81
commit
5e9d8ca8c6
@ -119,7 +119,7 @@ public class PgpEncryptDecryptTest {
|
|||||||
InputData data = new InputData(in, in.available());
|
InputData data = new InputData(in, in.available());
|
||||||
Builder b = new PgpSignEncrypt.Builder(Robolectric.application,
|
Builder b = new PgpSignEncrypt.Builder(Robolectric.application,
|
||||||
new ProviderHelper(Robolectric.application),
|
new ProviderHelper(Robolectric.application),
|
||||||
null, // new DummyPassphraseCache(mPassphrase, 0L)
|
null,
|
||||||
data, out);
|
data, out);
|
||||||
|
|
||||||
b.setSymmetricPassphrase(mPassphrase);
|
b.setSymmetricPassphrase(mPassphrase);
|
||||||
@ -216,11 +216,8 @@ public class PgpEncryptDecryptTest {
|
|||||||
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||||
InputData data = new InputData(in, in.available());
|
InputData data = new InputData(in, in.available());
|
||||||
|
|
||||||
PgpDecryptVerify.Builder b = new PgpDecryptVerify.Builder(
|
|
||||||
Robolectric.application,
|
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out, null, null, null);
|
||||||
new ProviderHelper(Robolectric.application),
|
|
||||||
null, // new DummyPassphraseCache(null, null),
|
|
||||||
data, out);
|
|
||||||
b.setPassphrase(mKeyPhrase1);
|
b.setPassphrase(mKeyPhrase1);
|
||||||
DecryptVerifyResult result = b.build().execute();
|
DecryptVerifyResult result = b.build().execute();
|
||||||
Assert.assertTrue("decryption with provided passphrase must succeed", result.success());
|
Assert.assertTrue("decryption with provided passphrase must succeed", result.success());
|
||||||
@ -231,74 +228,157 @@ public class PgpEncryptDecryptTest {
|
|||||||
|
|
||||||
// TODO how to test passphrase cache?
|
// TODO how to test passphrase cache?
|
||||||
|
|
||||||
/*{ // decryption with passphrase cached should succeed
|
{ // decryption with passphrase cached should succeed
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||||
InputData data = new InputData(in, in.available());
|
InputData data = new InputData(in, in.available());
|
||||||
|
|
||||||
PassphraseCacheService.addCachedPassphrase(
|
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
|
||||||
Robolectric.application, mStaticRing1.getMasterKeyId(),
|
mKeyPhrase1, mStaticRing1.getMasterKeyId(), null);
|
||||||
mStaticRing1.getMasterKeyId(), mKeyPhrase1, "dummy");
|
|
||||||
|
|
||||||
PgpDecryptVerify.Builder b = new PgpDecryptVerify.Builder(
|
|
||||||
Robolectric.application,
|
|
||||||
new ProviderHelper(Robolectric.application),
|
|
||||||
null, // new DummyPassphraseCache(mKeyPhrase1, null),
|
|
||||||
data, out);
|
|
||||||
DecryptVerifyResult result = b.build().execute();
|
DecryptVerifyResult result = b.build().execute();
|
||||||
Assert.assertTrue("decryption with cached passphrase must succeed", result.success());
|
Assert.assertTrue("decryption with cached passphrase must succeed", result.success());
|
||||||
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
|
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
|
||||||
out.toByteArray(), plaintext.getBytes());
|
out.toByteArray(), plaintext.getBytes());
|
||||||
Assert.assertNull("signature should be empty", result.getSignatureResult());
|
Assert.assertNull("signature should be empty", result.getSignatureResult());
|
||||||
}*/
|
}
|
||||||
|
|
||||||
/*{ // decryption with no passphrase provided should return status pending
|
{ // decryption with no passphrase provided should return status pending
|
||||||
|
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||||
InputData data = new InputData(in, in.available());
|
InputData data = new InputData(in, in.available());
|
||||||
|
|
||||||
PgpDecryptVerify.Builder b = new PgpDecryptVerify.Builder(
|
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
|
||||||
Robolectric.application,
|
null, mStaticRing1.getMasterKeyId(), null);
|
||||||
new ProviderHelper(Robolectric.application),
|
|
||||||
null, // new DummyPassphraseCache(null, null),
|
|
||||||
data, out);
|
|
||||||
DecryptVerifyResult result = b.build().execute();
|
DecryptVerifyResult result = b.build().execute();
|
||||||
Assert.assertFalse("decryption with no passphrase must return pending", result.success());
|
Assert.assertFalse("decryption with no passphrase must return pending", result.success());
|
||||||
Assert.assertTrue("decryption with no passphrase should return pending", result.isPending());
|
Assert.assertTrue("decryption with no passphrase should return pending", result.isPending());
|
||||||
Assert.assertEquals("decryption with no passphrase should return pending passphrase",
|
Assert.assertEquals("decryption with no passphrase should return pending passphrase",
|
||||||
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, result.getResult());
|
DecryptVerifyResult.RESULT_PENDING_ASYM_PASSPHRASE, result.getResult());
|
||||||
}*/
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static class DummyPassphraseCache implements PassphraseCacheInterface {
|
@Test
|
||||||
|
public void testMultiAsymmetricEncryptDecrypt() {
|
||||||
|
|
||||||
String mPassphrase;
|
String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
|
||||||
Long mExpectedId;
|
byte[] ciphertext;
|
||||||
public DummyPassphraseCache(String passphrase, Long expectedId) {
|
|
||||||
mPassphrase = passphrase;
|
{ // encrypt data with a given passphrase
|
||||||
mExpectedId = expectedId;
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
|
||||||
|
|
||||||
|
InputData data = new InputData(in, in.available());
|
||||||
|
Builder b = new PgpSignEncrypt.Builder(
|
||||||
|
Robolectric.application,
|
||||||
|
new ProviderHelper(Robolectric.application),
|
||||||
|
null, // new DummyPassphraseCache(mPassphrase, 0L),
|
||||||
|
data, out);
|
||||||
|
|
||||||
|
b.setEncryptionMasterKeyIds(new long[] {
|
||||||
|
mStaticRing1.getMasterKeyId(),
|
||||||
|
mStaticRing2.getMasterKeyId()
|
||||||
|
});
|
||||||
|
b.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
|
||||||
|
SignEncryptResult result = b.build().execute();
|
||||||
|
Assert.assertTrue("encryption must succeed", result.success());
|
||||||
|
|
||||||
|
ciphertext = out.toByteArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
{ // decryption with passphrase cached should succeed for the first key
|
||||||
public String getCachedPassphrase(long masterKeyId, long subKeyId) throws NoSecretKeyException {
|
|
||||||
if (mExpectedId != null){
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
Assert.assertEquals("requested passphrase must be for expected id",
|
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||||
(long) mExpectedId, subKeyId);
|
InputData data = new InputData(in, in.available());
|
||||||
|
|
||||||
|
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
|
||||||
|
mKeyPhrase1, mStaticRing1.getMasterKeyId(), null);
|
||||||
|
|
||||||
|
DecryptVerifyResult result = b.build().execute();
|
||||||
|
Assert.assertTrue("decryption with cached passphrase must succeed for the first key", result.success());
|
||||||
|
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
|
||||||
|
out.toByteArray(), plaintext.getBytes());
|
||||||
|
Assert.assertNull("signature should be empty", result.getSignatureResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // decryption with passphrase cached should succeed for the first key
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||||
|
InputData data = new InputData(in, in.available());
|
||||||
|
|
||||||
|
// allow only the second to decrypt
|
||||||
|
HashSet<Long> allowed = new HashSet<Long>();
|
||||||
|
allowed.add(mStaticRing2.getMasterKeyId());
|
||||||
|
|
||||||
|
// provide passphrase for the second, and check that the first is never asked for!
|
||||||
|
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
|
||||||
|
mKeyPhrase2, mStaticRing2.getMasterKeyId(), null);
|
||||||
|
b.setAllowedKeyIds(allowed);
|
||||||
|
|
||||||
|
DecryptVerifyResult result = b.build().execute();
|
||||||
|
Assert.assertTrue("decryption with cached passphrase must succeed for the first key", result.success());
|
||||||
|
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
|
||||||
|
out.toByteArray(), plaintext.getBytes());
|
||||||
|
Assert.assertNull("signature should be empty", result.getSignatureResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // decryption with passphrase cached should succeed for the other key if first is gone
|
||||||
|
|
||||||
|
// delete first key from database
|
||||||
|
new ProviderHelper(Robolectric.application).getContentResolver().delete(
|
||||||
|
KeyRingData.buildPublicKeyRingUri(mStaticRing1.getMasterKeyId()), null, null
|
||||||
|
);
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(ciphertext);
|
||||||
|
InputData data = new InputData(in, in.available());
|
||||||
|
|
||||||
|
PgpDecryptVerify.Builder b = builderWithFakePassphraseCache(data, out,
|
||||||
|
mKeyPhrase2, mStaticRing2.getMasterKeyId(), null);
|
||||||
|
|
||||||
|
DecryptVerifyResult result = b.build().execute();
|
||||||
|
Assert.assertTrue("decryption with cached passphrase must succeed", result.success());
|
||||||
|
Assert.assertArrayEquals("decrypted ciphertext with cached passphrase should equal plaintext",
|
||||||
|
out.toByteArray(), plaintext.getBytes());
|
||||||
|
Assert.assertNull("signature should be empty", result.getSignatureResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private PgpDecryptVerify.Builder builderWithFakePassphraseCache (
|
||||||
|
InputData data, OutputStream out,
|
||||||
|
final String passphrase, final Long checkMasterKeyId, final Long checkSubKeyId) {
|
||||||
|
|
||||||
|
return new PgpDecryptVerify.Builder(Robolectric.application,
|
||||||
|
new ProviderHelper(Robolectric.application),
|
||||||
|
null,
|
||||||
|
data, out) {
|
||||||
|
public PgpDecryptVerify build() {
|
||||||
|
return new PgpDecryptVerify(this) {
|
||||||
|
@Override
|
||||||
|
public String getCachedPassphrase(long masterKeyId, long subKeyId)
|
||||||
|
throws NoSecretKeyException {
|
||||||
|
if (checkMasterKeyId != null) {
|
||||||
|
Assert.assertEquals("requested passphrase should be for expected master key id",
|
||||||
|
(long) checkMasterKeyId, masterKeyId);
|
||||||
|
}
|
||||||
|
if (checkSubKeyId != null) {
|
||||||
|
Assert.assertEquals("requested passphrase should be for expected sub key id",
|
||||||
|
(long) checkSubKeyId, subKeyId);
|
||||||
|
}
|
||||||
|
if (passphrase == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return passphrase;
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return mPassphrase;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCachedPassphrase(long subKeyId) throws NoSecretKeyException {
|
|
||||||
if (mExpectedId != null){
|
|
||||||
Assert.assertEquals("requested passphrase must be for expected id",
|
|
||||||
(long) mExpectedId, subKeyId);
|
|
||||||
}
|
|
||||||
return mPassphrase;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ public class PgpDecryptVerify extends BaseOperation {
|
|||||||
private boolean mDecryptMetadataOnly;
|
private boolean mDecryptMetadataOnly;
|
||||||
private byte[] mDecryptedSessionKey;
|
private byte[] mDecryptedSessionKey;
|
||||||
|
|
||||||
private PgpDecryptVerify(Builder builder) {
|
protected PgpDecryptVerify(Builder builder) {
|
||||||
super(builder.mContext, builder.mProviderHelper, builder.mProgressable);
|
super(builder.mContext, builder.mProviderHelper, builder.mProgressable);
|
||||||
|
|
||||||
// private Constructor can only be called from Builder
|
// private Constructor can only be called from Builder
|
||||||
|
@ -95,7 +95,7 @@ public class PgpSignEncrypt extends BaseOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private PgpSignEncrypt(Builder builder) {
|
protected PgpSignEncrypt(Builder builder) {
|
||||||
super(builder.mContext, builder.mProviderHelper, builder.mProgressable);
|
super(builder.mContext, builder.mProviderHelper, builder.mProgressable);
|
||||||
|
|
||||||
// private Constructor can only be called from Builder
|
// private Constructor can only be called from Builder
|
||||||
|
Loading…
Reference in New Issue
Block a user