-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lower required Android API to 9 and use Animal Sniffer #18
Changes from 2 commits
9890764
39a7587
5c914f7
1d27969
781cba5
f937267
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,3 +5,4 @@ build/ | |
.DS_Store | ||
out/ | ||
gradle.properties | ||
*.iml |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,10 +5,11 @@ | |
import java.security.NoSuchAlgorithmException; | ||
import java.security.NoSuchProviderException; | ||
import java.security.SignatureException; | ||
import java.time.Instant; | ||
import java.util.Date; | ||
import java.util.HashSet; | ||
import java.util.Set; | ||
import javax.annotation.Nullable; | ||
|
||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.DefaultPGPAlgorithmSuites; | ||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.algorithms.PGPAlgorithmSuite; | ||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.encrypting.PGPEncryptingStream; | ||
|
@@ -66,11 +67,11 @@ public final class WithKeySelectionStrategy extends WithAlgorithmSuiteImpl { | |
private WithKeySelectionStrategy() { | ||
super(); | ||
BuildEncryptionOutputStreamAPI.this.keySelectionStrategy = new Rfc4880KeySelectionStrategy( | ||
Instant.now()); | ||
new Date()); | ||
} | ||
|
||
public WithAlgorithmSuite setReferenceDateForKeyValidityTo( | ||
Instant dateOfTimestampVerification) { | ||
Date dateOfTimestampVerification) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See above (breaks API) |
||
if (dateOfTimestampVerification == null) { | ||
throw new IllegalArgumentException("dateOfTimestampVerification must not be null"); | ||
} | ||
|
@@ -87,7 +88,7 @@ public WithAlgorithmSuite withKeySelectionStrategy(final KeySelectionStrategy st | |
} | ||
BuildEncryptionOutputStreamAPI.this.keySelectionStrategy = strategy; | ||
LOGGER.trace("WithKeySelectionStrategy: override strategy to {}", | ||
strategy.getClass().toGenericString()); | ||
strategy.getClass().getName()); | ||
return new WithAlgorithmSuiteImpl(); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,12 @@ | ||
package name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.callbacks; | ||
|
||
import java.io.IOException; | ||
import java.time.Instant; | ||
import java.util.Date; | ||
import java.util.HashSet; | ||
import java.util.Iterator; | ||
import java.util.Set; | ||
import java.util.function.Predicate; | ||
import java.util.stream.Collectors; | ||
import java.util.stream.StreamSupport; | ||
import javax.annotation.Nullable; | ||
|
||
import name.neuhalfen.projects.crypto.bouncycastle.openpgp.keys.keyrings.KeyringConfig; | ||
import org.bouncycastle.openpgp.PGPException; | ||
import org.bouncycastle.openpgp.PGPKeyFlags; | ||
|
@@ -30,22 +28,22 @@ public class Rfc4880KeySelectionStrategy implements KeySelectionStrategy { | |
private static final org.slf4j.Logger LOGGER = org.slf4j.LoggerFactory | ||
.getLogger(Rfc4880KeySelectionStrategy.class); | ||
|
||
private final Instant dateOfTimestampVerification; | ||
private final Date dateOfTimestampVerification; | ||
|
||
/** | ||
* The date used for key expiration date checks as "now". | ||
* | ||
* @return dateOfTimestampVerification | ||
*/ | ||
protected Instant getDateOfTimestampVerification() { | ||
protected Date getDateOfTimestampVerification() { | ||
return dateOfTimestampVerification; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also breaks API, it is possible but unlikely that this will cause a major fuss (I'll skip over the next "breaking changes" ) |
||
} | ||
|
||
|
||
/** | ||
* @param dateOfTimestampVerification The date used for key expiration date checks as "now". | ||
*/ | ||
public Rfc4880KeySelectionStrategy(final Instant dateOfTimestampVerification) { | ||
public Rfc4880KeySelectionStrategy(final Date dateOfTimestampVerification) { | ||
this.dateOfTimestampVerification = dateOfTimestampVerification; | ||
} | ||
|
||
|
@@ -97,12 +95,17 @@ public Set<PGPPublicKey> validPublicKeysForVerifyingSignatures(String uid, | |
final Set<PGPPublicKeyRing> publicKeyrings = this | ||
.publicKeyRingsForUid(PURPOSE.FOR_SIGNING, uid, keyringConfig); | ||
|
||
return publicKeyrings.stream() | ||
.flatMap(keyring -> StreamSupport.stream(keyring.spliterator(), false)) | ||
.filter(this::isVerificationKey) | ||
.filter(this::isNotRevoked) | ||
.filter(this::isNotExpired) | ||
.collect(Collectors.toSet()); | ||
Set<PGPPublicKey> validKeys = new HashSet<>(); | ||
for (PGPPublicKeyRing p : publicKeyrings) { | ||
Iterator<PGPPublicKey> keys = p.iterator(); | ||
while (keys.hasNext()) { | ||
PGPPublicKey key = keys.next(); | ||
if (isVerificationKey(key) && isNotRevoked(key) && isNotExpired(key)) { | ||
validKeys.add(key); | ||
} | ||
} | ||
} | ||
return validKeys; | ||
} | ||
|
||
@Nullable | ||
|
@@ -116,52 +119,61 @@ public PGPPublicKey selectPublicKey(PURPOSE purpose, String uid, KeyringConfig k | |
|
||
final PGPSecretKeyRingCollection secretKeyRings = keyringConfig.getSecretKeyRings(); | ||
|
||
PGPPublicKey publicKey = null; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a comment to the method (if there is none yet) to say that the last matching key is selected ("use the newest"). |
||
switch (purpose) { | ||
case FOR_SIGNING: | ||
return publicKeyrings.stream() | ||
.flatMap(keyring -> StreamSupport.stream(keyring.spliterator(), false)) | ||
.filter(this::isVerificationKey) | ||
.filter(this::isNotRevoked) | ||
.filter(this::isNotExpired) | ||
.filter(hasPrivateKey(secretKeyRings)) | ||
.reduce((a, b) -> b) | ||
.orElse(null); | ||
for (PGPPublicKeyRing ring : publicKeyrings) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe move this to a dedicated method? |
||
Iterator<PGPPublicKey> iterator = ring.iterator(); | ||
while (iterator.hasNext()) { | ||
PGPPublicKey key = iterator.next(); | ||
if (isVerificationKey(key) && | ||
isNotRevoked(key) && | ||
isNotExpired(key) && | ||
hasPrivateKey(key, secretKeyRings)) { | ||
publicKey = key; | ||
} | ||
} | ||
} | ||
return publicKey; | ||
|
||
case FOR_ENCRYPTION: | ||
return publicKeyrings.stream() | ||
.flatMap(keyring -> StreamSupport.stream(keyring.spliterator(), false)) | ||
.filter(this::isEncryptionKey) | ||
.filter(this::isNotRevoked) | ||
.filter(this::isNotExpired) | ||
.reduce((a, b) -> b) | ||
.orElse(null); | ||
for (PGPPublicKeyRing ring : publicKeyrings) { | ||
Iterator<PGPPublicKey> iterator = ring.iterator(); | ||
while (iterator.hasNext()) { | ||
PGPPublicKey key = iterator.next(); | ||
if (isEncryptionKey(key) && | ||
isNotRevoked(key) && | ||
isNotExpired(key)) { | ||
publicKey = key; | ||
} | ||
} | ||
} | ||
return publicKey; | ||
|
||
default: | ||
return null; | ||
} | ||
} | ||
|
||
protected boolean hasPrivateKey(PGPPublicKey pubKey, PGPSecretKeyRingCollection secretKeyRings) { | ||
boolean result = false; | ||
try { | ||
final boolean hasPrivateKey = secretKeyRings.contains(pubKey.getKeyID()); | ||
|
||
protected Predicate<PGPPublicKey> hasPrivateKey(final PGPSecretKeyRingCollection secretKeyRings) { | ||
return pubKey -> { | ||
try { | ||
final boolean hasPrivateKey = secretKeyRings.contains(pubKey.getKeyID()); | ||
if (!hasPrivateKey) { | ||
LOGGER.trace("Skipping pubkey {} (no private key found)", | ||
Long.toHexString(pubKey.getKeyID())); | ||
} | ||
|
||
if (!hasPrivateKey) { | ||
LOGGER.trace("Skipping pubkey {} (no private key found)", | ||
Long.toHexString(pubKey.getKeyID())); | ||
} | ||
result = hasPrivateKey; | ||
} catch (PGPException e) { | ||
// ignore this for filtering | ||
LOGGER.debug("Failed to test for private key for pubkey " + pubKey.getKeyID()); | ||
} | ||
|
||
return hasPrivateKey; | ||
} catch (PGPException e) { | ||
// ignore this for filtering | ||
LOGGER.debug("Failed to test for private key for pubkey " + pubKey.getKeyID()); | ||
return false; | ||
} | ||
}; | ||
return result; | ||
} | ||
|
||
|
||
protected boolean isNotMasterKey(PGPPublicKey pubKey) { | ||
return !pubKey.isMasterKey(); | ||
} | ||
|
@@ -179,10 +191,9 @@ protected boolean isExpired(PGPPublicKey pubKey) { | |
final boolean isExpired; | ||
|
||
if (hasExpiryDate) { | ||
final Instant expiryDate = pubKey.getCreationTime().toInstant() | ||
.plusSeconds(pubKey.getValidSeconds()); | ||
final Date expiryDate = new Date(pubKey.getCreationTime().getTime() + 1000L * pubKey.getValidSeconds()); | ||
isExpired = expiryDate | ||
.isBefore(getDateOfTimestampVerification()); | ||
.before(getDateOfTimestampVerification()); | ||
|
||
if (isExpired) { | ||
LOGGER.trace("Skipping pubkey {} (expired since {})", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing
public Validation setReferenceDateForKeyValidityTo(Instant)
topublic Validation setReferenceDateForKeyValidityTo(Date)
would break the published API. Although 2.1 is not yet used widely this is not good. UnfortunatelyInstant
got added to android in API Level 26.The best way would be to loosen your "support (very) old devices" requirement.