tests: make sure encryption happens to all enc-capable subkeys
This commit is contained in:
@@ -279,7 +279,7 @@ public class PgpSignEncryptOperation extends BaseOperation {
|
|||||||
CanonicalizedPublicKey key = keyRing.getPublicKey(subKeyId);
|
CanonicalizedPublicKey key = keyRing.getPublicKey(subKeyId);
|
||||||
cPk.addMethod(key.getPubKeyEncryptionGenerator(input.isHiddenRecipients()));
|
cPk.addMethod(key.getPubKeyEncryptionGenerator(input.isHiddenRecipients()));
|
||||||
log.add(LogType.MSG_PSE_KEY_OK, indent + 1,
|
log.add(LogType.MSG_PSE_KEY_OK, indent + 1,
|
||||||
KeyFormattingUtils.convertKeyIdToHex(id));
|
KeyFormattingUtils.convertKeyIdToHex(subKeyId));
|
||||||
}
|
}
|
||||||
if (encryptSubKeyIds.isEmpty()) {
|
if (encryptSubKeyIds.isEmpty()) {
|
||||||
log.add(LogType.MSG_PSE_KEY_WARN, indent + 1,
|
log.add(LogType.MSG_PSE_KEY_WARN, indent + 1,
|
||||||
|
|||||||
@@ -17,6 +17,15 @@
|
|||||||
|
|
||||||
package org.sufficientlysecure.keychain.pgp;
|
package org.sufficientlysecure.keychain.pgp;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.security.Security;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
@@ -24,14 +33,19 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.openintents.openpgp.OpenPgpMetadata;
|
import org.openintents.openpgp.OpenPgpMetadata;
|
||||||
import org.openintents.openpgp.OpenPgpSignatureResult;
|
import org.openintents.openpgp.OpenPgpSignatureResult;
|
||||||
import org.robolectric.*;
|
import org.robolectric.RobolectricGradleTestRunner;
|
||||||
|
import org.robolectric.RuntimeEnvironment;
|
||||||
import org.robolectric.annotation.Config;
|
import org.robolectric.annotation.Config;
|
||||||
import org.robolectric.shadows.ShadowLog;
|
import org.robolectric.shadows.ShadowLog;
|
||||||
|
import org.spongycastle.bcpg.BCPGInputStream;
|
||||||
|
import org.spongycastle.bcpg.Packet;
|
||||||
|
import org.spongycastle.bcpg.PacketTags;
|
||||||
|
import org.spongycastle.bcpg.PublicKeyEncSessionPacket;
|
||||||
import org.spongycastle.bcpg.sig.KeyFlags;
|
import org.spongycastle.bcpg.sig.KeyFlags;
|
||||||
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
import org.spongycastle.jce.provider.BouncyCastleProvider;
|
||||||
import org.spongycastle.openpgp.PGPEncryptedData;
|
import org.spongycastle.openpgp.PGPEncryptedData;
|
||||||
import org.sufficientlysecure.keychain.BuildConfig;
|
|
||||||
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
|
import org.sufficientlysecure.keychain.WorkaroundBuildConfig;
|
||||||
|
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
import org.sufficientlysecure.keychain.operations.results.OperationResult.LogType;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpEditKeyResult;
|
||||||
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
|
import org.sufficientlysecure.keychain.operations.results.PgpSignEncryptResult;
|
||||||
@@ -39,21 +53,19 @@ import org.sufficientlysecure.keychain.provider.KeychainContract.KeyRingData;
|
|||||||
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
import org.sufficientlysecure.keychain.provider.ProviderHelper;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel;
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.Algorithm;
|
||||||
import org.sufficientlysecure.keychain.operations.results.DecryptVerifyResult;
|
|
||||||
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
import org.sufficientlysecure.keychain.service.SaveKeyringParcel.ChangeUnlockParcel;
|
||||||
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
import org.sufficientlysecure.keychain.service.input.CryptoInputParcel;
|
||||||
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
|
import org.sufficientlysecure.keychain.service.input.RequiredInputParcel.RequiredInputType;
|
||||||
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper;
|
||||||
|
import org.sufficientlysecure.keychain.support.KeyringTestingHelper.RawPacket;
|
||||||
import org.sufficientlysecure.keychain.util.InputData;
|
import org.sufficientlysecure.keychain.util.InputData;
|
||||||
import org.sufficientlysecure.keychain.util.Passphrase;
|
import org.sufficientlysecure.keychain.util.Passphrase;
|
||||||
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
import org.sufficientlysecure.keychain.util.ProgressScaler;
|
||||||
import org.sufficientlysecure.keychain.util.TestingUtils;
|
import org.sufficientlysecure.keychain.util.TestingUtils;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import static org.hamcrest.core.AnyOf.anyOf;
|
||||||
import java.io.ByteArrayOutputStream;
|
import static org.hamcrest.core.Is.is;
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.security.Security;
|
|
||||||
import java.util.HashSet;
|
|
||||||
|
|
||||||
@RunWith(RobolectricGradleTestRunner.class)
|
@RunWith(RobolectricGradleTestRunner.class)
|
||||||
@Config(constants = WorkaroundBuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml")
|
@Config(constants = WorkaroundBuildConfig.class, sdk = 21, manifest = "src/main/AndroidManifest.xml")
|
||||||
@@ -83,6 +95,8 @@ public class PgpEncryptDecryptTest {
|
|||||||
Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
Algorithm.DSA, 1024, null, KeyFlags.SIGN_DATA, 0L));
|
||||||
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
Algorithm.ELGAMAL, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
||||||
|
parcel.mAddSubKeys.add(new SaveKeyringParcel.SubkeyAdd(
|
||||||
|
Algorithm.RSA, 1024, null, KeyFlags.ENCRYPT_COMMS, 0L));
|
||||||
parcel.mAddUserIds.add("bloom");
|
parcel.mAddUserIds.add("bloom");
|
||||||
parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase1);
|
parcel.mNewUnlock = new ChangeUnlockParcel(mKeyPhrase1);
|
||||||
|
|
||||||
@@ -326,6 +340,101 @@ public class PgpEncryptDecryptTest {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAsymmetricMultiSubkeyEncrypt() throws Exception {
|
||||||
|
|
||||||
|
String plaintext = "dies ist ein plaintext ☭" + TestingUtils.genPassphrase(true);
|
||||||
|
|
||||||
|
{ // encrypt data with key
|
||||||
|
byte[] ciphertext;
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
|
||||||
|
|
||||||
|
PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application,
|
||||||
|
new ProviderHelper(RuntimeEnvironment.application), null);
|
||||||
|
|
||||||
|
InputData data = new InputData(in, in.available());
|
||||||
|
PgpSignEncryptInputParcel input = new PgpSignEncryptInputParcel();
|
||||||
|
|
||||||
|
input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() });
|
||||||
|
input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
|
||||||
|
PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(), data, out);
|
||||||
|
Assert.assertTrue("encryption must succeed", result.success());
|
||||||
|
|
||||||
|
ciphertext = out.toByteArray();
|
||||||
|
|
||||||
|
Iterator<RawPacket> packets = KeyringTestingHelper.parseKeyring(ciphertext);
|
||||||
|
|
||||||
|
RawPacket enc1 = packets.next(), enc2 = packets.next();
|
||||||
|
Assert.assertEquals("last packet must be encrypted data packet",
|
||||||
|
PacketTags.SYM_ENC_INTEGRITY_PRO, packets.next().tag);
|
||||||
|
Assert.assertFalse("no further packets", packets.hasNext());
|
||||||
|
|
||||||
|
Packet p;
|
||||||
|
p = new BCPGInputStream(new ByteArrayInputStream(enc1.buf)).readPacket();
|
||||||
|
Assert.assertTrue("first packet must be session packet", p instanceof PublicKeyEncSessionPacket);
|
||||||
|
long encKeyId1 = ((PublicKeyEncSessionPacket) p).getKeyID();
|
||||||
|
|
||||||
|
p = new BCPGInputStream(new ByteArrayInputStream(enc2.buf)).readPacket();
|
||||||
|
Assert.assertTrue("second packet must be session packet", p instanceof PublicKeyEncSessionPacket);
|
||||||
|
long encKeyId2 = ((PublicKeyEncSessionPacket) p).getKeyID();
|
||||||
|
|
||||||
|
Assert.assertNotEquals("encrypted-to subkey ids must not be equal",
|
||||||
|
encKeyId1, encKeyId2);
|
||||||
|
Assert.assertThat("first packet must be encrypted to one of the subkeys",
|
||||||
|
KeyringTestingHelper.getSubkeyId(mStaticRing1, 2), anyOf(is(encKeyId1), is(encKeyId2)));
|
||||||
|
Assert.assertThat("second packet must be encrypted to one of the subkeys",
|
||||||
|
KeyringTestingHelper.getSubkeyId(mStaticRing1, 3), anyOf(is(encKeyId1), is(encKeyId2)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // revoke first encryption subkey of keyring in database
|
||||||
|
SaveKeyringParcel parcel = new SaveKeyringParcel(mStaticRing1.getMasterKeyId(), mStaticRing1.getFingerprint());
|
||||||
|
parcel.mRevokeSubKeys.add(KeyringTestingHelper.getSubkeyId(mStaticRing1, 2));
|
||||||
|
UncachedKeyRing modified = PgpKeyOperationTest.applyModificationWithChecks(parcel, mStaticRing1,
|
||||||
|
new ArrayList<RawPacket>(), new ArrayList<RawPacket>(), new CryptoInputParcel(mKeyPhrase1));
|
||||||
|
|
||||||
|
ProviderHelper providerHelper = new ProviderHelper(RuntimeEnvironment.application);
|
||||||
|
providerHelper.saveSecretKeyRing(modified, new ProgressScaler());
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // encrypt to this keyring, make sure it's not encrypted to the revoked subkey
|
||||||
|
byte[] ciphertext;
|
||||||
|
|
||||||
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
|
ByteArrayInputStream in = new ByteArrayInputStream(plaintext.getBytes());
|
||||||
|
|
||||||
|
PgpSignEncryptOperation op = new PgpSignEncryptOperation(RuntimeEnvironment.application,
|
||||||
|
new ProviderHelper(RuntimeEnvironment.application), null);
|
||||||
|
|
||||||
|
InputData data = new InputData(in, in.available());
|
||||||
|
PgpSignEncryptInputParcel input = new PgpSignEncryptInputParcel();
|
||||||
|
|
||||||
|
input.setEncryptionMasterKeyIds(new long[] { mStaticRing1.getMasterKeyId() });
|
||||||
|
input.setSymmetricEncryptionAlgorithm(PGPEncryptedData.AES_128);
|
||||||
|
PgpSignEncryptResult result = op.execute(input, new CryptoInputParcel(), data, out);
|
||||||
|
Assert.assertTrue("encryption must succeed", result.success());
|
||||||
|
|
||||||
|
ciphertext = out.toByteArray();
|
||||||
|
|
||||||
|
Iterator<RawPacket> packets = KeyringTestingHelper.parseKeyring(ciphertext);
|
||||||
|
|
||||||
|
RawPacket enc1 = packets.next();
|
||||||
|
Assert.assertEquals("last packet must be encrypted data packet",
|
||||||
|
PacketTags.SYM_ENC_INTEGRITY_PRO, packets.next().tag);
|
||||||
|
Assert.assertFalse("no further packets", packets.hasNext());
|
||||||
|
|
||||||
|
Packet p;
|
||||||
|
p = new BCPGInputStream(new ByteArrayInputStream(enc1.buf)).readPacket();
|
||||||
|
Assert.assertTrue("first packet must be session packet", p instanceof PublicKeyEncSessionPacket);
|
||||||
|
Assert.assertEquals("first packet must be encrypted to second enc subkey",
|
||||||
|
KeyringTestingHelper.getSubkeyId(mStaticRing1, 3), ((PublicKeyEncSessionPacket) p).getKeyID());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultiAsymmetricEncryptDecrypt() {
|
public void testMultiAsymmetricEncryptDecrypt() {
|
||||||
|
|
||||||
|
|||||||
@@ -1240,14 +1240,14 @@ public class PgpKeyOperationTest {
|
|||||||
Assert.assertFalse("non-restricted operations should fail without passphrase", result.success());
|
Assert.assertFalse("non-restricted operations should fail without passphrase", result.success());
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
|
public static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
|
||||||
UncachedKeyRing ring,
|
UncachedKeyRing ring,
|
||||||
ArrayList<RawPacket> onlyA,
|
ArrayList<RawPacket> onlyA,
|
||||||
ArrayList<RawPacket> onlyB) {
|
ArrayList<RawPacket> onlyB) {
|
||||||
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, cryptoInput, true, true);
|
return applyModificationWithChecks(parcel, ring, onlyA, onlyB, cryptoInput, true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
|
public static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
|
||||||
UncachedKeyRing ring,
|
UncachedKeyRing ring,
|
||||||
ArrayList<RawPacket> onlyA,
|
ArrayList<RawPacket> onlyA,
|
||||||
ArrayList<RawPacket> onlyB,
|
ArrayList<RawPacket> onlyB,
|
||||||
@@ -1256,7 +1256,7 @@ public class PgpKeyOperationTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// applies a parcel modification while running some integrity checks
|
// applies a parcel modification while running some integrity checks
|
||||||
private static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
|
public static UncachedKeyRing applyModificationWithChecks(SaveKeyringParcel parcel,
|
||||||
UncachedKeyRing ring,
|
UncachedKeyRing ring,
|
||||||
ArrayList<RawPacket> onlyA,
|
ArrayList<RawPacket> onlyA,
|
||||||
ArrayList<RawPacket> onlyB,
|
ArrayList<RawPacket> onlyB,
|
||||||
|
|||||||
Reference in New Issue
Block a user