mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-23 03:17:58 +01:00
Add and test GnuDummyKeyUtil
This commit is contained in:
parent
7467170bcc
commit
2487e3300a
5 changed files with 427 additions and 0 deletions
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.key.gnu_dummy_s2k;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.S2K;
|
||||||
|
|
||||||
|
public enum GNUExtension {
|
||||||
|
|
||||||
|
NO_PRIVATE_KEY(S2K.GNU_PROTECTION_MODE_NO_PRIVATE_KEY),
|
||||||
|
DIVERT_TO_CARD(S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD),
|
||||||
|
;
|
||||||
|
|
||||||
|
private final int id;
|
||||||
|
|
||||||
|
GNUExtension(int id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.key.gnu_dummy_s2k;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.PublicKeyPacket;
|
||||||
|
import org.bouncycastle.bcpg.S2K;
|
||||||
|
import org.bouncycastle.bcpg.SecretKeyPacket;
|
||||||
|
import org.bouncycastle.bcpg.SecretSubkeyPacket;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class GnuDummyKeyUtil {
|
||||||
|
|
||||||
|
private GnuDummyKeyUtil() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Builder modify(PGPSecretKeyRing secretKeys) {
|
||||||
|
return new Builder(secretKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class Builder {
|
||||||
|
|
||||||
|
private final PGPSecretKeyRing keys;
|
||||||
|
|
||||||
|
private Builder(PGPSecretKeyRing keys) {
|
||||||
|
this.keys = keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing removePrivateKeys(KeyFilter filter) {
|
||||||
|
return doIt(GNUExtension.NO_PRIVATE_KEY, null, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing divertPrivateKeysToCard(KeyFilter filter) {
|
||||||
|
return divertPrivateKeysToCard(filter, new byte[16]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PGPSecretKeyRing divertPrivateKeysToCard(KeyFilter filter, byte[] cardSerialNumber) {
|
||||||
|
return doIt(GNUExtension.DIVERT_TO_CARD, cardSerialNumber, filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PGPSecretKeyRing doIt(GNUExtension extension, byte[] serial, KeyFilter filter) {
|
||||||
|
byte[] encodedSerial = serial != null ? encodeSerial(serial) : null;
|
||||||
|
S2K s2k = extensionToS2K(extension);
|
||||||
|
|
||||||
|
List<PGPSecretKey> secretKeyList = new ArrayList<>();
|
||||||
|
for (PGPSecretKey secretKey : keys) {
|
||||||
|
if (!filter.filter(secretKey.getKeyID())) {
|
||||||
|
// No conversion, do not modify subkey
|
||||||
|
secretKeyList.add(secretKey);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
PublicKeyPacket publicKeyPacket = secretKey.getPublicKey().getPublicKeyPacket();
|
||||||
|
if (secretKey.isMasterKey()) {
|
||||||
|
SecretKeyPacket keyPacket = new SecretKeyPacket(publicKeyPacket,
|
||||||
|
0, 255, s2k, null, encodedSerial);
|
||||||
|
PGPSecretKey onCard = new PGPSecretKey(keyPacket, secretKey.getPublicKey());
|
||||||
|
secretKeyList.add(onCard);
|
||||||
|
} else {
|
||||||
|
SecretSubkeyPacket keyPacket = new SecretSubkeyPacket(publicKeyPacket,
|
||||||
|
0, 255, s2k, null, encodedSerial);
|
||||||
|
PGPSecretKey onCard = new PGPSecretKey(keyPacket, secretKey.getPublicKey());
|
||||||
|
secretKeyList.add(onCard);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PGPSecretKeyRing gnuDummyKey = new PGPSecretKeyRing(secretKeyList);
|
||||||
|
return gnuDummyKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] encodeSerial(byte[] serial) {
|
||||||
|
byte[] encoded = new byte[serial.length + 1];
|
||||||
|
encoded[0] = 0x10;
|
||||||
|
System.arraycopy(serial, 0, encoded, 1, serial.length);
|
||||||
|
return encoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
private S2K extensionToS2K(GNUExtension extension) {
|
||||||
|
S2K s2k = S2K.gnuDummyS2K(extension == GNUExtension.DIVERT_TO_CARD ?
|
||||||
|
S2K.GNUDummyParams.divertToCard() : S2K.GNUDummyParams.noPrivateKey());
|
||||||
|
return s2k;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface KeyFilter {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if the given key should be selected, false otherwise.
|
||||||
|
*
|
||||||
|
* @param keyId id of the key
|
||||||
|
* @return select
|
||||||
|
*/
|
||||||
|
boolean filter(long keyId);
|
||||||
|
|
||||||
|
static KeyFilter any() {
|
||||||
|
return keyId -> true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static KeyFilter only(long onlyKeyId) {
|
||||||
|
return keyId -> keyId == onlyKeyId;
|
||||||
|
}
|
||||||
|
|
||||||
|
static KeyFilter selected(Collection<Long> ids) {
|
||||||
|
return keyId -> ids.contains(keyId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utility classes related to creating keys with GNU DUMMY S2K values.
|
||||||
|
*/
|
||||||
|
package org.pgpainless.key.gnu_dummy_s2k;
|
|
@ -0,0 +1,82 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.decryption_verification;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.key.SubkeyIdentifier;
|
||||||
|
import org.pgpainless.key.gnu_dummy_s2k.GnuDummyKeyUtil;
|
||||||
|
import org.pgpainless.key.util.KeyIdUtil;
|
||||||
|
|
||||||
|
public class HardwareSecurityTest {
|
||||||
|
|
||||||
|
private static final String KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: DE2E 9AB2 6650 8191 53E7 D599 C176 507F 2B5D 43B3\n" +
|
||||||
|
"Comment: Alice <alice@pgpainless.org>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEY1vjgRYJKwYBBAHaRw8BAQdAXjLoPTOIOdvlFT2Nt3rcvLTVx5ujPBGghZ5S\n" +
|
||||||
|
"D5tEnyoAAP0fAUJTiPrxZYdzs6MP0KFo+Nmr/wb1PJHTkzmYpt4wkRKBtBxBbGlj\n" +
|
||||||
|
"ZSA8YWxpY2VAcGdwYWlubGVzcy5vcmc+iI8EExYKAEEFAmNb44EJEMF2UH8rXUOz\n" +
|
||||||
|
"FiEE3i6asmZQgZFT59WZwXZQfytdQ7MCngECmwEFFgIDAQAECwkIBwUVCgkICwKZ\n" +
|
||||||
|
"AQAAHLYA/AgW+YrpU+UqrwX2dhY6RAfgHTTMU89RHjaTHJx8pLrBAP4gthGof00a\n" +
|
||||||
|
"XEjwTWteDOO049SIp2AUfj9deJqtrQcHD5xdBGNb44ESCisGAQQBl1UBBQEBB0DN\n" +
|
||||||
|
"vUT3awa3YLmwf41LRpPrm7B87AOHfYIP8S9QJ4GDJgMBCAcAAP9bwlSaF+lti8JY\n" +
|
||||||
|
"qKFO3qt3ZYQMu1l/LRBle89ZB4zD+BDOiHUEGBYKAB0FAmNb44ECngECmwwFFgID\n" +
|
||||||
|
"AQAECwkIBwUVCgkICwAKCRDBdlB/K11Ds/TsAP9kvpUrCWnrWGq+a9n1CqEfCMX5\n" +
|
||||||
|
"cT+qzrwNf+J0L22KowD+M9SVO0qssiAqutLE9h9dGYLbEiFvsHzK3WSnjKYbIgac\n" +
|
||||||
|
"WARjW+OBFgkrBgEEAdpHDwEBB0BCPh8M5TnXSmG6Ygwp4j5RR4u3hmxl8CYjX4h/\n" +
|
||||||
|
"XtvvNwAA/RP04coSrLHVI6vUfbJk4MhWYeyhJBRYY0vGp7yq+wVtEpKI1QQYFgoA\n" +
|
||||||
|
"fQUCY1vjgQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmNb44EACgkQ\n" +
|
||||||
|
"mlozJSF7rXQW+AD/TA3YBxTd+YbBSwfgqzWNbfT9BBcFrdn3uPCsbvfmqXoA/3oj\n" +
|
||||||
|
"oupkgoaXesrGxn2k9hW9/GBXSvNcgY2txZ6/oYoIAAoJEMF2UH8rXUOziZ4A/0Xl\n" +
|
||||||
|
"xSZJWmkRpBh5AO8Cnqosz6j947IYAxS16ay+sIOHAP9aN9CUNJIIdHnHdFHO4GZz\n" +
|
||||||
|
"ejjknn4wt8NVJP97JxlnBQ==\n" +
|
||||||
|
"=qSQb\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetSingleIdOfHardwareBackedKey() throws IOException {
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY);
|
||||||
|
assertTrue(HardwareSecurity.getIdsOfHardwareBackedKeys(secretKeys).isEmpty());
|
||||||
|
long encryptionKeyId = KeyIdUtil.fromLongKeyId("0AAD8F5891262F50");
|
||||||
|
|
||||||
|
PGPSecretKeyRing withHardwareBackedEncryptionKey = GnuDummyKeyUtil.modify(secretKeys)
|
||||||
|
.divertPrivateKeysToCard(GnuDummyKeyUtil.KeyFilter.only(encryptionKeyId));
|
||||||
|
|
||||||
|
Set<SubkeyIdentifier> hardwareBackedKeys = HardwareSecurity
|
||||||
|
.getIdsOfHardwareBackedKeys(withHardwareBackedEncryptionKey);
|
||||||
|
assertEquals(Collections.singleton(new SubkeyIdentifier(secretKeys, encryptionKeyId)), hardwareBackedKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetIdsOfFullyHardwareBackedKey() throws IOException {
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY);
|
||||||
|
assertTrue(HardwareSecurity.getIdsOfHardwareBackedKeys(secretKeys).isEmpty());
|
||||||
|
|
||||||
|
PGPSecretKeyRing withHardwareBackedEncryptionKey = GnuDummyKeyUtil.modify(secretKeys)
|
||||||
|
.divertPrivateKeysToCard(GnuDummyKeyUtil.KeyFilter.any());
|
||||||
|
Set<SubkeyIdentifier> expected = new HashSet<>();
|
||||||
|
for (PGPSecretKey key : secretKeys) {
|
||||||
|
expected.add(new SubkeyIdentifier(secretKeys, key.getKeyID()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<SubkeyIdentifier> hardwareBackedKeys = HardwareSecurity
|
||||||
|
.getIdsOfHardwareBackedKeys(withHardwareBackedEncryptionKey);
|
||||||
|
|
||||||
|
assertEquals(expected, hardwareBackedKeys);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,199 @@
|
||||||
|
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.key.gnu_dummy_s2k;
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.S2K;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
|
import org.pgpainless.key.util.KeyIdUtil;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
public class GnuDummyKeyUtilTest {
|
||||||
|
// normal, non-hw-backed key
|
||||||
|
private static final String FULL_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: 01FD AB6C E04A 5078 79FE 4A18 C312 C97D A9F7 6A4F\n" +
|
||||||
|
"Comment: Hardy Hardware <hardy@hard.ware>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEY1vSiBYJKwYBBAHaRw8BAQdAQ58lZn/HOtg+1b1KS18odyQ6M4LaDdbJAyRf\n" +
|
||||||
|
"eBwCeTQAAPwJN+Xmr0jjN7RA9jgqXnxC/rcWHmdp/j9NdEd7K2Wbxw/rtCBIYXJk\n" +
|
||||||
|
"eSBIYXJkd2FyZSA8aGFyZHlAaGFyZC53YXJlPoiPBBMWCgBBBQJjW9KICRDDEsl9\n" +
|
||||||
|
"qfdqTxYhBAH9q2zgSlB4ef5KGMMSyX2p92pPAp4BApsBBRYCAwEABAsJCAcFFQoJ\n" +
|
||||||
|
"CAsCmQEAAPk2AP922T5TQ7hukFlpxX3ThMhieJnECGY5Eqt5U0/vEY1XdgD/eE1M\n" +
|
||||||
|
"l9qqx6QGcaNKe8deMe3EhTant6mS9tqMHp2/3gmcXQRjW9KIEgorBgEEAZdVAQUB\n" +
|
||||||
|
"AQdAVXBLNvNmFh9KX6iLmdNJM28Zc9PGnzEoAD9+T4p0lDwDAQgHAAD/fw9hnzeH\n" +
|
||||||
|
"VtBaHi6efXvnc4rdVj8zWk0LKo1clFd3bTAN+oh1BBgWCgAdBQJjW9KIAp4BApsM\n" +
|
||||||
|
"BRYCAwEABAsJCAcFFQoJCAsACgkQwxLJfan3ak/JyQD9GBj0vjtYZAf5Fi0eEKdi\n" +
|
||||||
|
"Ags0yZrQPkMs6eL+83te770A/jG0DeJy+88fOfWTj+mixO98PZPnQ0MybWC/1QUT\n" +
|
||||||
|
"vP0BnFgEY1vSiBYJKwYBBAHaRw8BAQdAvSYTD60t8vx10dSEBACUoIfVCpeOB30D\n" +
|
||||||
|
"6nfwJtbDT0YAAQCgnCsN9iX7s2TQd8NPggWs4QdhaFpb6olt3SlAvUy/wRBDiNUE\n" +
|
||||||
|
"GBYKAH0FAmNb0ogCngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJjW9KI\n" +
|
||||||
|
"AAoJEJQCL6VtwFtJDmMBAKqsGfRFQxJXyPgugWBgEaO5lt9fMM0yUxa76cmSWe5f\n" +
|
||||||
|
"AQD2oLSEW1GOgIs64+Z3gvtXopmeupT09HhI7ger98zDAwAKCRDDEsl9qfdqTwR6\n" +
|
||||||
|
"AP9Xftw8xZ7/MWhYImk/xheqPy07K4qo3T1pGKUvUqjWQQEAhE3r0oTcJn+KVCwG\n" +
|
||||||
|
"jF6AYiLOzO/R1x5bSlYD3FeJ3Qo=\n" +
|
||||||
|
"=+vXp\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----\n";
|
||||||
|
|
||||||
|
private static final long primaryKeyId = KeyIdUtil.fromLongKeyId("C312C97DA9F76A4F");
|
||||||
|
private static final long encryptionKeyId = KeyIdUtil.fromLongKeyId("6924D066714CE8C6");
|
||||||
|
private static final long signatureKeyId = KeyIdUtil.fromLongKeyId("94022FA56DC05B49");
|
||||||
|
private static final byte[] cardSerial = new byte[] {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
|
||||||
|
|
||||||
|
public static final String ALL_KEYS_ON_CARD = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: 01FD AB6C E04A 5078 79FE 4A18 C312 C97D A9F7 6A4F\n" +
|
||||||
|
"Comment: Hardy Hardware <hardy@hard.ware>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lEwEY1vSiBYJKwYBBAHaRw8BAQdAQ58lZn/HOtg+1b1KS18odyQ6M4LaDdbJAyRf\n" +
|
||||||
|
"eBwCeTT/AGUAR05VAhAAAQIDBAUGBwgJCgsMDQ4PtCBIYXJkeSBIYXJkd2FyZSA8\n" +
|
||||||
|
"aGFyZHlAaGFyZC53YXJlPoiPBBMWCgBBBQJjW9KICRDDEsl9qfdqTxYhBAH9q2zg\n" +
|
||||||
|
"SlB4ef5KGMMSyX2p92pPAp4BApsBBRYCAwEABAsJCAcFFQoJCAsCmQEAAPk2AP92\n" +
|
||||||
|
"2T5TQ7hukFlpxX3ThMhieJnECGY5Eqt5U0/vEY1XdgD/eE1Ml9qqx6QGcaNKe8de\n" +
|
||||||
|
"Me3EhTant6mS9tqMHp2/3gmcUQRjW9KIEgorBgEEAZdVAQUBAQdAVXBLNvNmFh9K\n" +
|
||||||
|
"X6iLmdNJM28Zc9PGnzEoAD9+T4p0lDwDAQgH/wBlAEdOVQIQAAECAwQFBgcICQoL\n" +
|
||||||
|
"DA0OD4h1BBgWCgAdBQJjW9KIAp4BApsMBRYCAwEABAsJCAcFFQoJCAsACgkQwxLJ\n" +
|
||||||
|
"fan3ak/JyQD9GBj0vjtYZAf5Fi0eEKdiAgs0yZrQPkMs6eL+83te770A/jG0DeJy\n" +
|
||||||
|
"+88fOfWTj+mixO98PZPnQ0MybWC/1QUTvP0BnEwEY1vSiBYJKwYBBAHaRw8BAQdA\n" +
|
||||||
|
"vSYTD60t8vx10dSEBACUoIfVCpeOB30D6nfwJtbDT0b/AGUAR05VAhAAAQIDBAUG\n" +
|
||||||
|
"BwgJCgsMDQ4PiNUEGBYKAH0FAmNb0ogCngECmwIFFgIDAQAECwkIBwUVCgkIC18g\n" +
|
||||||
|
"BBkWCgAGBQJjW9KIAAoJEJQCL6VtwFtJDmMBAKqsGfRFQxJXyPgugWBgEaO5lt9f\n" +
|
||||||
|
"MM0yUxa76cmSWe5fAQD2oLSEW1GOgIs64+Z3gvtXopmeupT09HhI7ger98zDAwAK\n" +
|
||||||
|
"CRDDEsl9qfdqTwR6AP9Xftw8xZ7/MWhYImk/xheqPy07K4qo3T1pGKUvUqjWQQEA\n" +
|
||||||
|
"hE3r0oTcJn+KVCwGjF6AYiLOzO/R1x5bSlYD3FeJ3Qo=\n" +
|
||||||
|
"=wsFa\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
public static final String PRIMARY_KEY_ON_CARD = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: 01FD AB6C E04A 5078 79FE 4A18 C312 C97D A9F7 6A4F\n" +
|
||||||
|
"Comment: Hardy Hardware <hardy@hard.ware>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lEwEY1vSiBYJKwYBBAHaRw8BAQdAQ58lZn/HOtg+1b1KS18odyQ6M4LaDdbJAyRf\n" +
|
||||||
|
"eBwCeTT/AGUAR05VAhAAAQIDBAUGBwgJCgsMDQ4PtCBIYXJkeSBIYXJkd2FyZSA8\n" +
|
||||||
|
"aGFyZHlAaGFyZC53YXJlPoiPBBMWCgBBBQJjW9KICRDDEsl9qfdqTxYhBAH9q2zg\n" +
|
||||||
|
"SlB4ef5KGMMSyX2p92pPAp4BApsBBRYCAwEABAsJCAcFFQoJCAsCmQEAAPk2AP92\n" +
|
||||||
|
"2T5TQ7hukFlpxX3ThMhieJnECGY5Eqt5U0/vEY1XdgD/eE1Ml9qqx6QGcaNKe8de\n" +
|
||||||
|
"Me3EhTant6mS9tqMHp2/3gmcXQRjW9KIEgorBgEEAZdVAQUBAQdAVXBLNvNmFh9K\n" +
|
||||||
|
"X6iLmdNJM28Zc9PGnzEoAD9+T4p0lDwDAQgHAAD/fw9hnzeHVtBaHi6efXvnc4rd\n" +
|
||||||
|
"Vj8zWk0LKo1clFd3bTAN+oh1BBgWCgAdBQJjW9KIAp4BApsMBRYCAwEABAsJCAcF\n" +
|
||||||
|
"FQoJCAsACgkQwxLJfan3ak/JyQD9GBj0vjtYZAf5Fi0eEKdiAgs0yZrQPkMs6eL+\n" +
|
||||||
|
"83te770A/jG0DeJy+88fOfWTj+mixO98PZPnQ0MybWC/1QUTvP0BnFgEY1vSiBYJ\n" +
|
||||||
|
"KwYBBAHaRw8BAQdAvSYTD60t8vx10dSEBACUoIfVCpeOB30D6nfwJtbDT0YAAQCg\n" +
|
||||||
|
"nCsN9iX7s2TQd8NPggWs4QdhaFpb6olt3SlAvUy/wRBDiNUEGBYKAH0FAmNb0ogC\n" +
|
||||||
|
"ngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJjW9KIAAoJEJQCL6VtwFtJ\n" +
|
||||||
|
"DmMBAKqsGfRFQxJXyPgugWBgEaO5lt9fMM0yUxa76cmSWe5fAQD2oLSEW1GOgIs6\n" +
|
||||||
|
"4+Z3gvtXopmeupT09HhI7ger98zDAwAKCRDDEsl9qfdqTwR6AP9Xftw8xZ7/MWhY\n" +
|
||||||
|
"Imk/xheqPy07K4qo3T1pGKUvUqjWQQEAhE3r0oTcJn+KVCwGjF6AYiLOzO/R1x5b\n" +
|
||||||
|
"SlYD3FeJ3Qo=\n" +
|
||||||
|
"=s+B1\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
public static final String ENCRYPTION_KEY_ON_CARD = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: 01FD AB6C E04A 5078 79FE 4A18 C312 C97D A9F7 6A4F\n" +
|
||||||
|
"Comment: Hardy Hardware <hardy@hard.ware>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEY1vSiBYJKwYBBAHaRw8BAQdAQ58lZn/HOtg+1b1KS18odyQ6M4LaDdbJAyRf\n" +
|
||||||
|
"eBwCeTQAAPwJN+Xmr0jjN7RA9jgqXnxC/rcWHmdp/j9NdEd7K2Wbxw/rtCBIYXJk\n" +
|
||||||
|
"eSBIYXJkd2FyZSA8aGFyZHlAaGFyZC53YXJlPoiPBBMWCgBBBQJjW9KICRDDEsl9\n" +
|
||||||
|
"qfdqTxYhBAH9q2zgSlB4ef5KGMMSyX2p92pPAp4BApsBBRYCAwEABAsJCAcFFQoJ\n" +
|
||||||
|
"CAsCmQEAAPk2AP922T5TQ7hukFlpxX3ThMhieJnECGY5Eqt5U0/vEY1XdgD/eE1M\n" +
|
||||||
|
"l9qqx6QGcaNKe8deMe3EhTant6mS9tqMHp2/3gmcUQRjW9KIEgorBgEEAZdVAQUB\n" +
|
||||||
|
"AQdAVXBLNvNmFh9KX6iLmdNJM28Zc9PGnzEoAD9+T4p0lDwDAQgH/wBlAEdOVQIQ\n" +
|
||||||
|
"AAECAwQFBgcICQoLDA0OD4h1BBgWCgAdBQJjW9KIAp4BApsMBRYCAwEABAsJCAcF\n" +
|
||||||
|
"FQoJCAsACgkQwxLJfan3ak/JyQD9GBj0vjtYZAf5Fi0eEKdiAgs0yZrQPkMs6eL+\n" +
|
||||||
|
"83te770A/jG0DeJy+88fOfWTj+mixO98PZPnQ0MybWC/1QUTvP0BnFgEY1vSiBYJ\n" +
|
||||||
|
"KwYBBAHaRw8BAQdAvSYTD60t8vx10dSEBACUoIfVCpeOB30D6nfwJtbDT0YAAQCg\n" +
|
||||||
|
"nCsN9iX7s2TQd8NPggWs4QdhaFpb6olt3SlAvUy/wRBDiNUEGBYKAH0FAmNb0ogC\n" +
|
||||||
|
"ngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJjW9KIAAoJEJQCL6VtwFtJ\n" +
|
||||||
|
"DmMBAKqsGfRFQxJXyPgugWBgEaO5lt9fMM0yUxa76cmSWe5fAQD2oLSEW1GOgIs6\n" +
|
||||||
|
"4+Z3gvtXopmeupT09HhI7ger98zDAwAKCRDDEsl9qfdqTwR6AP9Xftw8xZ7/MWhY\n" +
|
||||||
|
"Imk/xheqPy07K4qo3T1pGKUvUqjWQQEAhE3r0oTcJn+KVCwGjF6AYiLOzO/R1x5b\n" +
|
||||||
|
"SlYD3FeJ3Qo=\n" +
|
||||||
|
"=TPAl\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
public static final String SIGNATURE_KEY_ON_CARD = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: PGPainless\n" +
|
||||||
|
"Comment: 01FD AB6C E04A 5078 79FE 4A18 C312 C97D A9F7 6A4F\n" +
|
||||||
|
"Comment: Hardy Hardware <hardy@hard.ware>\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEY1vSiBYJKwYBBAHaRw8BAQdAQ58lZn/HOtg+1b1KS18odyQ6M4LaDdbJAyRf\n" +
|
||||||
|
"eBwCeTQAAPwJN+Xmr0jjN7RA9jgqXnxC/rcWHmdp/j9NdEd7K2Wbxw/rtCBIYXJk\n" +
|
||||||
|
"eSBIYXJkd2FyZSA8aGFyZHlAaGFyZC53YXJlPoiPBBMWCgBBBQJjW9KICRDDEsl9\n" +
|
||||||
|
"qfdqTxYhBAH9q2zgSlB4ef5KGMMSyX2p92pPAp4BApsBBRYCAwEABAsJCAcFFQoJ\n" +
|
||||||
|
"CAsCmQEAAPk2AP922T5TQ7hukFlpxX3ThMhieJnECGY5Eqt5U0/vEY1XdgD/eE1M\n" +
|
||||||
|
"l9qqx6QGcaNKe8deMe3EhTant6mS9tqMHp2/3gmcXQRjW9KIEgorBgEEAZdVAQUB\n" +
|
||||||
|
"AQdAVXBLNvNmFh9KX6iLmdNJM28Zc9PGnzEoAD9+T4p0lDwDAQgHAAD/fw9hnzeH\n" +
|
||||||
|
"VtBaHi6efXvnc4rdVj8zWk0LKo1clFd3bTAN+oh1BBgWCgAdBQJjW9KIAp4BApsM\n" +
|
||||||
|
"BRYCAwEABAsJCAcFFQoJCAsACgkQwxLJfan3ak/JyQD9GBj0vjtYZAf5Fi0eEKdi\n" +
|
||||||
|
"Ags0yZrQPkMs6eL+83te770A/jG0DeJy+88fOfWTj+mixO98PZPnQ0MybWC/1QUT\n" +
|
||||||
|
"vP0BnEwEY1vSiBYJKwYBBAHaRw8BAQdAvSYTD60t8vx10dSEBACUoIfVCpeOB30D\n" +
|
||||||
|
"6nfwJtbDT0b/AGUAR05VAhAAAQIDBAUGBwgJCgsMDQ4PiNUEGBYKAH0FAmNb0ogC\n" +
|
||||||
|
"ngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJjW9KIAAoJEJQCL6VtwFtJ\n" +
|
||||||
|
"DmMBAKqsGfRFQxJXyPgugWBgEaO5lt9fMM0yUxa76cmSWe5fAQD2oLSEW1GOgIs6\n" +
|
||||||
|
"4+Z3gvtXopmeupT09HhI7ger98zDAwAKCRDDEsl9qfdqTwR6AP9Xftw8xZ7/MWhY\n" +
|
||||||
|
"Imk/xheqPy07K4qo3T1pGKUvUqjWQQEAhE3r0oTcJn+KVCwGjF6AYiLOzO/R1x5b\n" +
|
||||||
|
"SlYD3FeJ3Qo=\n" +
|
||||||
|
"=p8I9\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveAllKeysToCard() throws IOException {
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||||
|
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(ALL_KEYS_ON_CARD);
|
||||||
|
|
||||||
|
PGPSecretKeyRing onCard = GnuDummyKeyUtil.modify(secretKeys)
|
||||||
|
.divertPrivateKeysToCard(GnuDummyKeyUtil.KeyFilter.any(), cardSerial);
|
||||||
|
|
||||||
|
for (PGPSecretKey key : onCard) {
|
||||||
|
assertEquals(255, key.getS2KUsage());
|
||||||
|
S2K s2K = key.getS2K();
|
||||||
|
assertEquals(S2K.GNU_PROTECTION_MODE_DIVERT_TO_CARD, s2K.getProtectionMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMovePrimaryKeyToCard() throws IOException {
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||||
|
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(PRIMARY_KEY_ON_CARD);
|
||||||
|
|
||||||
|
PGPSecretKeyRing onCard = GnuDummyKeyUtil.modify(secretKeys)
|
||||||
|
.divertPrivateKeysToCard(GnuDummyKeyUtil.KeyFilter.only(primaryKeyId), cardSerial);
|
||||||
|
|
||||||
|
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveEncryptionKeyToCard() throws IOException {
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||||
|
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(ENCRYPTION_KEY_ON_CARD);
|
||||||
|
|
||||||
|
PGPSecretKeyRing onCard = GnuDummyKeyUtil.modify(secretKeys)
|
||||||
|
.divertPrivateKeysToCard(GnuDummyKeyUtil.KeyFilter.only(encryptionKeyId), cardSerial);
|
||||||
|
|
||||||
|
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveSigningKeyToCard() throws IOException {
|
||||||
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(FULL_KEY);
|
||||||
|
PGPSecretKeyRing expected = PGPainless.readKeyRing().secretKeyRing(SIGNATURE_KEY_ON_CARD);
|
||||||
|
|
||||||
|
PGPSecretKeyRing onCard = GnuDummyKeyUtil.modify(secretKeys)
|
||||||
|
.divertPrivateKeysToCard(GnuDummyKeyUtil.KeyFilter.only(signatureKeyId), cardSerial);
|
||||||
|
|
||||||
|
assertArrayEquals(expected.getEncoded(), onCard.getEncoded());
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue