issue #107 Add method KeyRingInfo.isFullyEncrypted() (#110)

Add method KeyRingInfo.isFullyEncrypted()

Fixes #107 

Co-authored-by: Ivan Pizhenko <IvanPizhenko@users.noreply.github.com>
This commit is contained in:
Ivan Pizhenko 2021-04-27 12:06:04 +03:00 committed by GitHub
parent 0b3511486c
commit eb47e5caa3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 118 additions and 14 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2021 Flowcrypt a.s. Copyright 2021 Paul Schaub
* Copyright 2021 Paul Schaub. Copyright 2021 Flowcrypt a.s.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -77,7 +77,8 @@ public class PGPKeyRingCollection {
pgpPublicKeyRingCollection = new PGPPublicKeyRingCollection(publicKeyRings);
}
public PGPKeyRingCollection(Collection<PGPKeyRing> collection, boolean isSilent) throws IOException, PGPException {
public PGPKeyRingCollection(@Nonnull Collection<PGPKeyRing> collection, boolean isSilent)
throws IOException, PGPException {
List<PGPSecretKeyRing> secretKeyRings = new ArrayList<>();
List<PGPPublicKeyRing> publicKeyRings = new ArrayList<>();

View File

@ -1,5 +1,5 @@
/*
* Copyright 2021 Paul Schaub.
* Copyright 2021 Paul Schaub. Copyright 2021 Flowcrypt a.s.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,7 @@ import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
import org.bouncycastle.bcpg.ECPublicBCPGKey;
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
import org.bouncycastle.bcpg.S2K;
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey;
@ -39,6 +40,38 @@ public class KeyInfo {
this.secretKey = null;
}
public String getCurveName() {
return getCurveName(publicKey);
}
/**
* Returns indication that a contained secret key is encrypted.
*
* @return true if secret key is encrypted, false if secret key is not encrypted or there is public key only.
*/
public boolean isEncrypted() {
return secretKey != null && isEncrypted(secretKey);
}
/**
* Returns indication that a contained secret key is not encrypted.
*
* @return true if secret key is not encrypted or there is public key only, false if secret key is encrypted.
*/
public boolean isDecrypted() {
return secretKey == null || isDecrypted(secretKey);
}
/**
* Returns indication that a contained secret key has S2K of a type GNU_DUMMY_S2K.
*
* @return true if secret key has S2K of a type GNU_DUMMY_S2K, false if there is public key only,
* or S2K on the secret key is absent or not of a type GNU_DUMMY_S2K.
*/
public boolean hasDummyS2K() {
return secretKey != null && hasDummyS2K(secretKey);
}
public static String getCurveName(PGPPublicKey publicKey) {
PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.fromId(publicKey.getAlgorithm());
ECPublicBCPGKey key;
@ -64,4 +97,35 @@ public class KeyInfo {
public static String getCurveName(ECPublicBCPGKey key) {
return ECUtil.getCurveName(key.getCurveOID());
}
/**
* Returns indication that a secret key is encrypted.
*
* @param secretKey A secret key to examine.
* @return true if secret key is encrypted, false otherwise.
*/
public static boolean isEncrypted(PGPSecretKey secretKey) {
return secretKey.getS2KUsage() != 0;
}
/**
* Returns indication that a secret key is not encrypted.
*
* @param secretKey A secret key to examine.
* @return true if secret key is encrypted, false otherwise.
*/
public static boolean isDecrypted(PGPSecretKey secretKey) {
return secretKey.getS2KUsage() == 0;
}
/**
* Returns indication that a secret key has S2K of a type GNU_DUMMY_S2K.
*
* @param secretKey A secret key to examine.
* @return true if secret key has S2K of a type GNU_DUMMY_S2K, false otherwise.
*/
public static boolean hasDummyS2K(PGPSecretKey secretKey) {
final S2K s2k = secretKey.getS2K();
return s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020 Paul Schaub.
* Copyright 2020 Paul Schaub. Copyright 2021 Flowcrypt a.s.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -297,16 +297,17 @@ public class KeyRingInfo {
}
/**
* Return true when every secret key on the key ring is not encrypted.
* If there is at least one encrypted secret key on the ring, return false.
* If the ring is a {@link PGPPublicKeyRing}, return true.
* Returns true when every secret key on the key ring is not encrypted.
* If there is at least one encrypted secret key on the key ring, returns false.
* If the key ring is a {@link PGPPublicKeyRing}, returns true.
* Sub-keys with S2K of a type GNU_DUMMY_S2K do not affect the result.
*
* @return true if all secret keys are unencrypted.
*/
public boolean isFullyDecrypted() {
if (isSecretKey()) {
for (PGPSecretKey secretKey : getSecretKeys()) {
if (secretKey.getS2KUsage() != 0) {
if (!KeyInfo.hasDummyS2K(secretKey) && KeyInfo.isEncrypted(secretKey)) {
return false;
}
}
@ -314,6 +315,26 @@ public class KeyRingInfo {
return true;
}
/**
* Returns true when every secret key on the key ring is encrypted.
* If there is at least one not encrypted secret key on the key ring, returns false.
* If the key ring is a {@link PGPPublicKeyRing}, returns false.
* Sub-keys with S2K of a type GNU_DUMMY_S2K do not affect a result.
*
* @return true if all secret keys are encrypted.
*/
public boolean isFullyEncrypted() {
if (isSecretKey()) {
for (PGPSecretKey secretKey : getSecretKeys()) {
if (!KeyInfo.hasDummyS2K(secretKey) && KeyInfo.isDecrypted(secretKey)) {
return false;
}
}
return true;
}
return false;
}
public List<PGPSignature> getSelfSignaturesOnKey(long subkeyId) {
PGPPublicKey publicKey = KeyRingUtils.requirePublicKeyFrom(keys, subkeyId);
Iterator<PGPSignature> it = publicKey.getSignaturesForKeyID(keys.getPublicKey().getKeyID());

View File

@ -1,5 +1,5 @@
/*
* Copyright 2020 Paul Schaub.
* Copyright 2020 Paul Schaub. Copyright 2021 Flowcrypt a.s.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -89,16 +89,34 @@ public class KeyRingInfoTest {
assertTrue(info.isFullyDecrypted());
secretKeys = PGPainless.modifyKeyRing(secretKeys)
.changePassphraseFromOldPassphrase(null)
.withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("sw0rdf1sh"))
.done();
secretKeys = encryptSecretKeys(secretKeys);
info = PGPainless.inspectKeyRing(secretKeys);
assertFalse(info.isFullyDecrypted());
}
@Test
public void testIsFullyEncrypted() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
assertFalse(info.isFullyEncrypted());
secretKeys = encryptSecretKeys(secretKeys);
info = PGPainless.inspectKeyRing(secretKeys);
assertTrue(info.isFullyEncrypted());
}
private static PGPSecretKeyRing encryptSecretKeys(PGPSecretKeyRing secretKeys) throws PGPException {
return PGPainless.modifyKeyRing(secretKeys)
.changePassphraseFromOldPassphrase(null)
.withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("sw0rdf1sh"))
.done();
}
@Test
public void testGetSecretKey() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing();