1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-09-10 18:59:39 +02:00

Port SecretKeyRingEditor, replace Singleton usage with API instance calls

This commit is contained in:
Paul Schaub 2025-03-19 17:24:04 +01:00
parent 9041a6c601
commit 261838dd2a
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
43 changed files with 811 additions and 611 deletions

View file

@ -67,9 +67,14 @@ class PGPainless(
* @param referenceTime reference time for evaluation * @param referenceTime reference time for evaluation
* @return [KeyRingInfo] wrapper * @return [KeyRingInfo] wrapper
*/ */
@JvmOverloads
fun inspect(keyOrCertificate: OpenPGPCertificate, referenceTime: Date = Date()): KeyRingInfo = fun inspect(keyOrCertificate: OpenPGPCertificate, referenceTime: Date = Date()): KeyRingInfo =
KeyRingInfo(keyOrCertificate, this, referenceTime) KeyRingInfo(keyOrCertificate, this, referenceTime)
@JvmOverloads
fun modify(key: OpenPGPKey, referenceTime: Date = Date()): SecretKeyRingEditor =
SecretKeyRingEditor(key, this, referenceTime)
fun readKey(): OpenPGPKeyReader = api.readKeyOrCertificate() fun readKey(): OpenPGPKeyReader = api.readKeyOrCertificate()
fun toKey(secretKeyRing: PGPSecretKeyRing): OpenPGPKey = fun toKey(secretKeyRing: PGPSecretKeyRing): OpenPGPKey =

View file

@ -694,7 +694,7 @@ class OpenPgpMessageInputStream(
private fun getDecryptionKey(pkesk: PGPPublicKeyEncryptedData): OpenPGPKey? = private fun getDecryptionKey(pkesk: PGPPublicKeyEncryptedData): OpenPGPKey? =
options.getDecryptionKeys().firstOrNull { options.getDecryptionKeys().firstOrNull {
it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null && it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null &&
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { subkey -> api.inspect(it).decryptionSubkeys.any { subkey ->
pkesk.keyIdentifier.matches(subkey.keyIdentifier) pkesk.keyIdentifier.matches(subkey.keyIdentifier)
} }
} }
@ -702,7 +702,7 @@ class OpenPgpMessageInputStream(
private fun getDecryptionKeys(pkesk: PGPPublicKeyEncryptedData): List<OpenPGPKey> = private fun getDecryptionKeys(pkesk: PGPPublicKeyEncryptedData): List<OpenPGPKey> =
options.getDecryptionKeys().filter { options.getDecryptionKeys().filter {
it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null && it.pgpSecretKeyRing.getSecretKeyFor(pkesk) != null &&
PGPainless.inspectKeyRing(it).decryptionSubkeys.any { subkey -> api.inspect(it).decryptionSubkeys.any { subkey ->
pkesk.keyIdentifier.matches(subkey.keyIdentifier) pkesk.keyIdentifier.matches(subkey.keyIdentifier)
} }
} }
@ -713,7 +713,7 @@ class OpenPgpMessageInputStream(
val algorithm = pkesk.algorithm val algorithm = pkesk.algorithm
val candidates = mutableListOf<OpenPGPSecretKey>() val candidates = mutableListOf<OpenPGPSecretKey>()
options.getDecryptionKeys().forEach { options.getDecryptionKeys().forEach {
val info = PGPainless.inspectKeyRing(it) val info = api.inspect(it)
for (key in info.decryptionSubkeys) { for (key in info.decryptionSubkeys) {
if (key.pgpPublicKey.algorithm == algorithm && if (key.pgpPublicKey.algorithm == algorithm &&
info.isSecretKeyAvailable(key.keyIdentifier)) { info.isSecretKeyAvailable(key.keyIdentifier)) {

View file

@ -10,7 +10,6 @@ import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator import org.bouncycastle.openpgp.operator.PGPKeyEncryptionMethodGenerator
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.PGPainless.Companion.inspectKeyRing
import org.pgpainless.algorithm.EncryptionPurpose import org.pgpainless.algorithm.EncryptionPurpose
import org.pgpainless.algorithm.SymmetricKeyAlgorithm import org.pgpainless.algorithm.SymmetricKeyAlgorithm
import org.pgpainless.algorithm.negotiation.SymmetricKeyAlgorithmNegotiator.Companion.byPopularity import org.pgpainless.algorithm.negotiation.SymmetricKeyAlgorithmNegotiator.Companion.byPopularity
@ -191,7 +190,7 @@ class EncryptionOptions(private val purpose: EncryptionPurpose, private val api:
userId: CharSequence, userId: CharSequence,
encryptionKeySelector: EncryptionKeySelector encryptionKeySelector: EncryptionKeySelector
) = apply { ) = apply {
val info = inspectKeyRing(cert, evaluationDate) val info = api.inspect(cert, evaluationDate)
val subkeys = val subkeys =
encryptionKeySelector.selectEncryptionSubkeys( encryptionKeySelector.selectEncryptionSubkeys(
info.getEncryptionSubkeys(userId, purpose)) info.getEncryptionSubkeys(userId, purpose))
@ -289,7 +288,7 @@ class EncryptionOptions(private val purpose: EncryptionPurpose, private val api:
selector: EncryptionKeySelector, selector: EncryptionKeySelector,
wildcardKeyId: Boolean wildcardKeyId: Boolean
) = apply { ) = apply {
val info = inspectKeyRing(cert, evaluationDate) val info = api.inspect(cert, evaluationDate)
val primaryKeyExpiration = val primaryKeyExpiration =
try { try {
info.primaryKeyExpirationDate info.primaryKeyExpirationDate

View file

@ -8,6 +8,7 @@ import java.util.*
import org.bouncycastle.openpgp.PGPLiteralData import org.bouncycastle.openpgp.PGPLiteralData
import org.bouncycastle.openpgp.PGPPublicKeyRing import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.pgpainless.algorithm.CompressionAlgorithm import org.pgpainless.algorithm.CompressionAlgorithm
import org.pgpainless.algorithm.StreamEncoding import org.pgpainless.algorithm.StreamEncoding
import org.pgpainless.algorithm.SymmetricKeyAlgorithm import org.pgpainless.algorithm.SymmetricKeyAlgorithm
@ -34,6 +35,9 @@ data class EncryptionResult(
val isForYourEyesOnly: Boolean val isForYourEyesOnly: Boolean
get() = PGPLiteralData.CONSOLE == fileName get() = PGPLiteralData.CONSOLE == fileName
fun isEncryptedFor(certificate: OpenPGPCertificate) =
recipients.any { certificate.getKey(it.keyIdentifier) != null }
/** /**
* Returns true, if the message was encrypted for at least one subkey of the given certificate. * Returns true, if the message was encrypted for at least one subkey of the given certificate.
* *

View file

@ -12,7 +12,6 @@ import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPPrivateKey
import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey import org.bouncycastle.openpgp.api.OpenPGPKey.OpenPGPSecretKey
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.PGPainless.Companion.inspectKeyRing
import org.pgpainless.algorithm.DocumentSignatureType import org.pgpainless.algorithm.DocumentSignatureType
import org.pgpainless.algorithm.HashAlgorithm import org.pgpainless.algorithm.HashAlgorithm
import org.pgpainless.algorithm.PublicKeyAlgorithm.Companion.requireFromId import org.pgpainless.algorithm.PublicKeyAlgorithm.Companion.requireFromId
@ -138,6 +137,7 @@ class SigningOptions(private val api: PGPainless) {
signatureType: DocumentSignatureType signatureType: DocumentSignatureType
) = addInlineSignature(signingKeyProtector, api.toKey(signingKey), signatureType) ) = addInlineSignature(signingKeyProtector, api.toKey(signingKey), signatureType)
@JvmOverloads
fun addInlineSignature( fun addInlineSignature(
signingKeyProtector: SecretKeyRingProtector, signingKeyProtector: SecretKeyRingProtector,
signingKey: OpenPGPKey, signingKey: OpenPGPKey,
@ -145,7 +145,7 @@ class SigningOptions(private val api: PGPainless) {
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT, signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketsCallback: Callback? = null subpacketsCallback: Callback? = null
) = apply { ) = apply {
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate) val keyRingInfo = api.inspect(signingKey, evaluationDate)
if (userId != null && !keyRingInfo.isUserIdValid(userId)) { if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
throw UnboundUserIdException( throw UnboundUserIdException(
of(signingKey), of(signingKey),
@ -212,7 +212,7 @@ class SigningOptions(private val api: PGPainless) {
subpacketsCallback: Callback? = null subpacketsCallback: Callback? = null
): SigningOptions = apply { ): SigningOptions = apply {
val openPGPKey = signingKey.openPGPKey val openPGPKey = signingKey.openPGPKey
val keyRingInfo = inspectKeyRing(openPGPKey, evaluationDate) val keyRingInfo = api.inspect(openPGPKey, evaluationDate)
val signingPubKeys = keyRingInfo.signingSubkeys val signingPubKeys = keyRingInfo.signingSubkeys
if (signingPubKeys.isEmpty()) { if (signingPubKeys.isEmpty()) {
throw UnacceptableSigningKeyException(openPGPKey) throw UnacceptableSigningKeyException(openPGPKey)
@ -319,7 +319,7 @@ class SigningOptions(private val api: PGPainless) {
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT, signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketCallback: Callback? = null subpacketCallback: Callback? = null
): SigningOptions = apply { ): SigningOptions = apply {
val keyRingInfo = inspectKeyRing(signingKey, evaluationDate) val keyRingInfo = api.inspect(signingKey, evaluationDate)
if (userId != null && !keyRingInfo.isUserIdValid(userId)) { if (userId != null && !keyRingInfo.isUserIdValid(userId)) {
throw UnboundUserIdException( throw UnboundUserIdException(
of(signingKey), of(signingKey),
@ -380,7 +380,7 @@ class SigningOptions(private val api: PGPainless) {
signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT, signatureType: DocumentSignatureType = DocumentSignatureType.BINARY_DOCUMENT,
subpacketCallback: Callback? = null subpacketCallback: Callback? = null
): SigningOptions = apply { ): SigningOptions = apply {
val keyRingInfo = inspectKeyRing(signingKey.openPGPKey, evaluationDate) val keyRingInfo = api.inspect(signingKey.openPGPKey, evaluationDate)
val signingPrivKey: OpenPGPPrivateKey = signingKey.unlock(signingKeyProtector) val signingPrivKey: OpenPGPPrivateKey = signingKey.unlock(signingKeyProtector)
val hashAlgorithms = val hashAlgorithms =
if (userId != null) keyRingInfo.getPreferredHashAlgorithms(userId) if (userId != null) keyRingInfo.getPreferredHashAlgorithms(userId)

View file

@ -134,7 +134,7 @@ class CertifyCertificate(private val api: PGPainless) {
key: OpenPGPKey, key: OpenPGPKey,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): CertificationOnUserIdWithSubpackets { ): CertificationOnUserIdWithSubpackets {
val secretKey = getCertifyingSecretKey(key) val secretKey = getCertifyingSecretKey(key, api)
val sigBuilder = val sigBuilder =
ThirdPartyCertificationSignatureBuilder( ThirdPartyCertificationSignatureBuilder(
certificationType.asSignatureType(), secretKey, protector, api) certificationType.asSignatureType(), secretKey, protector, api)
@ -220,7 +220,7 @@ class CertifyCertificate(private val api: PGPainless) {
key: OpenPGPKey, key: OpenPGPKey,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): DelegationOnCertificateWithSubpackets { ): DelegationOnCertificateWithSubpackets {
val secretKey = getCertifyingSecretKey(key) val secretKey = getCertifyingSecretKey(key, api)
val sigBuilder = ThirdPartyDirectKeySignatureBuilder(secretKey, protector, api) val sigBuilder = ThirdPartyDirectKeySignatureBuilder(secretKey, protector, api)
if (trustworthiness != null) { if (trustworthiness != null) {
sigBuilder.hashedSubpackets.setTrust( sigBuilder.hashedSubpackets.setTrust(
@ -306,10 +306,11 @@ class CertifyCertificate(private val api: PGPainless) {
companion object { companion object {
@JvmStatic @JvmStatic
private fun getCertifyingSecretKey( private fun getCertifyingSecretKey(
certificationKey: OpenPGPKey certificationKey: OpenPGPKey,
api: PGPainless
): OpenPGPKey.OpenPGPSecretKey { ): OpenPGPKey.OpenPGPSecretKey {
val now = Date() val now = Date()
val info = PGPainless.inspectKeyRing(certificationKey, now) val info = api.inspect(certificationKey, now)
val fingerprint = info.fingerprint val fingerprint = info.fingerprint
val certificationPubKey = info.getPublicKey(fingerprint) val certificationPubKey = info.getPublicKey(fingerprint)

View file

@ -8,10 +8,11 @@ import java.util.*
import java.util.function.Predicate import java.util.function.Predicate
import javax.annotation.Nonnull import javax.annotation.Nonnull
import kotlin.NoSuchElementException import kotlin.NoSuchElementException
import openpgp.openPgpKeyId
import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.bcpg.sig.KeyExpirationTime import org.bouncycastle.bcpg.sig.KeyExpirationTime
import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.*
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPSubkey import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPSubkey
import org.bouncycastle.openpgp.api.OpenPGPImplementation import org.bouncycastle.openpgp.api.OpenPGPImplementation
import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey
@ -20,7 +21,6 @@ import org.bouncycastle.openpgp.api.OpenPGPKeyEditor
import org.bouncycastle.openpgp.api.OpenPGPSignature import org.bouncycastle.openpgp.api.OpenPGPSignature
import org.bouncycastle.openpgp.api.SignatureParameters import org.bouncycastle.openpgp.api.SignatureParameters
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.PGPainless.Companion.inspectKeyRing
import org.pgpainless.algorithm.AlgorithmSuite import org.pgpainless.algorithm.AlgorithmSuite
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.algorithm.OpenPGPKeyVersion import org.pgpainless.algorithm.OpenPGPKeyVersion
@ -29,7 +29,6 @@ import org.pgpainless.algorithm.negotiation.HashAlgorithmNegotiator
import org.pgpainless.bouncycastle.extensions.checksumCalculator import org.pgpainless.bouncycastle.extensions.checksumCalculator
import org.pgpainless.bouncycastle.extensions.getKeyExpirationDate import org.pgpainless.bouncycastle.extensions.getKeyExpirationDate
import org.pgpainless.bouncycastle.extensions.publicKeyAlgorithm import org.pgpainless.bouncycastle.extensions.publicKeyAlgorithm
import org.pgpainless.bouncycastle.extensions.requirePublicKey
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.generation.KeyRingBuilder import org.pgpainless.key.generation.KeyRingBuilder
import org.pgpainless.key.generation.KeySpec import org.pgpainless.key.generation.KeySpec
@ -50,8 +49,6 @@ class SecretKeyRingEditor(
override val referenceTime: Date = Date() override val referenceTime: Date = Date()
) : SecretKeyRingEditorInterface { ) : SecretKeyRingEditorInterface {
private var secretKeyRing: PGPSecretKeyRing = key.pgpSecretKeyRing
@JvmOverloads @JvmOverloads
constructor( constructor(
secretKeyRing: PGPSecretKeyRing, secretKeyRing: PGPSecretKeyRing,
@ -64,8 +61,7 @@ class SecretKeyRingEditor(
callback: SelfSignatureSubpackets.Callback?, callback: SelfSignatureSubpackets.Callback?,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
key = PGPainless.getInstance().toKey(secretKeyRing) val info = api.inspect(key, referenceTime)
val info = inspectKeyRing(key, referenceTime)
require(!info.isHardRevoked(userId)) { require(!info.isHardRevoked(userId)) {
"User-ID $userId is hard revoked and cannot be re-certified." "User-ID $userId is hard revoked and cannot be re-certified."
} }
@ -89,7 +85,7 @@ class SecretKeyRingEditor(
.setSignatureCreationTime(referenceTime) .setSignatureCreationTime(referenceTime)
.setHashedSubpacketsFunction { subpacketGenerator -> .setHashedSubpacketsFunction { subpacketGenerator ->
val subpackets = SignatureSubpackets(subpacketGenerator) val subpackets = SignatureSubpackets(subpacketGenerator)
subpackets.setAppropriateIssuerInfo(secretKeyRing.publicKey) subpackets.setAppropriateIssuerInfo(key.primaryKey.pgpPublicKey)
subpackets.setKeyFlags(info.getKeyFlagsOf(key.keyIdentifier)) subpackets.setKeyFlags(info.getKeyFlagsOf(key.keyIdentifier))
subpackets.setPreferredHashAlgorithms(hashAlgorithmPreferences) subpackets.setPreferredHashAlgorithms(hashAlgorithmPreferences)
@ -111,7 +107,6 @@ class SecretKeyRingEditor(
} }
}) })
.done() .done()
secretKeyRing = key.pgpSecretKeyRing
return this return this
} }
@ -120,8 +115,8 @@ class SecretKeyRingEditor(
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
val uid = sanitizeUserId(userId) val uid = sanitizeUserId(userId)
val primaryKey = secretKeyRing.publicKey val primaryKey = key.primaryKey.pgpPublicKey
var info = inspectKeyRing(secretKeyRing, referenceTime) var info = api.inspect(key, referenceTime)
val primaryUserId = info.primaryUserId val primaryUserId = info.primaryUserId
val signature = val signature =
if (primaryUserId == null) info.latestDirectKeySelfSignature if (primaryUserId == null) info.latestDirectKeySelfSignature
@ -144,7 +139,7 @@ class SecretKeyRingEditor(
protector) protector)
// unmark previous primary user-ids to be non-primary // unmark previous primary user-ids to be non-primary
info = inspectKeyRing(secretKeyRing, referenceTime) info = api.inspect(key, referenceTime)
info.validAndExpiredUserIds info.validAndExpiredUserIds
.filterNot { it == uid } .filterNot { it == uid }
.forEach { otherUserId -> .forEach { otherUserId ->
@ -215,7 +210,7 @@ class SecretKeyRingEditor(
require(oldUID.isNotBlank()) { "Old user-ID cannot be empty." } require(oldUID.isNotBlank()) { "Old user-ID cannot be empty." }
require(newUID.isNotBlank()) { "New user-ID cannot be empty." } require(newUID.isNotBlank()) { "New user-ID cannot be empty." }
val info = inspectKeyRing(secretKeyRing, referenceTime) val info = api.inspect(key, referenceTime)
if (!info.isUserIdValid(oldUID)) { if (!info.isUserIdValid(oldUID)) {
throw NoSuchElementException( throw NoSuchElementException(
"Key does not carry user-ID '$oldUID', or it is not valid.") "Key does not carry user-ID '$oldUID', or it is not valid.")
@ -244,7 +239,6 @@ class SecretKeyRingEditor(
} }
}, },
protector) protector)
return revokeUserId(oldUID, protector) return revokeUserId(oldUID, protector)
} }
@ -270,7 +264,7 @@ class SecretKeyRingEditor(
callback: SelfSignatureSubpackets.Callback?, callback: SelfSignatureSubpackets.Callback?,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
val version = OpenPGPKeyVersion.from(secretKeyRing.publicKey.version) val version = OpenPGPKeyVersion.from(key.primarySecretKey.version)
val keyPair = KeyRingBuilder.generateKeyPair(keySpec, version, api.implementation) val keyPair = KeyRingBuilder.generateKeyPair(keySpec, version, api.implementation)
val subkeyProtector = val subkeyProtector =
PasswordBasedSecretKeyRingProtector.forKeyId(keyPair.keyIdentifier, subkeyPassphrase) PasswordBasedSecretKeyRingProtector.forKeyId(keyPair.keyIdentifier, subkeyPassphrase)
@ -303,8 +297,8 @@ class SecretKeyRingEditor(
"Public key algorithm policy violation: $subkeyAlgorithm with bit strength $bitStrength is not acceptable." "Public key algorithm policy violation: $subkeyAlgorithm with bit strength $bitStrength is not acceptable."
} }
val primaryKey = secretKeyRing.secretKey val primaryKey = key.primarySecretKey.pgpSecretKey
val info = inspectKeyRing(secretKeyRing, referenceTime) val info = api.inspect(key, referenceTime)
val hashAlgorithm = val hashAlgorithm =
HashAlgorithmNegotiator.negotiateSignatureHashAlgorithm(api.algorithmPolicy) HashAlgorithmNegotiator.negotiateSignatureHashAlgorithm(api.algorithmPolicy)
.negotiateHashAlgorithm(info.preferredHashAlgorithms) .negotiateHashAlgorithm(info.preferredHashAlgorithms)
@ -341,7 +335,8 @@ class SecretKeyRingEditor(
secretSubkey = secretSubkey =
KeyRingUtils.secretKeyPlusSignature( KeyRingUtils.secretKeyPlusSignature(
secretSubkey, skBindingBuilder.build(secretSubkey.publicKey)) secretSubkey, skBindingBuilder.build(secretSubkey.publicKey))
secretKeyRing = KeyRingUtils.keysPlusSecretKey(secretKeyRing, secretSubkey) val secretKeyRing = KeyRingUtils.keysPlusSecretKey(key.pgpSecretKeyRing, secretSubkey)
key = api.toKey(secretKeyRing)
return this return this
} }
@ -356,26 +351,33 @@ class SecretKeyRingEditor(
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
callback: RevocationSignatureSubpackets.Callback? callback: RevocationSignatureSubpackets.Callback?
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
return revokeSubKey(secretKeyRing.secretKey.keyID, protector, callback) return revokeSubKey(key.keyIdentifier, protector, callback)
} }
override fun revokeSubKey( override fun revokeSubKey(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
return revokeSubKey( return revokeSubKey(
subkeyId, protector, callbackFromRevocationAttributes(revocationAttributes)) subkeyIdentifier, protector, callbackFromRevocationAttributes(revocationAttributes))
} }
override fun revokeSubKey( override fun revokeSubKey(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
callback: RevocationSignatureSubpackets.Callback? callback: RevocationSignatureSubpackets.Callback?
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
val revokeeSubKey = secretKeyRing.requirePublicKey(subkeyId) var secretKeyRing = key.pgpSecretKeyRing
val revokeeSubKey =
key.getKey(subkeyIdentifier)
?: throw NoSuchElementException(
"Certificate ${key.keyIdentifier} does not contain subkey $subkeyIdentifier")
val subkeyRevocation = generateRevocation(protector, revokeeSubKey, callback) val subkeyRevocation = generateRevocation(protector, revokeeSubKey, callback)
secretKeyRing = injectCertification(secretKeyRing, revokeeSubKey, subkeyRevocation) secretKeyRing =
injectCertification(
secretKeyRing, revokeeSubKey.pgpPublicKey, subkeyRevocation.signature)
key = api.toKey(secretKeyRing)
return this return this
} }
@ -451,6 +453,7 @@ class SecretKeyRingEditor(
expiration: Date?, expiration: Date?,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface { ): SecretKeyRingEditorInterface {
var secretKeyRing = key.pgpSecretKeyRing
require(secretKeyRing.secretKey.isMasterKey) { require(secretKeyRing.secretKey.isMasterKey) {
"OpenPGP key does not appear to contain a primary secret key." "OpenPGP key does not appear to contain a primary secret key."
} }
@ -465,8 +468,9 @@ class SecretKeyRingEditor(
reissueDirectKeySignature(expiration, protector, prevDirectKeySig).signature) reissueDirectKeySignature(expiration, protector, prevDirectKeySig).signature)
} }
val primaryUserId = val info = api.inspect(key, referenceTime)
inspectKeyRing(secretKeyRing, referenceTime).getPossiblyExpiredPrimaryUserId()
val primaryUserId = info.getPossiblyExpiredPrimaryUserId()
if (primaryUserId != null) { if (primaryUserId != null) {
val prevUserIdSig = getPreviousUserIdSignatures(primaryUserId) val prevUserIdSig = getPreviousUserIdSignatures(primaryUserId)
val userIdSig = val userIdSig =
@ -474,7 +478,6 @@ class SecretKeyRingEditor(
secretKeyRing = injectCertification(secretKeyRing, primaryUserId, userIdSig) secretKeyRing = injectCertification(secretKeyRing, primaryUserId, userIdSig)
} }
val info = inspectKeyRing(secretKeyRing, referenceTime)
for (userId in info.validUserIds) { for (userId in info.validUserIds) {
if (userId == primaryUserId) { if (userId == primaryUserId) {
continue continue
@ -493,35 +496,40 @@ class SecretKeyRingEditor(
} }
} }
key = api.toKey(secretKeyRing)
return this return this
} }
override fun setExpirationDateOfSubkey( override fun setExpirationDateOfSubkey(
expiration: Date?, expiration: Date?,
keyId: Long, keyId: KeyIdentifier,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface = apply { ): SecretKeyRingEditorInterface = apply {
var secretKeyRing = key.pgpSecretKeyRing
// is primary key // is primary key
if (keyId == secretKeyRing.publicKey.keyID) { if (keyId.matches(key.keyIdentifier)) {
return setExpirationDate(expiration, protector) return setExpirationDate(expiration, protector)
} }
// is subkey // is subkey
val subkey = val subkey =
secretKeyRing.getPublicKey(keyId) key.getKey(keyId) ?: throw NoSuchElementException("No subkey with ID $keyId found.")
?: throw NoSuchElementException("No subkey with ID ${keyId.openPgpKeyId()} found.")
val prevBinding = val prevBinding =
inspectKeyRing(secretKeyRing).getCurrentSubkeyBindingSignature(keyId) api.inspect(key).getCurrentSubkeyBindingSignature(keyId)
?: throw NoSuchElementException( ?: throw NoSuchElementException(
"Previous subkey binding signaure for ${keyId.openPgpKeyId()} MUST NOT be null.") "Previous subkey binding signaure for $keyId MUST NOT be null.")
val bindingSig = reissueSubkeyBindingSignature(subkey, expiration, protector, prevBinding) val bindingSig = reissueSubkeyBindingSignature(subkey, expiration, protector, prevBinding)
secretKeyRing = injectCertification(secretKeyRing, subkey, bindingSig) secretKeyRing =
injectCertification(secretKeyRing, subkey.pgpPublicKey, bindingSig.signature)
key = api.toKey(secretKeyRing)
} }
override fun createMinimalRevocationCertificate( override fun createMinimalRevocationCertificate(
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPPublicKeyRing { ): OpenPGPCertificate {
// Check reason // Check reason
if (revocationAttributes != null) { if (revocationAttributes != null) {
require(RevocationAttributes.Reason.isKeyRevocation(revocationAttributes.reason)) { require(RevocationAttributes.Reason.isKeyRevocation(revocationAttributes.reason)) {
@ -530,49 +538,47 @@ class SecretKeyRingEditor(
} }
val revocation = createRevocation(protector, revocationAttributes) val revocation = createRevocation(protector, revocationAttributes)
var primaryKey = secretKeyRing.secretKey.publicKey var primaryKey = key.primaryKey.pgpPublicKey
primaryKey = KeyRingUtils.getStrippedDownPublicKey(primaryKey) primaryKey = KeyRingUtils.getStrippedDownPublicKey(primaryKey)
primaryKey = PGPPublicKey.addCertification(primaryKey, revocation) primaryKey = PGPPublicKey.addCertification(primaryKey, revocation.signature)
return PGPPublicKeyRing(listOf(primaryKey)) return api.toCertificate(PGPPublicKeyRing(listOf(primaryKey)))
} }
override fun createRevocation( override fun createRevocation(
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPSignature { ): OpenPGPSignature {
return generateRevocation( return generateRevocation(
protector, protector, key.primaryKey, callbackFromRevocationAttributes(revocationAttributes))
secretKeyRing.publicKey,
callbackFromRevocationAttributes(revocationAttributes))
} }
override fun createRevocation( override fun createRevocation(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPSignature { ): OpenPGPSignature {
return generateRevocation( return generateRevocation(
protector, protector,
secretKeyRing.requirePublicKey(subkeyId), key.getKey(subkeyIdentifier),
callbackFromRevocationAttributes(revocationAttributes)) callbackFromRevocationAttributes(revocationAttributes))
} }
override fun createRevocation( override fun createRevocation(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
callback: RevocationSignatureSubpackets.Callback? callback: RevocationSignatureSubpackets.Callback?
): PGPSignature { ): OpenPGPSignature {
return generateRevocation(protector, secretKeyRing.requirePublicKey(subkeyId), callback) return generateRevocation(protector, key.getKey(subkeyIdentifier), callback)
} }
override fun createRevocation( override fun createRevocation(
subkeyFingerprint: OpenPgpFingerprint, subkeyFingerprint: OpenPgpFingerprint,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPSignature { ): OpenPGPSignature {
return generateRevocation( return generateRevocation(
protector, protector,
secretKeyRing.requirePublicKey(subkeyFingerprint), key.getKey(subkeyFingerprint.keyIdentifier),
callbackFromRevocationAttributes(revocationAttributes)) callbackFromRevocationAttributes(revocationAttributes))
} }
@ -599,8 +605,8 @@ class SecretKeyRingEditor(
mapOf(keyIdentifier to oldPassphrase), oldProtectionSettings, null)) mapOf(keyIdentifier to oldPassphrase), oldProtectionSettings, null))
} }
override fun done(): PGPSecretKeyRing { override fun done(): OpenPGPKey {
return secretKeyRing return key
} }
private fun sanitizeUserId(userId: CharSequence): CharSequence = private fun sanitizeUserId(userId: CharSequence): CharSequence =
@ -619,11 +625,11 @@ class SecretKeyRingEditor(
private fun generateRevocation( private fun generateRevocation(
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revokeeSubkey: PGPPublicKey, revokeeSubkey: OpenPGPComponentKey,
callback: RevocationSignatureSubpackets.Callback? callback: RevocationSignatureSubpackets.Callback?
): PGPSignature { ): OpenPGPSignature {
val signatureType = val signatureType =
if (revokeeSubkey.isMasterKey) SignatureType.KEY_REVOCATION if (revokeeSubkey.isPrimaryKey) SignatureType.KEY_REVOCATION
else SignatureType.SUBKEY_REVOCATION else SignatureType.SUBKEY_REVOCATION
return RevocationSignatureBuilder(signatureType, key.primarySecretKey, protector, api) return RevocationSignatureBuilder(signatureType, key.primarySecretKey, protector, api)
@ -643,19 +649,20 @@ class SecretKeyRingEditor(
applyCallback(callback) applyCallback(callback)
} }
.let { .let {
secretKeyRing = val secretKeyRing =
injectCertification(secretKeyRing, userId, it.build(userId.toString())) injectCertification(key.pgpSecretKeyRing, userId, it.build(userId.toString()))
key = api.toKey(secretKeyRing)
} }
return this return this
} }
private fun getPreviousDirectKeySignature(): PGPSignature? { private fun getPreviousDirectKeySignature(): PGPSignature? {
val info = inspectKeyRing(secretKeyRing, referenceTime) val info = api.inspect(key, referenceTime)
return info.latestDirectKeySelfSignature return info.latestDirectKeySelfSignature
} }
private fun getPreviousUserIdSignatures(userId: String): PGPSignature? { private fun getPreviousUserIdSignatures(userId: String): PGPSignature? {
val info = inspectKeyRing(secretKeyRing, referenceTime) val info = api.inspect(key, referenceTime)
return info.getLatestUserIdCertification(userId) return info.getLatestUserIdCertification(userId)
} }
@ -696,7 +703,7 @@ class SecretKeyRingEditor(
) { ) {
if (expiration != null) { if (expiration != null) {
hashedSubpackets.setKeyExpirationTime( hashedSubpackets.setKeyExpirationTime(
true, secretKeyRing.publicKey.creationTime, expiration) true, key.primaryKey.creationTime, expiration)
} else { } else {
hashedSubpackets.setKeyExpirationTime(KeyExpirationTime(true, 0)) hashedSubpackets.setKeyExpirationTime(KeyExpirationTime(true, 0))
} }
@ -713,6 +720,7 @@ class SecretKeyRingEditor(
secretKeyRingProtector: SecretKeyRingProtector, secretKeyRingProtector: SecretKeyRingProtector,
prevDirectKeySig: PGPSignature prevDirectKeySig: PGPSignature
): OpenPGPSignature { ): OpenPGPSignature {
val secretKeyRing = key.pgpSecretKeyRing
return DirectKeySelfSignatureBuilder( return DirectKeySelfSignatureBuilder(
secretKeyRing, secretKeyRingProtector, prevDirectKeySig, api) secretKeyRing, secretKeyRingProtector, prevDirectKeySig, api)
.apply { .apply {
@ -735,13 +743,13 @@ class SecretKeyRingEditor(
} }
private fun reissueSubkeyBindingSignature( private fun reissueSubkeyBindingSignature(
subkey: PGPPublicKey, subkey: OpenPGPComponentKey,
expiration: Date?, expiration: Date?,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
prevSubkeyBindingSignature: PGPSignature prevSubkeyBindingSignature: PGPSignature
): PGPSignature { ): OpenPGPSignature {
val primaryKey = secretKeyRing.publicKey val primaryKey = key.primaryKey
val secretSubkey: PGPSecretKey? = secretKeyRing.getSecretKey(subkey.keyID) val secretSubkey: OpenPGPSecretKey? = key.getSecretKey(subkey)
val builder = val builder =
SubkeyBindingSignatureBuilder( SubkeyBindingSignatureBuilder(
@ -749,7 +757,7 @@ class SecretKeyRingEditor(
builder.hashedSubpackets.apply { builder.hashedSubpackets.apply {
// set expiration // set expiration
setSignatureCreationTime(referenceTime) setSignatureCreationTime(referenceTime)
setKeyExpirationTime(subkey, expiration) setKeyExpirationTime(subkey.pgpPublicKey, expiration)
setSignatureExpirationTime(null) // avoid copying sig exp time setSignatureExpirationTime(null) // avoid copying sig exp time
// signing-capable subkeys need embedded primary key binding sig // signing-capable subkeys need embedded primary key binding sig
@ -758,7 +766,7 @@ class SecretKeyRingEditor(
if (secretSubkey == null) { if (secretSubkey == null) {
throw NoSuchElementException( throw NoSuchElementException(
"Secret key does not contain secret-key" + "Secret key does not contain secret-key" +
" component for subkey ${subkey.keyID.openPgpKeyId()}") " component for subkey ${subkey.keyIdentifier}")
} }
// create new embedded back-sig // create new embedded back-sig
@ -766,7 +774,8 @@ class SecretKeyRingEditor(
addEmbeddedSignature( addEmbeddedSignature(
PrimaryKeyBindingSignatureBuilder( PrimaryKeyBindingSignatureBuilder(
key.getSecretKey(subkey.keyIdentifier), protector, api) key.getSecretKey(subkey.keyIdentifier), protector, api)
.build(primaryKey)) .build(primaryKey)
.signature)
} }
} }
} }
@ -775,7 +784,7 @@ class SecretKeyRingEditor(
} }
private fun selectUserIds(predicate: Predicate<String>): List<String> = private fun selectUserIds(predicate: Predicate<String>): List<String> =
inspectKeyRing(secretKeyRing).validUserIds.filter { predicate.test(it) } key.validUserIds.map { it.userId }.filter { predicate.test(it) }.toList()
private class WithKeyRingEncryptionSettingsImpl( private class WithKeyRingEncryptionSettingsImpl(
private val editor: SecretKeyRingEditor, private val editor: SecretKeyRingEditor,
@ -805,15 +814,17 @@ class SecretKeyRingEditor(
val protector = val protector =
PasswordBasedSecretKeyRingProtector( PasswordBasedSecretKeyRingProtector(
newProtectionSettings, SolitaryPassphraseProvider(passphrase)) newProtectionSettings, SolitaryPassphraseProvider(passphrase))
val secretKeys = changePassphrase(keyId, editor.secretKeyRing, oldProtector, protector) val secretKeys =
editor.secretKeyRing = secretKeys changePassphrase(keyId, editor.key.pgpSecretKeyRing, oldProtector, protector)
editor.key = editor.api.toKey(secretKeys)
return editor return editor
} }
override fun toNoPassphrase(): SecretKeyRingEditorInterface { override fun toNoPassphrase(): SecretKeyRingEditorInterface {
val protector = UnprotectedKeysProtector() val protector = UnprotectedKeysProtector()
val secretKeys = changePassphrase(keyId, editor.secretKeyRing, oldProtector, protector) val secretKeys =
editor.secretKeyRing = secretKeys changePassphrase(keyId, editor.key.pgpSecretKeyRing, oldProtector, protector)
editor.key = editor.api.toKey(secretKeys)
return editor return editor
} }
} }

View file

@ -10,6 +10,9 @@ import java.security.NoSuchAlgorithmException
import java.util.* import java.util.*
import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.* import org.bouncycastle.openpgp.*
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.api.OpenPGPSignature
import org.pgpainless.algorithm.KeyFlag import org.pgpainless.algorithm.KeyFlag
import org.pgpainless.key.OpenPgpFingerprint import org.pgpainless.key.OpenPgpFingerprint
import org.pgpainless.key.generation.KeySpec import org.pgpainless.key.generation.KeySpec
@ -262,26 +265,37 @@ interface SecretKeyRingEditorInterface {
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? = null revocationAttributes: RevocationAttributes? = null
): SecretKeyRingEditorInterface = ): SecretKeyRingEditorInterface =
revokeSubKey(fingerprint.keyId, protector, revocationAttributes) revokeSubKey(fingerprint.keyIdentifier, protector, revocationAttributes)
@Deprecated("Pass in a KeyIdentifier instead of keyId")
fun revokeSubKey(subkeyId: Long, protector: SecretKeyRingProtector) =
revokeSubKey(KeyIdentifier(subkeyId), protector)
/** /**
* Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be * Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be
* revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown. * revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown.
* *
* @param subkeyId id of the subkey * @param subkeyIdentifier id of the subkey
* @param protector protector to unlock the primary key * @param protector protector to unlock the primary key
* @return the builder * @return the builder
* @throws PGPException in case we cannot generate a revocation signature for the subkey * @throws PGPException in case we cannot generate a revocation signature for the subkey
*/ */
@Throws(PGPException::class) @Throws(PGPException::class)
fun revokeSubKey(subkeyId: Long, protector: SecretKeyRingProtector) = fun revokeSubKey(subkeyIdentifier: KeyIdentifier, protector: SecretKeyRingProtector) =
revokeSubKey(subkeyId, protector, null as RevocationAttributes?) revokeSubKey(subkeyIdentifier, protector, null as RevocationAttributes?)
@Deprecated("Pass in a KeyIdentifier instead of keyId")
fun revokeSubKey(
subkeyId: Long,
protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? = null
) = revokeSubKey(KeyIdentifier(subkeyId), protector, revocationAttributes)
/** /**
* Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be * Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be
* revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown. * revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown.
* *
* @param subkeyId id of the subkey * @param subkeyIdentifier id of the subkey
* @param protector protector to unlock the primary key * @param protector protector to unlock the primary key
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
* @return the builder * @return the builder
@ -289,18 +303,25 @@ interface SecretKeyRingEditorInterface {
*/ */
@Throws(PGPException::class) @Throws(PGPException::class)
fun revokeSubKey( fun revokeSubKey(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? = null revocationAttributes: RevocationAttributes? = null
): SecretKeyRingEditorInterface ): SecretKeyRingEditorInterface
@Deprecated("Pass in a KeyIdentifier instead of keyId.")
fun revokeSubKey(
keyId: Long,
protector: SecretKeyRingProtector,
callback: RevocationSignatureSubpackets.Callback?
) = revokeSubKey(KeyIdentifier(keyId), protector, callback)
/** /**
* Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be * Revoke the subkey binding signature of a subkey. The subkey with the provided key-id will be
* revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown. * revoked. If no suitable subkey is found, a [NoSuchElementException] will be thrown.
* *
* The provided subpackets callback is used to modify the revocation signatures subpackets. * The provided subpackets callback is used to modify the revocation signatures subpackets.
* *
* @param subkeyId id of the subkey * @param subkeyIdentifier id of the subkey
* @param protector protector to unlock the secret key ring * @param protector protector to unlock the secret key ring
* @param callback callback which can be used to modify the subpackets of the revocation * @param callback callback which can be used to modify the subpackets of the revocation
* signature * signature
@ -309,7 +330,7 @@ interface SecretKeyRingEditorInterface {
*/ */
@Throws(PGPException::class) @Throws(PGPException::class)
fun revokeSubKey( fun revokeSubKey(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
callback: RevocationSignatureSubpackets.Callback? callback: RevocationSignatureSubpackets.Callback?
): SecretKeyRingEditorInterface ): SecretKeyRingEditorInterface
@ -470,6 +491,14 @@ interface SecretKeyRingEditorInterface {
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface ): SecretKeyRingEditorInterface
@Deprecated("Pass in a KeyIdentifier instead of keyId")
@Throws(PGPException::class)
fun setExpirationDateOfSubkey(
expiration: Date?,
keyId: Long,
protector: SecretKeyRingProtector
) = setExpirationDateOfSubkey(expiration, KeyIdentifier(keyId), protector)
/** /**
* Set the expiration date for the subkey identified by the given keyId to the given expiration * Set the expiration date for the subkey identified by the given keyId to the given expiration
* date. If the key is supposed to never expire, then an expiration date of null is expected. * date. If the key is supposed to never expire, then an expiration date of null is expected.
@ -484,7 +513,7 @@ interface SecretKeyRingEditorInterface {
@Throws(PGPException::class) @Throws(PGPException::class)
fun setExpirationDateOfSubkey( fun setExpirationDateOfSubkey(
expiration: Date?, expiration: Date?,
keyId: Long, keyId: KeyIdentifier,
protector: SecretKeyRingProtector protector: SecretKeyRingProtector
): SecretKeyRingEditorInterface ): SecretKeyRingEditorInterface
@ -502,7 +531,7 @@ interface SecretKeyRingEditorInterface {
fun createMinimalRevocationCertificate( fun createMinimalRevocationCertificate(
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPPublicKeyRing ): OpenPGPCertificate
/** /**
* Create a detached revocation certificate, which can be used to revoke the whole key. The * Create a detached revocation certificate, which can be used to revoke the whole key. The
@ -517,13 +546,21 @@ interface SecretKeyRingEditorInterface {
fun createRevocation( fun createRevocation(
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPSignature ): OpenPGPSignature
@Throws(PGPException::class)
@Deprecated("Pass in a KeyIdentifier instead of a keyId")
fun createRevocation(
subkeyId: Long,
protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes?
) = createRevocation(KeyIdentifier(subkeyId), protector, revocationAttributes)
/** /**
* Create a detached revocation certificate, which can be used to revoke the specified subkey. * Create a detached revocation certificate, which can be used to revoke the specified subkey.
* The original key will not be modified by this method. * The original key will not be modified by this method.
* *
* @param subkeyId id of the subkey to be revoked * @param subkeyIdentifier id of the subkey to be revoked
* @param protector protector to unlock the primary key. * @param protector protector to unlock the primary key.
* @param revocationAttributes reason for the revocation * @param revocationAttributes reason for the revocation
* @return revocation certificate * @return revocation certificate
@ -531,16 +568,24 @@ interface SecretKeyRingEditorInterface {
*/ */
@Throws(PGPException::class) @Throws(PGPException::class)
fun createRevocation( fun createRevocation(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPSignature ): OpenPGPSignature
@Deprecated("Pass in a KeyIdentifier instead of keyId")
@Throws(PGPException::class)
fun createRevocation(
subkeyId: Long,
protector: SecretKeyRingProtector,
callback: RevocationSignatureSubpackets.Callback?
) = createRevocation(KeyIdentifier(subkeyId), protector, callback)
/** /**
* Create a detached revocation certificate, which can be used to revoke the specified subkey. * Create a detached revocation certificate, which can be used to revoke the specified subkey.
* The original key will not be modified by this method. * The original key will not be modified by this method.
* *
* @param subkeyId id of the subkey to be revoked * @param subkeyIdentifier id of the subkey to be revoked
* @param protector protector to unlock the primary key. * @param protector protector to unlock the primary key.
* @param callback callback to modify the subpackets of the revocation certificate. * @param callback callback to modify the subpackets of the revocation certificate.
* @return revocation certificate * @return revocation certificate
@ -548,10 +593,10 @@ interface SecretKeyRingEditorInterface {
*/ */
@Throws(PGPException::class) @Throws(PGPException::class)
fun createRevocation( fun createRevocation(
subkeyId: Long, subkeyIdentifier: KeyIdentifier,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
callback: RevocationSignatureSubpackets.Callback? callback: RevocationSignatureSubpackets.Callback?
): PGPSignature ): OpenPGPSignature
/** /**
* Create a detached revocation certificate, which can be used to revoke the specified subkey. * Create a detached revocation certificate, which can be used to revoke the specified subkey.
@ -568,7 +613,7 @@ interface SecretKeyRingEditorInterface {
subkeyFingerprint: OpenPgpFingerprint, subkeyFingerprint: OpenPgpFingerprint,
protector: SecretKeyRingProtector, protector: SecretKeyRingProtector,
revocationAttributes: RevocationAttributes? revocationAttributes: RevocationAttributes?
): PGPSignature ): OpenPGPSignature
/** /**
* Change the passphrase of the whole key ring. * Change the passphrase of the whole key ring.
@ -676,7 +721,7 @@ interface SecretKeyRingEditorInterface {
* *
* @return the key * @return the key
*/ */
fun done(): PGPSecretKeyRing fun done(): OpenPGPKey
fun addSubKey( fun addSubKey(
keySpec: KeySpec, keySpec: KeySpec,

View file

@ -7,6 +7,7 @@ package org.pgpainless.key.protection
import org.bouncycastle.bcpg.KeyIdentifier import org.bouncycastle.bcpg.KeyIdentifier
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.PGPSecretKey import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
import org.pgpainless.util.Passphrase import org.pgpainless.util.Passphrase
@ -32,6 +33,25 @@ class PasswordBasedSecretKeyRingProtector : BaseSecretKeyRingProtector {
) : super(passphraseProvider, settings) ) : super(passphraseProvider, settings)
companion object { companion object {
@JvmStatic
fun forKey(
cert: OpenPGPCertificate,
passphrase: Passphrase
): PasswordBasedSecretKeyRingProtector {
return object : SecretKeyPassphraseProvider {
override fun getPassphraseFor(keyIdentifier: KeyIdentifier): Passphrase? {
return if (hasPassphrase(keyIdentifier)) passphrase else null
}
override fun hasPassphrase(keyIdentifier: KeyIdentifier): Boolean {
return cert.getKey(keyIdentifier) != null
}
}
.let { PasswordBasedSecretKeyRingProtector(it) }
}
@JvmStatic @JvmStatic
fun forKey( fun forKey(
keyRing: PGPKeyRing, keyRing: PGPKeyRing,

View file

@ -12,6 +12,7 @@ import org.bouncycastle.openpgp.PGPSecretKey
import org.bouncycastle.openpgp.PGPSecretKeyRing import org.bouncycastle.openpgp.PGPSecretKeyRing
import org.bouncycastle.openpgp.api.KeyPassphraseProvider import org.bouncycastle.openpgp.api.KeyPassphraseProvider
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor import org.bouncycastle.openpgp.operator.PBESecretKeyEncryptor
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider
@ -105,6 +106,10 @@ interface SecretKeyRingProtector : KeyPassphraseProvider {
KeyRingProtectionSettings.secureDefaultSettings(), KeyRingProtectionSettings.secureDefaultSettings(),
missingPassphraseCallback) missingPassphraseCallback)
@JvmStatic
fun unlockEachKeyWith(passphrase: Passphrase, keys: OpenPGPKey): SecretKeyRingProtector =
fromPassphraseMap(keys.secretKeys.keys.associateWith { passphrase })
/** /**
* Use the provided passphrase to lock/unlock all keys in the provided key ring. * Use the provided passphrase to lock/unlock all keys in the provided key ring.
* *

View file

@ -8,6 +8,8 @@ import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPPrimaryKey
import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.algorithm.HashAlgorithm import org.pgpainless.algorithm.HashAlgorithm
@ -63,4 +65,7 @@ class PrimaryKeyBindingSignatureBuilder :
fun build(primaryKey: PGPPublicKey): PGPSignature = fun build(primaryKey: PGPPublicKey): PGPSignature =
buildAndInitSignatureGenerator() buildAndInitSignatureGenerator()
.generateCertification(primaryKey, signingKey.publicKey.pgpPublicKey) .generateCertification(primaryKey, signingKey.publicKey.pgpPublicKey)
fun build(primaryKey: OpenPGPPrimaryKey): OpenPGPComponentSignature =
OpenPGPComponentSignature(build(primaryKey.pgpPublicKey), primaryKey, primaryKey)
} }

View file

@ -8,7 +8,11 @@ import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPUserId
import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey
import org.bouncycastle.openpgp.api.OpenPGPSignature
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.algorithm.SignatureType import org.pgpainless.algorithm.SignatureType
import org.pgpainless.key.protection.SecretKeyRingProtector import org.pgpainless.key.protection.SecretKeyRingProtector
@ -59,6 +63,11 @@ constructor(
} }
} }
fun build(revokeeKey: OpenPGPComponentKey): OpenPGPSignature {
return OpenPGPComponentSignature(
build(revokeeKey.pgpPublicKey), signingKey.publicKey, revokeeKey)
}
@Throws(PGPException::class) @Throws(PGPException::class)
fun build(revokeeUserId: CharSequence): PGPSignature = fun build(revokeeUserId: CharSequence): PGPSignature =
buildAndInitSignatureGenerator() buildAndInitSignatureGenerator()
@ -69,6 +78,11 @@ constructor(
} }
.generateCertification(revokeeUserId.toString(), signingKey.publicKey.pgpPublicKey) .generateCertification(revokeeUserId.toString(), signingKey.publicKey.pgpPublicKey)
fun build(revokeeUserId: OpenPGPUserId): OpenPGPComponentSignature {
return OpenPGPComponentSignature(
build(revokeeUserId.userId), signingKey.publicKey, revokeeUserId)
}
init { init {
hashedSubpackets.setRevocable(false) hashedSubpackets.setRevocable(false)
} }

View file

@ -8,6 +8,8 @@ import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKey import org.bouncycastle.openpgp.PGPPublicKey
import org.bouncycastle.openpgp.PGPSignature import org.bouncycastle.openpgp.PGPSignature
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentKey
import org.bouncycastle.openpgp.api.OpenPGPCertificate.OpenPGPComponentSignature
import org.bouncycastle.openpgp.api.OpenPGPKey import org.bouncycastle.openpgp.api.OpenPGPKey
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.algorithm.HashAlgorithm import org.pgpainless.algorithm.HashAlgorithm
@ -77,4 +79,7 @@ class SubkeyBindingSignatureBuilder : AbstractSignatureBuilder<SubkeyBindingSign
fun build(subkey: PGPPublicKey): PGPSignature = fun build(subkey: PGPPublicKey): PGPSignature =
buildAndInitSignatureGenerator() buildAndInitSignatureGenerator()
.generateCertification(signingKey.publicKey.pgpPublicKey, subkey) .generateCertification(signingKey.publicKey.pgpPublicKey, subkey)
fun build(subkey: OpenPGPComponentKey): OpenPGPComponentSignature =
OpenPGPComponentSignature(build(subkey.pgpPublicKey), signingKey.publicKey, subkey)
} }

View file

@ -6,6 +6,7 @@ package org.pgpainless.util.selection.userid
import java.util.function.Predicate import java.util.function.Predicate
import org.bouncycastle.openpgp.PGPKeyRing import org.bouncycastle.openpgp.PGPKeyRing
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
abstract class SelectUserId : Predicate<String>, (String) -> Boolean { abstract class SelectUserId : Predicate<String>, (String) -> Boolean {
@ -72,6 +73,14 @@ abstract class SelectUserId : Predicate<String>, (String) -> Boolean {
@JvmStatic @JvmStatic
fun byEmail(email: CharSequence) = or(exactMatch(email), containsEmailAddress(email)) fun byEmail(email: CharSequence) = or(exactMatch(email), containsEmailAddress(email))
@JvmStatic
fun validUserId(key: OpenPGPCertificate) =
object : SelectUserId() {
private val info = PGPainless.getInstance().inspect(key)
override fun invoke(userId: String): Boolean = info.isUserIdValid(userId)
}
@JvmStatic @JvmStatic
fun validUserId(keyRing: PGPKeyRing) = fun validUserId(keyRing: PGPKeyRing) =
object : SelectUserId() { object : SelectUserId() {

View file

@ -23,6 +23,7 @@ import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -130,16 +131,16 @@ public class SigningTest {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void testSignWithRevokedUserIdFails() public void testSignWithRevokedUserIdFails()
throws PGPException { throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("alice", "password123") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("alice", "password123");
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith( SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(
Passphrase.fromPassword("password123")); Passphrase.fromPassword("password123"));
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.revokeUserId("alice", protector) .revokeUserId("alice", protector)
.done(); .done();
final PGPSecretKeyRing fSecretKeys = secretKeys; final OpenPGPKey fSecretKeys = secretKeys;
SigningOptions opts = SigningOptions.get(); SigningOptions opts = SigningOptions.get();
// "alice" has been revoked // "alice" has been revoked

View file

@ -9,14 +9,14 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -34,25 +34,25 @@ import org.pgpainless.util.Passphrase;
/** /**
* PGPainless offers a simple API to modify keys by adding and replacing signatures and/or subkeys. * PGPainless offers a simple API to modify keys by adding and replacing signatures and/or subkeys.
* The main entry point to this API is {@link PGPainless#modifyKeyRing(PGPSecretKeyRing)}. * The main entry point to this API is {@link PGPainless#modify(OpenPGPKey)}.
*/ */
public class ModifyKeys { public class ModifyKeys {
private final String userId = "alice@pgpainless.org"; private final String userId = "alice@pgpainless.org";
private final String originalPassphrase = "p4ssw0rd"; private final String originalPassphrase = "p4ssw0rd";
private PGPSecretKeyRing secretKey; private OpenPGPKey secretKey;
private long primaryKeyId; private KeyIdentifier primaryKeyId;
private KeyIdentifier encryptionSubkeyId; private KeyIdentifier encryptionSubkeyId;
private KeyIdentifier signingSubkeyId; private KeyIdentifier signingSubkeyId;
@BeforeEach @BeforeEach
public void generateKey() { public void generateKey() {
secretKey = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing(userId, originalPassphrase) secretKey = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing(userId, originalPassphrase);
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey); KeyRingInfo info = api.inspect(secretKey);
primaryKeyId = info.getKeyIdentifier().getKeyId(); primaryKeyId = info.getKeyIdentifier();
encryptionSubkeyId = info.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getKeyIdentifier(); encryptionSubkeyId = info.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getKeyIdentifier();
signingSubkeyId = info.getSigningSubkeys().get(0).getKeyIdentifier(); signingSubkeyId = info.getSigningSubkeys().get(0).getKeyIdentifier();
} }
@ -63,9 +63,9 @@ public class ModifyKeys {
@Test @Test
public void extractPublicKey() { public void extractPublicKey() {
// the certificate consists of only the public keys // the certificate consists of only the public keys
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKey); OpenPGPCertificate certificate = secretKey.toCertificate();
KeyRingInfo info = PGPainless.inspectKeyRing(certificate); KeyRingInfo info = PGPainless.getInstance().inspect(certificate);
assertFalse(info.isSecretKey()); assertFalse(info.isSecretKey());
} }
@ -73,11 +73,11 @@ public class ModifyKeys {
* This example demonstrates how to export a secret key or certificate to an ASCII armored string. * This example demonstrates how to export a secret key or certificate to an ASCII armored string.
*/ */
@Test @Test
public void toAsciiArmoredString() { public void toAsciiArmoredString() throws IOException {
PGPPublicKeyRing certificate = PGPainless.extractCertificate(secretKey); OpenPGPCertificate certificate = secretKey.toCertificate();
String asciiArmoredSecretKey = PGPainless.asciiArmor(secretKey); String asciiArmoredSecretKey = secretKey.toAsciiArmoredString();
String asciiArmoredCertificate = PGPainless.asciiArmor(certificate); String asciiArmoredCertificate = certificate.toAsciiArmoredString();
assertTrue(asciiArmoredSecretKey.startsWith("-----BEGIN PGP PRIVATE KEY BLOCK-----")); assertTrue(asciiArmoredSecretKey.startsWith("-----BEGIN PGP PRIVATE KEY BLOCK-----"));
assertTrue(asciiArmoredCertificate.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----")); assertTrue(asciiArmoredCertificate.startsWith("-----BEGIN PGP PUBLIC KEY BLOCK-----"));
@ -88,7 +88,8 @@ public class ModifyKeys {
*/ */
@Test @Test
public void changePassphrase() throws PGPException { public void changePassphrase() throws PGPException {
secretKey = PGPainless.modifyKeyRing(secretKey) PGPainless api = PGPainless.getInstance();
secretKey = api.modify(secretKey)
.changePassphraseFromOldPassphrase(Passphrase.fromPassword(originalPassphrase)) .changePassphraseFromOldPassphrase(Passphrase.fromPassword(originalPassphrase))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("n3wP4ssW0rD")) .toNewPassphrase(Passphrase.fromPassword("n3wP4ssW0rD"))
@ -96,9 +97,9 @@ public class ModifyKeys {
// Old passphrase no longer works // Old passphrase no longer works
assertThrows(WrongPassphraseException.class, () -> assertThrows(WrongPassphraseException.class, () ->
UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(), Passphrase.fromPassword(originalPassphrase))); UnlockSecretKey.unlockSecretKey(secretKey.getPGPSecretKeyRing().getSecretKey(), Passphrase.fromPassword(originalPassphrase)));
// But the new one does // But the new one does
UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(), Passphrase.fromPassword("n3wP4ssW0rD")); UnlockSecretKey.unlockSecretKey(secretKey.getPGPSecretKeyRing().getSecretKey(), Passphrase.fromPassword("n3wP4ssW0rD"));
} }
/** /**
@ -107,9 +108,10 @@ public class ModifyKeys {
*/ */
@Test @Test
public void changeSingleSubkeyPassphrase() throws PGPException { public void changeSingleSubkeyPassphrase() throws PGPException {
secretKey = PGPainless.modifyKeyRing(secretKey) PGPainless api = PGPainless.getInstance();
secretKey = api.modify(secretKey)
// Here we change the passphrase of the encryption subkey // Here we change the passphrase of the encryption subkey
.changeSubKeyPassphraseFromOldPassphrase(encryptionSubkeyId.getKeyId(), Passphrase.fromPassword(originalPassphrase)) .changeSubKeyPassphraseFromOldPassphrase(encryptionSubkeyId, Passphrase.fromPassword(originalPassphrase))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("cryptP4ssphr4s3")) .toNewPassphrase(Passphrase.fromPassword("cryptP4ssphr4s3"))
.done(); .done();
@ -117,12 +119,12 @@ public class ModifyKeys {
// encryption key can now only be unlocked using the new passphrase // encryption key can now only be unlocked using the new passphrase
assertThrows(WrongPassphraseException.class, () -> assertThrows(WrongPassphraseException.class, () ->
UnlockSecretKey.unlockSecretKey( UnlockSecretKey.unlockSecretKey(
secretKey.getSecretKey(encryptionSubkeyId), Passphrase.fromPassword(originalPassphrase))); secretKey.getSecretKey(encryptionSubkeyId).getPGPSecretKey(), Passphrase.fromPassword(originalPassphrase)));
UnlockSecretKey.unlockSecretKey( UnlockSecretKey.unlockSecretKey(
secretKey.getSecretKey(encryptionSubkeyId), Passphrase.fromPassword("cryptP4ssphr4s3")); secretKey.getSecretKey(encryptionSubkeyId).getPGPSecretKey(), Passphrase.fromPassword("cryptP4ssphr4s3"));
// primary key remains unchanged // primary key remains unchanged
UnlockSecretKey.unlockSecretKey( UnlockSecretKey.unlockSecretKey(
secretKey.getSecretKey(primaryKeyId), Passphrase.fromPassword(originalPassphrase)); secretKey.getSecretKey(primaryKeyId).getPGPSecretKey(), Passphrase.fromPassword(originalPassphrase));
} }
/** /**
@ -130,13 +132,14 @@ public class ModifyKeys {
*/ */
@Test @Test
public void addUserId() throws PGPException { public void addUserId() throws PGPException {
PGPainless api = PGPainless.getInstance();
SecretKeyRingProtector protector = SecretKeyRingProtector protector =
SecretKeyRingProtector.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey); SecretKeyRingProtector.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey);
secretKey = PGPainless.modifyKeyRing(secretKey) secretKey = api.modify(secretKey)
.addUserId("additional@user.id", protector) .addUserId("additional@user.id", protector)
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey); KeyRingInfo info = api.inspect(secretKey);
assertTrue(info.isUserIdValid("additional@user.id")); assertTrue(info.isUserIdValid("additional@user.id"));
assertFalse(info.isUserIdValid("another@user.id")); assertFalse(info.isUserIdValid("another@user.id"));
} }
@ -156,11 +159,12 @@ public class ModifyKeys {
*/ */
@Test @Test
public void addSubkey() { public void addSubkey() {
PGPainless api = PGPainless.getInstance();
// Protector for unlocking the existing secret key // Protector for unlocking the existing secret key
SecretKeyRingProtector protector = SecretKeyRingProtector protector =
SecretKeyRingProtector.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey); SecretKeyRingProtector.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey);
Passphrase subkeyPassphrase = Passphrase.fromPassword("subk3yP4ssphr4s3"); Passphrase subkeyPassphrase = Passphrase.fromPassword("subk3yP4ssphr4s3");
secretKey = PGPainless.modifyKeyRing(secretKey) secretKey = api.modify(secretKey)
.addSubKey( .addSubKey(
KeySpec.getBuilder(KeyType.ECDH(EllipticCurve._BRAINPOOLP512R1), KeyFlag.ENCRYPT_COMMS) KeySpec.getBuilder(KeyType.ECDH(EllipticCurve._BRAINPOOLP512R1), KeyFlag.ENCRYPT_COMMS)
.build(), .build(),
@ -168,7 +172,7 @@ public class ModifyKeys {
protector) protector)
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey); KeyRingInfo info = api.inspect(secretKey);
assertEquals(4, info.getSecretKeys().size()); assertEquals(4, info.getSecretKeys().size());
assertEquals(4, info.getPublicKeys().size()); assertEquals(4, info.getPublicKeys().size());
List<OpenPGPCertificate.OpenPGPComponentKey> encryptionSubkeys = info.getEncryptionSubkeys(EncryptionPurpose.COMMUNICATIONS); List<OpenPGPCertificate.OpenPGPComponentKey> encryptionSubkeys = info.getEncryptionSubkeys(EncryptionPurpose.COMMUNICATIONS);
@ -176,7 +180,7 @@ public class ModifyKeys {
OpenPGPCertificate.OpenPGPComponentKey addedKey = encryptionSubkeys.stream() OpenPGPCertificate.OpenPGPComponentKey addedKey = encryptionSubkeys.stream()
.filter(it -> !it.getKeyIdentifier().matches(encryptionSubkeyId)).findFirst() .filter(it -> !it.getKeyIdentifier().matches(encryptionSubkeyId)).findFirst()
.get(); .get();
UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(addedKey.getKeyIdentifier()), subkeyPassphrase); UnlockSecretKey.unlockSecretKey(secretKey.getSecretKey(addedKey.getKeyIdentifier()).getPGPSecretKey(), subkeyPassphrase);
} }
/** /**
@ -185,15 +189,16 @@ public class ModifyKeys {
*/ */
@Test @Test
public void setKeyExpirationDate() { public void setKeyExpirationDate() {
PGPainless api = PGPainless.getInstance();
Date expirationDate = DateUtil.parseUTCDate("2030-06-24 12:44:56 UTC"); Date expirationDate = DateUtil.parseUTCDate("2030-06-24 12:44:56 UTC");
SecretKeyRingProtector protector = SecretKeyRingProtector SecretKeyRingProtector protector = SecretKeyRingProtector
.unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey); .unlockEachKeyWith(Passphrase.fromPassword(originalPassphrase), secretKey);
secretKey = PGPainless.modifyKeyRing(secretKey) secretKey = api.modify(secretKey)
.setExpirationDate(expirationDate, protector) .setExpirationDate(expirationDate, protector)
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKey); KeyRingInfo info = api.inspect(secretKey);
assertEquals(DateUtil.formatUTCDate(expirationDate), assertEquals(DateUtil.formatUTCDate(expirationDate),
DateUtil.formatUTCDate(info.getPrimaryKeyExpirationDate())); DateUtil.formatUTCDate(info.getPrimaryKeyExpirationDate()));
assertEquals(DateUtil.formatUTCDate(expirationDate), assertEquals(DateUtil.formatUTCDate(expirationDate),
@ -207,19 +212,20 @@ public class ModifyKeys {
*/ */
@Test @Test
public void revokeUserId() throws PGPException { public void revokeUserId() throws PGPException {
PGPainless api = PGPainless.getInstance();
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockEachKeyWith( SecretKeyRingProtector protector = SecretKeyRingProtector.unlockEachKeyWith(
Passphrase.fromPassword(originalPassphrase), secretKey); Passphrase.fromPassword(originalPassphrase), secretKey);
secretKey = PGPainless.modifyKeyRing(secretKey) secretKey = api.modify(secretKey)
.addUserId("alcie@pgpainless.org", protector) .addUserId("alcie@pgpainless.org", protector)
.done(); .done();
// Initially the user-id is valid // Initially the user-id is valid
assertTrue(PGPainless.inspectKeyRing(secretKey).isUserIdValid("alcie@pgpainless.org")); assertTrue(api.inspect(secretKey).isUserIdValid("alcie@pgpainless.org"));
// Revoke the second user-id // Revoke the second user-id
secretKey = PGPainless.modifyKeyRing(secretKey) secretKey = api.modify(secretKey)
.revokeUserId("alcie@pgpainless.org", protector) .revokeUserId("alcie@pgpainless.org", protector)
.done(); .done();
// Now the user-id is no longer valid // Now the user-id is no longer valid
assertFalse(PGPainless.inspectKeyRing(secretKey).isUserIdValid("alcie@pgpainless.org")); assertFalse(api.inspect(secretKey).isUserIdValid("alcie@pgpainless.org"));
} }
} }

View file

@ -14,8 +14,11 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection; import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil; import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator; import org.bouncycastle.openpgp.operator.KeyFingerPrintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.pgpainless.PGPainless;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
public class TestKeys { public class TestKeys {
@ -265,6 +268,10 @@ public class TestKeys {
"=1d67\n" + "=1d67\n" +
"-----END PGP PRIVATE KEY BLOCK-----"; "-----END PGP PRIVATE KEY BLOCK-----";
public static OpenPGPKey getJulietKey() throws PGPException, IOException {
return PGPainless.getInstance().toKey(getJulietSecretKeyRing());
}
public static PGPSecretKeyRing getJulietSecretKeyRing() throws IOException, PGPException { public static PGPSecretKeyRing getJulietSecretKeyRing() throws IOException, PGPException {
if (julietSecretKeyRing == null) { if (julietSecretKeyRing == null) {
julietSecretKeyRing = new PGPSecretKeyRing( julietSecretKeyRing = new PGPSecretKeyRing(
@ -281,6 +288,10 @@ public class TestKeys {
return julietSecretKeyRingCollection; return julietSecretKeyRingCollection;
} }
public static OpenPGPCertificate getJulietCertificate() throws IOException {
return PGPainless.getInstance().toCertificate(getJulietPublicKeyRing());
}
public static PGPPublicKeyRing getJulietPublicKeyRing() throws IOException { public static PGPPublicKeyRing getJulietPublicKeyRing() throws IOException {
if (julietPublicKeyRing == null) { if (julietPublicKeyRing == null) {
julietPublicKeyRing = new PGPPublicKeyRing( julietPublicKeyRing = new PGPPublicKeyRing(
@ -297,6 +308,10 @@ public class TestKeys {
return julietPublicKeyRingCollection; return julietPublicKeyRingCollection;
} }
public static OpenPGPKey getRomeoKey() throws PGPException, IOException {
return PGPainless.getInstance().toKey(getRomeoSecretKeyRing());
}
public static PGPSecretKeyRing getRomeoSecretKeyRing() throws IOException, PGPException { public static PGPSecretKeyRing getRomeoSecretKeyRing() throws IOException, PGPException {
if (romeoSecretKeyRing == null) { if (romeoSecretKeyRing == null) {
romeoSecretKeyRing = new PGPSecretKeyRing( romeoSecretKeyRing = new PGPSecretKeyRing(
@ -313,6 +328,10 @@ public class TestKeys {
return romeoSecretKeyRingCollection; return romeoSecretKeyRingCollection;
} }
public static OpenPGPCertificate getRomeoCertificate() throws IOException {
return PGPainless.getInstance().toCertificate(getRomeoPublicKeyRing());
}
public static PGPPublicKeyRing getRomeoPublicKeyRing() throws IOException { public static PGPPublicKeyRing getRomeoPublicKeyRing() throws IOException {
if (romeoPublicKeyRing == null) { if (romeoPublicKeyRing == null) {
romeoPublicKeyRing = new PGPPublicKeyRing( romeoPublicKeyRing = new PGPPublicKeyRing(
@ -329,6 +348,10 @@ public class TestKeys {
return romeoPublicKeyRingCollection; return romeoPublicKeyRingCollection;
} }
public static OpenPGPKey getEmilKey() throws PGPException, IOException {
return PGPainless.getInstance().toKey(getEmilSecretKeyRing());
}
public static PGPSecretKeyRing getEmilSecretKeyRing() throws IOException, PGPException { public static PGPSecretKeyRing getEmilSecretKeyRing() throws IOException, PGPException {
if (emilSecretKeyRing == null) { if (emilSecretKeyRing == null) {
emilSecretKeyRing = new PGPSecretKeyRing( emilSecretKeyRing = new PGPSecretKeyRing(
@ -345,6 +368,10 @@ public class TestKeys {
return emilSecretKeyRingCollection; return emilSecretKeyRingCollection;
} }
public static OpenPGPCertificate getEmilCertificate() throws IOException {
return PGPainless.getInstance().toCertificate(getEmilPublicKeyRing());
}
public static PGPPublicKeyRing getEmilPublicKeyRing() throws IOException { public static PGPPublicKeyRing getEmilPublicKeyRing() throws IOException {
if (emilPublicKeyRing == null) { if (emilPublicKeyRing == null) {
emilPublicKeyRing = new PGPPublicKeyRing( emilPublicKeyRing = new PGPPublicKeyRing(
@ -361,6 +388,10 @@ public class TestKeys {
return emilPublicKeyRingCollection; return emilPublicKeyRingCollection;
} }
public static OpenPGPKey getCryptieKey() throws PGPException, IOException {
return PGPainless.getInstance().toKey(getCryptieSecretKeyRing());
}
public static PGPSecretKeyRing getCryptieSecretKeyRing() throws IOException, PGPException { public static PGPSecretKeyRing getCryptieSecretKeyRing() throws IOException, PGPException {
if (cryptieSecretKeyRing == null) { if (cryptieSecretKeyRing == null) {
cryptieSecretKeyRing = new PGPSecretKeyRing( cryptieSecretKeyRing = new PGPSecretKeyRing(
@ -377,6 +408,10 @@ public class TestKeys {
return cryptieSecretKeyRingCollection; return cryptieSecretKeyRingCollection;
} }
public static OpenPGPCertificate getCryptieCertificate() throws IOException {
return PGPainless.getInstance().toCertificate(getCryptiePublicKeyRing());
}
public static PGPPublicKeyRing getCryptiePublicKeyRing() throws IOException { public static PGPPublicKeyRing getCryptiePublicKeyRing() throws IOException {
if (cryptiePublicKeyRing == null) { if (cryptiePublicKeyRing == null) {
cryptiePublicKeyRing = new PGPPublicKeyRing( cryptiePublicKeyRing = new PGPPublicKeyRing(

View file

@ -18,10 +18,10 @@ import java.util.List;
import org.bouncycastle.bcpg.sig.IssuerFingerprint; import org.bouncycastle.bcpg.sig.IssuerFingerprint;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.HashAlgorithm; import org.pgpainless.algorithm.HashAlgorithm;
@ -39,10 +39,10 @@ public class KeyGenerationSubpacketsTest {
@Test @Test
public void verifyDefaultSubpacketsForUserIdSignatures() public void verifyDefaultSubpacketsForUserIdSignatures()
throws PGPException { throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
Date plus1Sec = new Date(secretKeys.getPublicKey().getCreationTime().getTime() + 1000); Date plus1Sec = new Date(secretKeys.getPrimarySecretKey().getCreationTime().getTime() + 1000);
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
PGPSignature userIdSig = info.getLatestUserIdCertification("Alice"); PGPSignature userIdSig = info.getLatestUserIdCertification("Alice");
assertNotNull(userIdSig); assertNotNull(userIdSig);
int keyFlags = userIdSig.getHashedSubPackets().getKeyFlags(); int keyFlags = userIdSig.getHashedSubPackets().getKeyFlags();
@ -54,7 +54,7 @@ public class KeyGenerationSubpacketsTest {
assertEquals("Alice", info.getPrimaryUserId()); assertEquals("Alice", info.getPrimaryUserId());
secretKeys = PGPainless.modifyKeyRing(secretKeys, plus1Sec) secretKeys = api.modify(secretKeys, plus1Sec)
.addUserId("Bob", .addUserId("Bob",
new SelfSignatureSubpackets.Callback() { new SelfSignatureSubpackets.Callback() {
@Override @Override
@ -66,7 +66,7 @@ public class KeyGenerationSubpacketsTest {
.addUserId("Alice", SecretKeyRingProtector.unprotectedKeys()) .addUserId("Alice", SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, plus1Sec); info = api.inspect(secretKeys, plus1Sec);
userIdSig = info.getLatestUserIdCertification("Alice"); userIdSig = info.getLatestUserIdCertification("Alice");
assertNotNull(userIdSig); assertNotNull(userIdSig);
@ -89,7 +89,7 @@ public class KeyGenerationSubpacketsTest {
Date now = plus1Sec; Date now = plus1Sec;
Date t1 = new Date(now.getTime() + 1000 * 60 * 60); Date t1 = new Date(now.getTime() + 1000 * 60 * 60);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1) secretKeys = api.modify(secretKeys, t1)
.addUserId("Alice", new SelfSignatureSubpackets.Callback() { .addUserId("Alice", new SelfSignatureSubpackets.Callback() {
@Override @Override
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) { public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
@ -98,7 +98,7 @@ public class KeyGenerationSubpacketsTest {
} }
}, SecretKeyRingProtector.unprotectedKeys()) }, SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, t1); info = api.inspect(secretKeys, t1);
assertEquals("Alice", info.getPrimaryUserId()); assertEquals("Alice", info.getPrimaryUserId());
assertEquals(Collections.singleton(HashAlgorithm.SHA1), info.getPreferredHashAlgorithms("Alice")); assertEquals(Collections.singleton(HashAlgorithm.SHA1), info.getPreferredHashAlgorithms("Alice"));
} }
@ -106,29 +106,29 @@ public class KeyGenerationSubpacketsTest {
@Test @Test
public void verifyDefaultSubpacketsForSubkeyBindingSignatures() public void verifyDefaultSubpacketsForSubkeyBindingSignatures()
throws PGPException { throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
List<OpenPGPCertificate.OpenPGPComponentKey> keysBefore = info.getPublicKeys(); List<OpenPGPCertificate.OpenPGPComponentKey> keysBefore = info.getPublicKeys();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addSubKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA).build(), .addSubKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA).build(),
Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys()) Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(secretKeys);
List<OpenPGPCertificate.OpenPGPComponentKey> keysAfter = new ArrayList<>(info.getPublicKeys()); List<OpenPGPCertificate.OpenPGPComponentKey> keysAfter = new ArrayList<>(info.getPublicKeys());
keysAfter.removeAll(keysBefore); keysAfter.removeAll(keysBefore);
assertEquals(1, keysAfter.size()); assertEquals(1, keysAfter.size());
OpenPGPCertificate.OpenPGPComponentKey newSigningKey = keysAfter.get(0); OpenPGPCertificate.OpenPGPComponentKey newSigningKey = keysAfter.get(0);
PGPSignature bindingSig = info.getCurrentSubkeyBindingSignature(newSigningKey.getKeyIdentifier().getKeyId()); PGPSignature bindingSig = info.getCurrentSubkeyBindingSignature(newSigningKey.getKeyIdentifier());
assertNotNull(bindingSig); assertNotNull(bindingSig);
assureSignatureHasDefaultSubpackets(bindingSig, secretKeys, KeyFlag.SIGN_DATA); assureSignatureHasDefaultSubpackets(bindingSig, secretKeys, KeyFlag.SIGN_DATA);
assertNotNull(bindingSig.getHashedSubPackets().getEmbeddedSignatures().get(0)); assertNotNull(bindingSig.getHashedSubPackets().getEmbeddedSignatures().get(0));
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addSubKey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS).build(), .addSubKey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS).build(),
Passphrase.emptyPassphrase(), Passphrase.emptyPassphrase(),
new SelfSignatureSubpackets.Callback() { new SelfSignatureSubpackets.Callback() {
@ -139,24 +139,24 @@ public class KeyGenerationSubpacketsTest {
}, SecretKeyRingProtector.unprotectedKeys()) }, SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(secretKeys);
keysAfter = new ArrayList<>(info.getPublicKeys()); keysAfter = new ArrayList<>(info.getPublicKeys());
keysAfter.removeAll(keysBefore); keysAfter.removeAll(keysBefore);
keysAfter.remove(newSigningKey); keysAfter.remove(newSigningKey);
assertEquals(1, keysAfter.size()); assertEquals(1, keysAfter.size());
OpenPGPCertificate.OpenPGPComponentKey newEncryptionKey = keysAfter.get(0); OpenPGPCertificate.OpenPGPComponentKey newEncryptionKey = keysAfter.get(0);
bindingSig = info.getCurrentSubkeyBindingSignature(newEncryptionKey.getKeyIdentifier().getKeyId()); bindingSig = info.getCurrentSubkeyBindingSignature(newEncryptionKey.getKeyIdentifier());
assertNotNull(bindingSig); assertNotNull(bindingSig);
assertNull(bindingSig.getHashedSubPackets().getIssuerFingerprint()); assertNull(bindingSig.getHashedSubPackets().getIssuerFingerprint());
assertEquals(KeyFlag.toBitmask(KeyFlag.ENCRYPT_COMMS), bindingSig.getHashedSubPackets().getKeyFlags()); assertEquals(KeyFlag.toBitmask(KeyFlag.ENCRYPT_COMMS), bindingSig.getHashedSubPackets().getKeyFlags());
} }
private void assureSignatureHasDefaultSubpackets(PGPSignature signature, PGPSecretKeyRing secretKeys, KeyFlag... keyFlags) { private void assureSignatureHasDefaultSubpackets(PGPSignature signature, OpenPGPKey secretKeys, KeyFlag... keyFlags) {
PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets(); PGPSignatureSubpacketVector hashedSubpackets = signature.getHashedSubPackets();
assertNotNull(hashedSubpackets.getIssuerFingerprint()); assertNotNull(hashedSubpackets.getIssuerFingerprint());
assertEquals(secretKeys.getPublicKey().getKeyID(), hashedSubpackets.getIssuerKeyID()); assertEquals(secretKeys.getKeyIdentifier().getKeyId(), hashedSubpackets.getIssuerKeyID());
assertArrayEquals( assertArrayEquals(
secretKeys.getPublicKey().getFingerprint(), secretKeys.getFingerprint(),
hashedSubpackets.getIssuerFingerprint().getFingerprint()); hashedSubpackets.getIssuerFingerprint().getFingerprint());
assertEquals(hashedSubpackets.getKeyFlags(), KeyFlag.toBitmask(keyFlags)); assertEquals(hashedSubpackets.getKeyFlags(), KeyFlag.toBitmask(keyFlags));
} }

View file

@ -24,9 +24,7 @@ import java.util.Set;
import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.JUtils; import org.junit.JUtils;
@ -50,7 +48,6 @@ import org.pgpainless.key.generation.type.ecc.EllipticCurve;
import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve; import org.pgpainless.key.generation.type.eddsa_legacy.EdDSALegacyCurve;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnprotectedKeysProtector; import org.pgpainless.key.protection.UnprotectedKeysProtector;
import org.pgpainless.key.util.KeyRingUtils;
import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.key.util.UserId; import org.pgpainless.key.util.UserId;
import org.pgpainless.util.DateUtil; import org.pgpainless.util.DateUtil;
@ -62,11 +59,12 @@ public class KeyRingInfoTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void testWithEmilsKeys() throws IOException, PGPException { public void testWithEmilsKeys() throws IOException, PGPException {
PGPainless api = PGPainless.getInstance();
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getEmilKey();
PGPPublicKeyRing publicKeys = TestKeys.getEmilPublicKeyRing(); OpenPGPCertificate publicKeys = TestKeys.getEmilCertificate();
KeyRingInfo sInfo = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo sInfo = api.inspect(secretKeys);
KeyRingInfo pInfo = PGPainless.inspectKeyRing(publicKeys); KeyRingInfo pInfo = api.inspect(publicKeys);
assertEquals(TestKeys.EMIL_KEY_ID, sInfo.getKeyIdentifier().getKeyId()); assertEquals(TestKeys.EMIL_KEY_ID, sInfo.getKeyIdentifier().getKeyId());
assertEquals(TestKeys.EMIL_KEY_ID, pInfo.getKeyIdentifier().getKeyId()); assertEquals(TestKeys.EMIL_KEY_ID, pInfo.getKeyIdentifier().getKeyId());
@ -108,13 +106,13 @@ public class KeyRingInfoTest {
assertNull(sInfo.getRevocationDate()); assertNull(sInfo.getRevocationDate());
assertNull(pInfo.getRevocationDate()); assertNull(pInfo.getRevocationDate());
Date revocationDate = DateUtil.now(); Date revocationDate = DateUtil.now();
PGPSecretKeyRing revoked = PGPainless.modifyKeyRing(secretKeys).revoke( OpenPGPKey revoked = api.modify(secretKeys).revoke(
new UnprotectedKeysProtector(), new UnprotectedKeysProtector(),
RevocationAttributes.createKeyRevocation() RevocationAttributes.createKeyRevocation()
.withReason(RevocationAttributes.Reason.KEY_RETIRED) .withReason(RevocationAttributes.Reason.KEY_RETIRED)
.withoutDescription() .withoutDescription()
).done(); ).done();
KeyRingInfo rInfo = PGPainless.inspectKeyRing(revoked); KeyRingInfo rInfo = api.inspect(revoked);
assertNotNull(rInfo.getRevocationDate()); assertNotNull(rInfo.getRevocationDate());
assertEquals(revocationDate.getTime(), rInfo.getRevocationDate().getTime(), 5); assertEquals(revocationDate.getTime(), rInfo.getRevocationDate().getTime(), 5);
assertEquals(revocationDate.getTime(), rInfo.getLastModified().getTime(), 5); assertEquals(revocationDate.getTime(), rInfo.getLastModified().getTime(), 5);
@ -125,32 +123,34 @@ public class KeyRingInfoTest {
@Test @Test
public void testIsFullyDecrypted() throws IOException, PGPException { public void testIsFullyDecrypted() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); PGPainless api = PGPainless.getInstance();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); OpenPGPKey secretKeys = TestKeys.getEmilKey();
KeyRingInfo info = api.inspect(secretKeys);
assertTrue(info.isFullyDecrypted()); assertTrue(info.isFullyDecrypted());
secretKeys = encryptSecretKeys(secretKeys); secretKeys = encryptSecretKeys(secretKeys, api);
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(secretKeys);
assertFalse(info.isFullyDecrypted()); assertFalse(info.isFullyDecrypted());
} }
@Test @Test
public void testIsFullyEncrypted() throws IOException, PGPException { public void testIsFullyEncrypted() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); PGPainless api = PGPainless.getInstance();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); OpenPGPKey secretKeys = TestKeys.getEmilKey();
KeyRingInfo info = api.inspect(secretKeys);
assertFalse(info.isFullyEncrypted()); assertFalse(info.isFullyEncrypted());
secretKeys = encryptSecretKeys(secretKeys); secretKeys = encryptSecretKeys(secretKeys, api);
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(secretKeys);
assertTrue(info.isFullyEncrypted()); assertTrue(info.isFullyEncrypted());
} }
private static PGPSecretKeyRing encryptSecretKeys(PGPSecretKeyRing secretKeys) throws PGPException { private static OpenPGPKey encryptSecretKeys(OpenPGPKey secretKeys, PGPainless api) throws PGPException {
return PGPainless.modifyKeyRing(secretKeys) return api.modify(secretKeys)
.changePassphraseFromOldPassphrase(Passphrase.emptyPassphrase()) .changePassphraseFromOldPassphrase(Passphrase.emptyPassphrase())
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("sw0rdf1sh")) .toNewPassphrase(Passphrase.fromPassword("sw0rdf1sh"))
@ -160,27 +160,29 @@ public class KeyRingInfoTest {
@Test @Test
public void testGetSecretKey() throws IOException, PGPException { public void testGetSecretKey() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPainless api = PGPainless.getInstance();
PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys); OpenPGPKey secretKeys = TestKeys.getCryptieKey();
OpenPGPCertificate publicKeys = secretKeys.toCertificate();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
OpenPGPKey.OpenPGPSecretKey primarySecretKey = info.getSecretKey(); OpenPGPKey.OpenPGPSecretKey primarySecretKey = info.getSecretKey();
assertNotNull(primarySecretKey); assertNotNull(primarySecretKey);
assertEquals(KeyRingUtils.requirePrimarySecretKeyFrom(secretKeys), primarySecretKey.getPGPSecretKey()); assertEquals(secretKeys.getPrimarySecretKey().getPGPSecretKey(), primarySecretKey.getPGPSecretKey());
info = PGPainless.inspectKeyRing(publicKeys); info = api.inspect(publicKeys);
assertNull(info.getSecretKey()); assertNull(info.getSecretKey());
} }
@Test @Test
public void testGetPublicKey() throws IOException, PGPException { public void testGetPublicKey() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertEquals(KeyRingUtils.requirePrimaryPublicKeyFrom(secretKeys), info.getPrimaryKey().getPGPPublicKey()); assertEquals(secretKeys.getPrimaryKey().getPGPPublicKey(), info.getPrimaryKey().getPGPPublicKey());
assertEquals(KeyRingUtils.requirePrimarySecretKeyFrom(secretKeys), assertEquals(secretKeys.getPrimarySecretKey().getPGPSecretKey(),
KeyRingUtils.requireSecretKeyFrom(secretKeys, secretKeys.getPublicKey().getKeyID())); secretKeys.getPGPSecretKeyRing().getSecretKey(secretKeys.getKeyIdentifier()));
} }
@TestTemplate @TestTemplate
@ -224,8 +226,8 @@ public class KeyRingInfoTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void testGetKeysWithFlagsAndExpiry() { public void testGetKeysWithFlagsAndExpiry() {
PGPainless api = PGPainless.getInstance();
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing() OpenPGPKey secretKeys = PGPainless.buildKeyRing()
.setPrimaryKey(KeySpec.getBuilder( .setPrimaryKey(KeySpec.getBuilder(
KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER)) KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER))
.addSubkey(KeySpec.getBuilder( .addSubkey(KeySpec.getBuilder(
@ -234,10 +236,9 @@ public class KeyRingInfoTest {
.addSubkey(KeySpec.getBuilder( .addSubkey(KeySpec.getBuilder(
KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), KeyFlag.SIGN_DATA)) KeyType.ECDSA(EllipticCurve._BRAINPOOLP384R1), KeyFlag.SIGN_DATA))
.addUserId(UserId.builder().withName("Alice").withEmail("alice@pgpainless.org").build()) .addUserId(UserId.builder().withName("Alice").withEmail("alice@pgpainless.org").build())
.build() .build();
.getPGPSecretKeyRing();
Iterator<PGPSecretKey> keys = secretKeys.iterator(); Iterator<PGPSecretKey> keys = secretKeys.getPGPSecretKeyRing().iterator();
Date now = DateUtil.now(); Date now = DateUtil.now();
Calendar calendar = Calendar.getInstance(); Calendar calendar = Calendar.getInstance();
@ -255,11 +256,11 @@ public class KeyRingInfoTest {
PGPSecretKey signingKey = keys.next(); PGPSecretKey signingKey = keys.next();
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.setExpirationDate(primaryKeyExpiration, protector) .setExpirationDate(primaryKeyExpiration, protector)
.done(); .done();
KeyRingInfo info = new KeyRingInfo(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
List<OpenPGPCertificate.OpenPGPComponentKey> encryptionKeys = info.getKeysWithKeyFlag(KeyFlag.ENCRYPT_STORAGE); List<OpenPGPCertificate.OpenPGPComponentKey> encryptionKeys = info.getKeysWithKeyFlag(KeyFlag.ENCRYPT_STORAGE);
assertEquals(1, encryptionKeys.size()); assertEquals(1, encryptionKeys.size());
@ -354,9 +355,10 @@ public class KeyRingInfoTest {
"crH02GDG8CotAnEHkLTz9GPO80q8mowzBV0EtHsXb4TeAFw5T5Qd0a5I+wk=\n" + "crH02GDG8CotAnEHkLTz9GPO80q8mowzBV0EtHsXb4TeAFw5T5Qd0a5I+wk=\n" +
"=Vcb3\n" + "=Vcb3\n" +
"-----END PGP ARMORED FILE-----\n"; "-----END PGP ARMORED FILE-----\n";
OpenPGPCertificate certificate = PGPainless.getInstance().readKey().parseCertificate(KEY); PGPainless api = PGPainless.getInstance();
OpenPGPCertificate certificate = api.readKey().parseCertificate(KEY);
KeyRingInfo info = PGPainless.inspectKeyRing(certificate, DateUtil.parseUTCDate("2021-10-10 00:00:00 UTC")); KeyRingInfo info = api.inspect(certificate, DateUtil.parseUTCDate("2021-10-10 00:00:00 UTC"));
// Subkey is hard revoked // Subkey is hard revoked
assertFalse(info.isKeyValidlyBound(new KeyIdentifier(5364407983539305061L))); assertFalse(info.isKeyValidlyBound(new KeyIdentifier(5364407983539305061L)));
} }
@ -434,14 +436,15 @@ public class KeyRingInfoTest {
"=7Feh\n" + "=7Feh\n" +
"-----END PGP ARMORED FILE-----\n"; "-----END PGP ARMORED FILE-----\n";
OpenPGPCertificate certificate = PGPainless.getInstance().readKey().parseCertificate(KEY); PGPainless api = PGPainless.getInstance();
OpenPGPCertificate certificate = api.readKey().parseCertificate(KEY);
final KeyIdentifier subkeyId = new KeyIdentifier(5364407983539305061L); final KeyIdentifier subkeyId = new KeyIdentifier(5364407983539305061L);
KeyRingInfo inspectDuringRevokedPeriod = PGPainless.inspectKeyRing(certificate, DateUtil.parseUTCDate("2019-01-02 00:00:00 UTC")); KeyRingInfo inspectDuringRevokedPeriod = api.inspect(certificate, DateUtil.parseUTCDate("2019-01-02 00:00:00 UTC"));
assertFalse(inspectDuringRevokedPeriod.isKeyValidlyBound(subkeyId)); assertFalse(inspectDuringRevokedPeriod.isKeyValidlyBound(subkeyId));
assertNotNull(inspectDuringRevokedPeriod.getSubkeyRevocationSignature(subkeyId)); assertNotNull(inspectDuringRevokedPeriod.getSubkeyRevocationSignature(subkeyId));
KeyRingInfo inspectAfterRebinding = PGPainless.inspectKeyRing(certificate, DateUtil.parseUTCDate("2020-01-02 00:00:00 UTC")); KeyRingInfo inspectAfterRebinding = api.inspect(certificate, DateUtil.parseUTCDate("2020-01-02 00:00:00 UTC"));
assertTrue(inspectAfterRebinding.isKeyValidlyBound(subkeyId)); assertTrue(inspectAfterRebinding.isKeyValidlyBound(subkeyId));
} }
@ -518,9 +521,10 @@ public class KeyRingInfoTest {
"=MhJL\n" + "=MhJL\n" +
"-----END PGP ARMORED FILE-----\n"; "-----END PGP ARMORED FILE-----\n";
OpenPGPCertificate keys = PGPainless.getInstance().readKey().parseCertificate(KEY); PGPainless api = PGPainless.getInstance();
OpenPGPCertificate keys = api.readKey().parseCertificate(KEY);
KeyRingInfo info = PGPainless.inspectKeyRing(keys); KeyRingInfo info = api.inspect(keys);
// Primary key is hard revoked // Primary key is hard revoked
assertFalse(info.isKeyValidlyBound(keys.getKeyIdentifier())); assertFalse(info.isKeyValidlyBound(keys.getKeyIdentifier()));
assertFalse(info.isFullyEncrypted()); assertFalse(info.isFullyEncrypted());
@ -528,49 +532,48 @@ public class KeyRingInfoTest {
@Test @Test
public void getSecretKeyTest() { public void getSecretKeyTest() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
OpenPGPKey key = new OpenPGPKey(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys);
OpenPgpV4Fingerprint primaryKeyFingerprint = new OpenPgpV4Fingerprint(secretKeys); OpenPgpV4Fingerprint primaryKeyFingerprint = new OpenPgpV4Fingerprint(secretKeys);
OpenPGPKey.OpenPGPSecretKey primaryKey = info.getSecretKey(primaryKeyFingerprint); OpenPGPKey.OpenPGPSecretKey primaryKey = info.getSecretKey(primaryKeyFingerprint);
assertNotNull(primaryKey); assertNotNull(primaryKey);
assertEquals(key.getPrimarySecretKey().getKeyIdentifier(), primaryKey.getKeyIdentifier()); assertEquals(secretKeys.getPrimarySecretKey().getKeyIdentifier(), primaryKey.getKeyIdentifier());
} }
@Test @Test
public void testGetLatestKeyCreationDate() throws PGPException, IOException { public void testGetLatestKeyCreationDate() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getEmilKey();
Date latestCreationDate = DateUtil.parseUTCDate("2020-01-12 18:01:44 UTC"); Date latestCreationDate = DateUtil.parseUTCDate("2020-01-12 18:01:44 UTC");
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = PGPainless.getInstance().inspect(secretKeys);
JUtils.assertDateEquals(latestCreationDate, info.getLatestKeyCreationDate()); JUtils.assertDateEquals(latestCreationDate, info.getLatestKeyCreationDate());
} }
@Test @Test
public void testGetExpirationDateForUse_SPLIT() throws PGPException, IOException { public void testGetExpirationDateForUse_SPLIT() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getEmilKey();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = PGPainless.getInstance().inspect(secretKeys);
assertThrows(IllegalArgumentException.class, () -> info.getExpirationDateForUse(KeyFlag.SPLIT)); assertThrows(IllegalArgumentException.class, () -> info.getExpirationDateForUse(KeyFlag.SPLIT));
} }
@Test @Test
public void testGetExpirationDateForUse_SHARED() throws PGPException, IOException { public void testGetExpirationDateForUse_SHARED() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getEmilKey();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = PGPainless.getInstance().inspect(secretKeys);
assertThrows(IllegalArgumentException.class, () -> info.getExpirationDateForUse(KeyFlag.SHARED)); assertThrows(IllegalArgumentException.class, () -> info.getExpirationDateForUse(KeyFlag.SHARED));
} }
@Test @Test
public void testGetExpirationDateForUse_NoSuchKey() { public void testGetExpirationDateForUse_NoSuchKey() {
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing() PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
.addUserId("Alice") .addUserId("Alice")
.setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER)) .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER))
.build() .build();
.getPGPSecretKeyRing();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertThrows(NoSuchElementException.class, () -> info.getExpirationDateForUse(KeyFlag.ENCRYPT_COMMS)); assertThrows(NoSuchElementException.class, () -> info.getExpirationDateForUse(KeyFlag.ENCRYPT_COMMS));
} }
@ -600,8 +603,8 @@ public class KeyRingInfoTest {
"/+XL+qMMgLHaQ25aA11GVAkC\n" + "/+XL+qMMgLHaQ25aA11GVAkC\n" +
"=7gbt\n" + "=7gbt\n" +
"-----END PGP PRIVATE KEY BLOCK-----"; "-----END PGP PRIVATE KEY BLOCK-----";
PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = PGPainless.getInstance().readKey().parseKey(KEY); OpenPGPKey secretKeys = api.readKey().parseKey(KEY);
final KeyIdentifier pkid = new KeyIdentifier(6643807985200014832L); final KeyIdentifier pkid = new KeyIdentifier(6643807985200014832L);
final KeyIdentifier skid1 = new KeyIdentifier(-2328413746552029063L); final KeyIdentifier skid1 = new KeyIdentifier(-2328413746552029063L);
final KeyIdentifier skid2 = new KeyIdentifier(-3276877650571760552L); final KeyIdentifier skid2 = new KeyIdentifier(-3276877650571760552L);
@ -611,7 +614,7 @@ public class KeyRingInfoTest {
Arrays.asList(CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZIP2, CompressionAlgorithm.ZIP, CompressionAlgorithm.UNCOMPRESSED)); Arrays.asList(CompressionAlgorithm.ZLIB, CompressionAlgorithm.BZIP2, CompressionAlgorithm.ZIP, CompressionAlgorithm.UNCOMPRESSED));
Set<SymmetricKeyAlgorithm> preferredSymmetricAlgorithms = new LinkedHashSet<>( Set<SymmetricKeyAlgorithm> preferredSymmetricAlgorithms = new LinkedHashSet<>(
Arrays.asList(SymmetricKeyAlgorithm.AES_256, SymmetricKeyAlgorithm.AES_192, SymmetricKeyAlgorithm.AES_128)); Arrays.asList(SymmetricKeyAlgorithm.AES_256, SymmetricKeyAlgorithm.AES_192, SymmetricKeyAlgorithm.AES_128));
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
// Bob is an invalid userId // Bob is an invalid userId
assertThrows(NoSuchElementException.class, () -> info.getPreferredSymmetricKeyAlgorithms("Bob")); assertThrows(NoSuchElementException.class, () -> info.getPreferredSymmetricKeyAlgorithms("Bob"));
@ -694,10 +697,10 @@ public class KeyRingInfoTest {
"C9h35EjDuD+1COXUOoW2B8LX6m2yf8cY72K70QgtGemj7UWhXL5u/wARAQAB\n" + "C9h35EjDuD+1COXUOoW2B8LX6m2yf8cY72K70QgtGemj7UWhXL5u/wARAQAB\n" +
"=A3B8\n" + "=A3B8\n" +
"-----END PGP PUBLIC KEY BLOCK-----\n"; "-----END PGP PUBLIC KEY BLOCK-----\n";
PGPainless api = PGPainless.getInstance();
OpenPGPCertificate certificate = PGPainless.getInstance().readKey().parseCertificate(KEY); OpenPGPCertificate certificate = api.readKey().parseCertificate(KEY);
OpenPgpV4Fingerprint unboundKey = new OpenPgpV4Fingerprint("D622C916384E0F6D364907E55D918BBD521CCD10"); OpenPgpV4Fingerprint unboundKey = new OpenPgpV4Fingerprint("D622C916384E0F6D364907E55D918BBD521CCD10");
KeyRingInfo info = PGPainless.inspectKeyRing(certificate); KeyRingInfo info = api.inspect(certificate);
assertFalse(info.isKeyValidlyBound(unboundKey.getKeyIdentifier())); assertFalse(info.isKeyValidlyBound(unboundKey.getKeyIdentifier()));
@ -773,9 +776,9 @@ public class KeyRingInfoTest {
"qDzPRwEAhdVBeryRUcwjgwHX0xmMFK7vLkdonn8BR2++nXBO2g8=\n" + "qDzPRwEAhdVBeryRUcwjgwHX0xmMFK7vLkdonn8BR2++nXBO2g8=\n" +
"=ZRAy\n" + "=ZRAy\n" +
"-----END PGP PRIVATE KEY BLOCK-----\n"; "-----END PGP PRIVATE KEY BLOCK-----\n";
PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = PGPainless.getInstance().readKey().parseKey(KEY); OpenPGPKey secretKeys = api.readKey().parseKey(KEY);
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
List<String> emails = info.getEmailAddresses(); List<String> emails = info.getEmailAddresses();
assertEquals(emails, Arrays.asList("alice@email.tld", "alice@pgpainless.org", "alice@openpgp.org", "alice@rfc4880.spec")); assertEquals(emails, Arrays.asList("alice@email.tld", "alice@pgpainless.org", "alice@openpgp.org", "alice@rfc4880.spec"));
@ -805,9 +808,9 @@ public class KeyRingInfoTest {
"J5wP\n" + "J5wP\n" +
"=nFoO\n" + "=nFoO\n" +
"-----END PGP PUBLIC KEY BLOCK-----"; "-----END PGP PUBLIC KEY BLOCK-----";
PGPainless api = PGPainless.getInstance();
OpenPGPCertificate cert = PGPainless.getInstance().readKey().parseCertificate(CERT); OpenPGPCertificate cert = api.readKey().parseCertificate(CERT);
KeyRingInfo info = PGPainless.inspectKeyRing(cert); KeyRingInfo info = api.inspect(cert);
assertTrue(info.isUsableForEncryption()); assertTrue(info.isUsableForEncryption());
} }
@ -833,9 +836,9 @@ public class KeyRingInfoTest {
"2XO/hpB2T8VXFfFKwj7U9LGkX+ciLg==\n" + "2XO/hpB2T8VXFfFKwj7U9LGkX+ciLg==\n" +
"=etPP\n" + "=etPP\n" +
"-----END PGP PUBLIC KEY BLOCK-----"; "-----END PGP PUBLIC KEY BLOCK-----";
PGPainless api = PGPainless.getInstance();
OpenPGPCertificate publicKeys = PGPainless.getInstance().readKey().parseCertificate(CERT); OpenPGPCertificate publicKeys = api.readKey().parseCertificate(CERT);
KeyRingInfo info = PGPainless.inspectKeyRing(publicKeys); KeyRingInfo info = api.inspect(publicKeys);
assertTrue(info.isUsableForEncryption(EncryptionPurpose.COMMUNICATIONS)); assertTrue(info.isUsableForEncryption(EncryptionPurpose.COMMUNICATIONS));
assertTrue(info.isUsableForEncryption(EncryptionPurpose.ANY)); assertTrue(info.isUsableForEncryption(EncryptionPurpose.ANY));
@ -870,8 +873,9 @@ public class KeyRingInfoTest {
"AQCjeV+3VT+u1movwIYv4XkzB6gB+B2C+DK9nvG5sXZhBg==\n" + "AQCjeV+3VT+u1movwIYv4XkzB6gB+B2C+DK9nvG5sXZhBg==\n" +
"=uqmO\n" + "=uqmO\n" +
"-----END PGP PUBLIC KEY BLOCK-----"; "-----END PGP PUBLIC KEY BLOCK-----";
OpenPGPCertificate publicKeys = PGPainless.getInstance().readKey().parseCertificate(CERT); PGPainless api = PGPainless.getInstance();
KeyRingInfo info = PGPainless.inspectKeyRing(publicKeys); OpenPGPCertificate publicKeys = api.readKey().parseCertificate(CERT);
KeyRingInfo info = api.inspect(publicKeys);
assertFalse(info.isUsableForEncryption()); assertFalse(info.isUsableForEncryption());
assertFalse(info.isUsableForEncryption(EncryptionPurpose.ANY)); assertFalse(info.isUsableForEncryption(EncryptionPurpose.ANY));

View file

@ -7,7 +7,7 @@ package org.pgpainless.key.info;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
@ -16,13 +16,13 @@ public class PrimaryUserIdTest {
@Test @Test
public void testGetPrimaryUserId() throws PGPException { public void testGetPrimaryUserId() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("alice@wonderland.lit") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("alice@wonderland.lit");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId("mad_alice@wonderland.lit", SecretKeyRingProtector.unprotectedKeys()) .addUserId("mad_alice@wonderland.lit", SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertEquals("alice@wonderland.lit", info.getPrimaryUserId()); assertEquals("alice@wonderland.lit", info.getPrimaryUserId());
} }
} }

View file

@ -15,11 +15,12 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.bcpg.SignatureSubpacketTags; import org.bouncycastle.bcpg.SignatureSubpacketTags;
import org.bouncycastle.bcpg.sig.RevocationReason; import org.bouncycastle.bcpg.sig.RevocationReason;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.KeyFlag; import org.pgpainless.algorithm.KeyFlag;
@ -37,7 +38,8 @@ public class UserIdRevocationTest {
@Test @Test
public void testRevocationWithoutRevocationAttributes() throws PGPException { public void testRevocationWithoutRevocationAttributes() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing() PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
.setPrimaryKey(KeySpec.getBuilder( .setPrimaryKey(KeySpec.getBuilder(
KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519),
KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER)) KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER))
@ -45,28 +47,27 @@ public class UserIdRevocationTest {
KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS)) KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS))
.addUserId("primary@key.id") .addUserId("primary@key.id")
.addUserId("secondary@key.id") .addUserId("secondary@key.id")
.build() .build();
.getPGPSecretKeyRing();
// make a copy with revoked subkey // make a copy with revoked subkey
PGPSecretKeyRing revoked = PGPainless.modifyKeyRing(secretKeys) OpenPGPKey revoked = api.modify(secretKeys)
.revokeUserId("secondary@key.id", new UnprotectedKeysProtector()) .revokeUserId("secondary@key.id", new UnprotectedKeysProtector())
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(revoked); KeyRingInfo info = api.inspect(revoked);
List<String> userIds = info.getUserIds(); List<String> userIds = info.getUserIds();
assertEquals(Arrays.asList("primary@key.id", "secondary@key.id"), userIds); assertEquals(Arrays.asList("primary@key.id", "secondary@key.id"), userIds);
assertTrue(info.isUserIdValid("primary@key.id")); assertTrue(info.isUserIdValid("primary@key.id"));
assertFalse(info.isUserIdValid("sedondary@key.id")); assertFalse(info.isUserIdValid("sedondary@key.id"));
assertFalse(info.isUserIdValid("tertiary@key.id")); assertFalse(info.isUserIdValid("tertiary@key.id"));
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(secretKeys);
assertTrue(info.isUserIdValid("secondary@key.id")); // key on original secret key ring is still valid assertTrue(info.isUserIdValid("secondary@key.id")); // key on original secret key ring is still valid
revoked = PGPainless.modifyKeyRing(secretKeys) revoked = api.modify(secretKeys)
.revokeUserId("secondary@key.id", new UnprotectedKeysProtector()) .revokeUserId("secondary@key.id", new UnprotectedKeysProtector())
.done(); .done();
info = PGPainless.inspectKeyRing(revoked); info = api.inspect(revoked);
userIds = info.getUserIds(); userIds = info.getUserIds();
assertEquals(Arrays.asList("primary@key.id", "secondary@key.id"), userIds); assertEquals(Arrays.asList("primary@key.id", "secondary@key.id"), userIds);
assertTrue(info.isUserIdValid("primary@key.id")); assertTrue(info.isUserIdValid("primary@key.id"));
@ -76,23 +77,23 @@ public class UserIdRevocationTest {
@Test @Test
public void testRevocationWithRevocationReason() { public void testRevocationWithRevocationReason() {
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing() PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
.setPrimaryKey(KeySpec.getBuilder( .setPrimaryKey(KeySpec.getBuilder(
KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519),
KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER)) KeyFlag.SIGN_DATA, KeyFlag.CERTIFY_OTHER))
.addSubkey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS)) .addSubkey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS))
.addUserId("primary@key.id") .addUserId("primary@key.id")
.addUserId("secondary@key.id") .addUserId("secondary@key.id")
.build() .build();
.getPGPSecretKeyRing();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.revokeUserId("secondary@key.id", new UnprotectedKeysProtector(), .revokeUserId("secondary@key.id", new UnprotectedKeysProtector(),
RevocationAttributes.createCertificateRevocation() RevocationAttributes.createCertificateRevocation()
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID) .withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
.withDescription("I lost my mail password")) .withDescription("I lost my mail password"))
.done(); .done();
KeyRingInfo info = new KeyRingInfo(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
PGPSignature signature = info.getUserIdRevocation("secondary@key.id"); PGPSignature signature = info.getUserIdRevocation("secondary@key.id");
assertNotNull(signature); assertNotNull(signature);
@ -104,31 +105,31 @@ public class UserIdRevocationTest {
@Test @Test
public void unknownKeyThrowsIllegalArgumentException() throws IOException, PGPException { public void unknownKeyThrowsIllegalArgumentException() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getCryptieKey();
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); .forKey(secretKeys, TestKeys.CRYPTIE_PASSPHRASE);
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) assertThrows(NoSuchElementException.class, () -> PGPainless.getInstance().modify(secretKeys)
.revokeSubKey(1L, protector)); .revokeSubKey(new KeyIdentifier(1L), protector));
} }
@Test @Test
public void unknownUserIdThrowsNoSuchElementException() throws IOException, PGPException { public void unknownUserIdThrowsNoSuchElementException() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getCryptieKey();
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); .forKey(secretKeys, TestKeys.CRYPTIE_PASSPHRASE);
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) assertThrows(NoSuchElementException.class, () -> PGPainless.getInstance().modify(secretKeys)
.revokeUserId("invalid@user.id", protector)); .revokeUserId("invalid@user.id", protector));
} }
@Test @Test
public void invalidRevocationReasonThrowsIllegalArgumentException() throws IOException, PGPException { public void invalidRevocationReasonThrowsIllegalArgumentException() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getCryptieKey();
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
.forKey(secretKeys.getSecretKey(), TestKeys.CRYPTIE_PASSPHRASE); .forKey(secretKeys, TestKeys.CRYPTIE_PASSPHRASE);
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) assertThrows(IllegalArgumentException.class, () -> PGPainless.getInstance().modify(secretKeys)
.revokeUserId("cryptie@encrypted.key", protector, .revokeUserId("cryptie@encrypted.key", protector,
RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED) RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED)
.withDescription("This is not a valid certification revocation reason."))); .withDescription("This is not a valid certification revocation reason.")));

View file

@ -16,8 +16,7 @@ import java.util.List;
import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -39,14 +38,15 @@ public class AddSubKeyTest {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void testAddSubKey() public void testAddSubKey()
throws IOException, PGPException { throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
List<KeyIdentifier> keyIdentifiersBefore = new ArrayList<>(); List<KeyIdentifier> keyIdentifiersBefore = new ArrayList<>();
for (Iterator<PGPPublicKey> it = secretKeys.getPublicKeys(); it.hasNext(); ) { for (Iterator<PGPPublicKey> it = secretKeys.getPGPSecretKeyRing().getPublicKeys(); it.hasNext(); ) {
keyIdentifiersBefore.add(it.next().getKeyIdentifier()); keyIdentifiersBefore.add(it.next().getKeyIdentifier());
} }
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addSubKey( .addSubKey(
KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256), KeyFlag.SIGN_DATA).build(), KeySpec.getBuilder(ECDSA.fromCurve(EllipticCurve._P256), KeyFlag.SIGN_DATA).build(),
Passphrase.fromPassword("subKeyPassphrase"), Passphrase.fromPassword("subKeyPassphrase"),
@ -54,7 +54,7 @@ public class AddSubKeyTest {
.done(); .done();
List<KeyIdentifier> keyIdentifiersAfter = new ArrayList<>(); List<KeyIdentifier> keyIdentifiersAfter = new ArrayList<>();
for (Iterator<PGPPublicKey> it = secretKeys.getPublicKeys(); it.hasNext(); ) { for (Iterator<PGPPublicKey> it = secretKeys.getPGPSecretKeyRing().getPublicKeys(); it.hasNext(); ) {
keyIdentifiersAfter.add(it.next().getKeyIdentifier()); keyIdentifiersAfter.add(it.next().getKeyIdentifier());
} }
assertNotEquals(keyIdentifiersAfter, keyIdentifiersBefore); assertNotEquals(keyIdentifiersAfter, keyIdentifiersBefore);
@ -62,12 +62,12 @@ public class AddSubKeyTest {
keyIdentifiersAfter.removeAll(keyIdentifiersBefore); keyIdentifiersAfter.removeAll(keyIdentifiersBefore);
KeyIdentifier subKeyIdentifier = keyIdentifiersAfter.get(0); KeyIdentifier subKeyIdentifier = keyIdentifiersAfter.get(0);
PGPSecretKey subKey = secretKeys.getSecretKey(subKeyIdentifier); OpenPGPKey.OpenPGPSecretKey subKey = secretKeys.getSecretKey(subKeyIdentifier);
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockEachKeyWith( SecretKeyRingProtector protector = SecretKeyRingProtector.unlockEachKeyWith(
Passphrase.fromPassword("subKeyPassphrase"), secretKeys); Passphrase.fromPassword("subKeyPassphrase"), secretKeys);
UnlockSecretKey.unlockSecretKey(subKey, protector); UnlockSecretKey.unlockSecretKey(subKey, protector);
KeyRingInfo info = new KeyRingInfo(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertEquals(Collections.singletonList(KeyFlag.SIGN_DATA), info.getKeyFlagsOf(subKeyIdentifier)); assertEquals(Collections.singletonList(KeyFlag.SIGN_DATA), info.getKeyFlagsOf(subKeyIdentifier));
} }
} }

View file

@ -14,9 +14,9 @@ import java.util.List;
import org.bouncycastle.bcpg.sig.NotationData; import org.bouncycastle.bcpg.sig.NotationData;
import org.bouncycastle.openpgp.PGPKeyPair; import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.JUtils; import org.junit.JUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -38,11 +38,11 @@ public class AddSubkeyWithModifiedBindingSignatureSubpacketsTest {
@Test @Test
public void bindEncryptionSubkeyAndModifyBindingSignatureHashedSubpackets() { public void bindEncryptionSubkeyAndModifyBindingSignatureHashedSubpackets() {
PGPainless api = PGPainless.getInstance();
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() OpenPGPKey secretKeys = api.generateKey()
.modernKeyRing("Alice <alice@pgpainless.org>") .modernKeyRing("Alice <alice@pgpainless.org>");
.getPGPSecretKeyRing(); KeyRingInfo before = api.inspect(secretKeys);
KeyRingInfo before = PGPainless.inspectKeyRing(secretKeys);
List<OpenPGPCertificate.OpenPGPComponentKey> signingKeysBefore = before.getSigningSubkeys(); List<OpenPGPCertificate.OpenPGPComponentKey> signingKeysBefore = before.getSigningSubkeys();
PGPKeyPair secretSubkey = KeyRingBuilder.generateKeyPair( PGPKeyPair secretSubkey = KeyRingBuilder.generateKeyPair(
@ -50,7 +50,7 @@ public class AddSubkeyWithModifiedBindingSignatureSubpacketsTest {
OpenPGPKeyVersion.v4); OpenPGPKeyVersion.v4);
long secondsUntilExpiration = 1000; long secondsUntilExpiration = 1000;
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addSubKey(secretSubkey, new SelfSignatureSubpackets.Callback() { .addSubKey(secretSubkey, new SelfSignatureSubpackets.Callback() {
@Override @Override
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) { public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
@ -60,7 +60,7 @@ public class AddSubkeyWithModifiedBindingSignatureSubpacketsTest {
}, SecretKeyRingProtector.unprotectedKeys(), protector, KeyFlag.SIGN_DATA) }, SecretKeyRingProtector.unprotectedKeys(), protector, KeyFlag.SIGN_DATA)
.done(); .done();
KeyRingInfo after = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo after = api.inspect(secretKeys);
List<OpenPGPCertificate.OpenPGPComponentKey> signingKeysAfter = after.getSigningSubkeys(); List<OpenPGPCertificate.OpenPGPComponentKey> signingKeysAfter = after.getSigningSubkeys();
signingKeysAfter.removeAll(signingKeysBefore); signingKeysAfter.removeAll(signingKeysBefore);
assertFalse(signingKeysAfter.isEmpty()); assertFalse(signingKeysAfter.isEmpty());

View file

@ -37,31 +37,31 @@ public class AddUserIdTest {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void addUserIdToExistingKeyRing() public void addUserIdToExistingKeyRing()
throws PGPException { throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.simpleEcKeyRing("alice@wonderland.lit", "rabb1th0le") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .simpleEcKeyRing("alice@wonderland.lit", "rabb1th0le");
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
Iterator<String> userIds = info.getValidUserIds().iterator(); Iterator<String> userIds = info.getValidUserIds().iterator();
assertEquals("alice@wonderland.lit", userIds.next()); assertEquals("alice@wonderland.lit", userIds.next());
assertFalse(userIds.hasNext()); assertFalse(userIds.hasNext());
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector.forKey(secretKeys, Passphrase.fromPassword("rabb1th0le")); SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector.forKey(secretKeys, Passphrase.fromPassword("rabb1th0le"));
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId("cheshirecat@wonderland.lit", protector) .addUserId("cheshirecat@wonderland.lit", protector)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(secretKeys);
userIds = info.getValidUserIds().iterator(); userIds = info.getValidUserIds().iterator();
assertEquals("alice@wonderland.lit", userIds.next()); assertEquals("alice@wonderland.lit", userIds.next());
assertEquals("cheshirecat@wonderland.lit", userIds.next()); assertEquals("cheshirecat@wonderland.lit", userIds.next());
assertFalse(userIds.hasNext()); assertFalse(userIds.hasNext());
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.revokeUserId("cheshirecat@wonderland.lit", protector) .revokeUserId("cheshirecat@wonderland.lit", protector)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(secretKeys);
userIds = info.getValidUserIds().iterator(); userIds = info.getValidUserIds().iterator();
assertEquals("alice@wonderland.lit", userIds.next()); assertEquals("alice@wonderland.lit", userIds.next());
assertFalse(userIds.hasNext()); assertFalse(userIds.hasNext());
@ -96,20 +96,21 @@ public class AddUserIdTest {
"=bk4o\r\n" + "=bk4o\r\n" +
"-----END PGP PRIVATE KEY BLOCK-----\r\n"; "-----END PGP PRIVATE KEY BLOCK-----\r\n";
OpenPGPKey key = PGPainless.getInstance().readKey().parseKey(ARMORED_PRIVATE_KEY); PGPainless api = PGPainless.getInstance();
PGPSecretKeyRing secretKeys = key.getPGPSecretKeyRing();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); OpenPGPKey key = api.readKey().parseKey(ARMORED_PRIVATE_KEY);
KeyRingInfo info = api.inspect(key);
Iterator<String> userIds = info.getValidUserIds().iterator(); Iterator<String> userIds = info.getValidUserIds().iterator();
assertEquals("<user@example.com>", userIds.next()); assertEquals("<user@example.com>", userIds.next());
assertFalse(userIds.hasNext()); assertFalse(userIds.hasNext());
SecretKeyRingProtector protector = new UnprotectedKeysProtector(); SecretKeyRingProtector protector = new UnprotectedKeysProtector();
secretKeys = PGPainless.modifyKeyRing(secretKeys) key = api.modify(key)
.revokeUserId("<user@example.com>", protector) .revokeUserId("<user@example.com>", protector)
.addUserId("cheshirecat@wonderland.lit", protector) .addUserId("cheshirecat@wonderland.lit", protector)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys); info = api.inspect(key);
userIds = info.getValidUserIds().iterator(); userIds = info.getValidUserIds().iterator();
assertEquals("cheshirecat@wonderland.lit", userIds.next()); assertEquals("cheshirecat@wonderland.lit", userIds.next());
assertFalse(userIds.hasNext()); assertFalse(userIds.hasNext());
@ -118,17 +119,17 @@ public class AddUserIdTest {
@Test @Test
public void addNewPrimaryUserIdTest() { public void addNewPrimaryUserIdTest() {
Date now = new Date(); Date now = new Date();
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("Alice") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("Alice");
UserId bob = UserId.builder().withName("Bob").noEmail().noComment().build(); UserId bob = UserId.builder().withName("Bob").noEmail().noComment().build();
assertNotEquals("Bob", PGPainless.inspectKeyRing(secretKeys).getPrimaryUserId()); assertNotEquals("Bob", api.inspect(secretKeys).getPrimaryUserId());
secretKeys = PGPainless.modifyKeyRing(secretKeys, DateExtensionsKt.plusSeconds(now, 1)) secretKeys = api.modify(secretKeys, DateExtensionsKt.plusSeconds(now, 1))
.addPrimaryUserId(bob, SecretKeyRingProtector.unprotectedKeys()) .addPrimaryUserId(bob, SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
assertEquals("Bob", PGPainless.inspectKeyRing(secretKeys, DateExtensionsKt.plusSeconds(now, 2)).getPrimaryUserId()); assertEquals("Bob", api.inspect(secretKeys, DateExtensionsKt.plusSeconds(now, 2)).getPrimaryUserId());
} }
} }

View file

@ -7,7 +7,7 @@ package org.pgpainless.key.modification;
import java.io.IOException; import java.io.IOException;
import java.util.Date; import java.util.Date;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.JUtils; import org.junit.JUtils;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -138,7 +138,8 @@ public class ChangeExpirationOnKeyWithDifferentSignatureTypesTest {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void setExpirationDate_keyHasSigClass10() public void setExpirationDate_keyHasSigClass10()
throws IOException { throws IOException {
PGPSecretKeyRing keys = PGPainless.readKeyRing().secretKeyRing(keyWithGenericCertification); PGPainless api = PGPainless.getInstance();
OpenPGPKey keys = api.readKey().parseKey(keyWithGenericCertification);
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
executeTestForKeys(keys, protector); executeTestForKeys(keys, protector);
} }
@ -147,20 +148,23 @@ public class ChangeExpirationOnKeyWithDifferentSignatureTypesTest {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void setExpirationDate_keyHasSigClass12() public void setExpirationDate_keyHasSigClass12()
throws IOException { throws IOException {
PGPSecretKeyRing keys = PGPainless.readKeyRing().secretKeyRing(keyWithCasualCertification); PGPainless api = PGPainless.getInstance();
OpenPGPKey keys = api.readKey().parseKey(keyWithCasualCertification);
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
executeTestForKeys(keys, protector); executeTestForKeys(keys, protector);
} }
private void executeTestForKeys(PGPSecretKeyRing keys, SecretKeyRingProtector protector) { private void executeTestForKeys(OpenPGPKey keys, SecretKeyRingProtector protector) {
PGPainless api = PGPainless.getInstance();
Date expirationDate = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 14); Date expirationDate = new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 24 * 14);
// round date for test stability // round date for test stability
expirationDate = DateUtil.toSecondsPrecision(expirationDate); expirationDate = DateUtil.toSecondsPrecision(expirationDate);
PGPSecretKeyRing modded = PGPainless.modifyKeyRing(keys) OpenPGPKey modded = api.modify(keys)
.setExpirationDate(expirationDate, protector) .setExpirationDate(expirationDate, protector)
.done(); .done();
JUtils.assertDateEquals(expirationDate, PGPainless.inspectKeyRing(modded).getPrimaryKeyExpirationDate()); JUtils.assertDateEquals(expirationDate, api.inspect(modded).getPrimaryKeyExpirationDate());
} }
} }

View file

@ -14,7 +14,7 @@ import java.util.Calendar;
import java.util.Date; import java.util.Date;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.JUtils; import org.junit.JUtils;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -35,27 +35,28 @@ public class ChangeExpirationTest {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void setExpirationDateAndThenUnsetIt_OnPrimaryKey() public void setExpirationDateAndThenUnsetIt_OnPrimaryKey()
throws PGPException, IOException { throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); PGPainless api = PGPainless.getInstance();
KeyRingInfo sInfo = PGPainless.inspectKeyRing(secretKeys); OpenPGPKey secretKeys = TestKeys.getEmilKey();
KeyRingInfo sInfo = api.inspect(secretKeys);
assertNull(sInfo.getPrimaryKeyExpirationDate()); assertNull(sInfo.getPrimaryKeyExpirationDate());
assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint)); assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint));
Date now = new Date(); Date now = new Date();
Date date = DateUtil.parseUTCDate("2020-11-27 16:10:32 UTC"); Date date = DateUtil.parseUTCDate("2020-11-27 16:10:32 UTC");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.setExpirationDate(date, new UnprotectedKeysProtector()).done(); .setExpirationDate(date, new UnprotectedKeysProtector()).done();
sInfo = PGPainless.inspectKeyRing(secretKeys); sInfo = api.inspect(secretKeys);
assertNotNull(sInfo.getPrimaryKeyExpirationDate()); assertNotNull(sInfo.getPrimaryKeyExpirationDate());
assertEquals(date.getTime(), sInfo.getPrimaryKeyExpirationDate().getTime()); assertEquals(date.getTime(), sInfo.getPrimaryKeyExpirationDate().getTime());
// subkey unchanged // subkey unchanged
assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint)); assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint));
Date t1 = new Date(now.getTime() + 1000 * 60 * 60); Date t1 = new Date(now.getTime() + 1000 * 60 * 60);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1) secretKeys = api.modify(secretKeys, t1)
.setExpirationDate(null, new UnprotectedKeysProtector()).done(); .setExpirationDate(null, new UnprotectedKeysProtector()).done();
sInfo = PGPainless.inspectKeyRing(secretKeys, t1); sInfo = api.inspect(secretKeys, t1);
assertNull(sInfo.getPrimaryKeyExpirationDate()); assertNull(sInfo.getPrimaryKeyExpirationDate());
assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint)); assertNull(sInfo.getSubkeyExpirationDate(subKeyFingerprint));
} }
@ -64,9 +65,9 @@ public class ChangeExpirationTest {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void setExpirationDateAndThenUnsetIt_OnSubkey() public void setExpirationDateAndThenUnsetIt_OnSubkey()
throws PGPException, IOException { throws PGPException, IOException {
PGPainless api = PGPainless.getInstance();
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getEmilKey();
KeyRingInfo sInfo = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo sInfo = api.inspect(secretKeys);
assertNull(sInfo.getPrimaryKeyExpirationDate()); assertNull(sInfo.getPrimaryKeyExpirationDate());
@ -76,42 +77,43 @@ public class ChangeExpirationTest {
calendar.add(Calendar.DATE, 5); calendar.add(Calendar.DATE, 5);
Date expiration = calendar.getTime(); // in 5 days Date expiration = calendar.getTime(); // in 5 days
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.setExpirationDate(expiration, new UnprotectedKeysProtector()).done(); .setExpirationDate(expiration, new UnprotectedKeysProtector()).done();
sInfo = PGPainless.inspectKeyRing(secretKeys); sInfo = api.inspect(secretKeys);
assertNotNull(sInfo.getPrimaryKeyExpirationDate()); assertNotNull(sInfo.getPrimaryKeyExpirationDate());
JUtils.assertDateEquals(expiration, sInfo.getPrimaryKeyExpirationDate()); JUtils.assertDateEquals(expiration, sInfo.getPrimaryKeyExpirationDate());
Date t1 = new Date(now.getTime() + 1000 * 60 * 60); Date t1 = new Date(now.getTime() + 1000 * 60 * 60);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1) secretKeys = api.modify(secretKeys, t1)
.setExpirationDate(null, new UnprotectedKeysProtector()).done(); .setExpirationDate(null, new UnprotectedKeysProtector()).done();
sInfo = PGPainless.inspectKeyRing(secretKeys, t1); sInfo = api.inspect(secretKeys, t1);
assertNull(sInfo.getPrimaryKeyExpirationDate()); assertNull(sInfo.getPrimaryKeyExpirationDate());
} }
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void testExtremeExpirationDates() throws PGPException, IOException { public void testExtremeExpirationDates() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getEmilKey();
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
// seconds from 2021 to 2199 will overflow 32bit integers // seconds from 2021 to 2199 will overflow 32bit integers
Date farAwayExpiration = DateUtil.parseUTCDate("2199-01-01 00:00:00 UTC"); Date farAwayExpiration = DateUtil.parseUTCDate("2199-01-01 00:00:00 UTC");
final PGPSecretKeyRing finalKeys = secretKeys; final OpenPGPKey finalKeys = secretKeys;
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
PGPainless.modifyKeyRing(finalKeys) api.modify(finalKeys)
.setExpirationDate(farAwayExpiration, protector) .setExpirationDate(farAwayExpiration, protector)
.done()); .done());
Date notSoFarAwayExpiration = DateUtil.parseUTCDate("2100-01-01 00:00:00 UTC"); Date notSoFarAwayExpiration = DateUtil.parseUTCDate("2100-01-01 00:00:00 UTC");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.setExpirationDate(notSoFarAwayExpiration, protector) .setExpirationDate(notSoFarAwayExpiration, protector)
.done(); .done();
Date actualExpiration = PGPainless.inspectKeyRing(secretKeys) Date actualExpiration = api.inspect(secretKeys)
.getPrimaryKeyExpirationDate(); .getPrimaryKeyExpirationDate();
JUtils.assertDateEquals(notSoFarAwayExpiration, actualExpiration); JUtils.assertDateEquals(notSoFarAwayExpiration, actualExpiration);
} }

View file

@ -5,8 +5,8 @@
package org.pgpainless.key.modification; package org.pgpainless.key.modification;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.key.info.KeyRingInfo; import org.pgpainless.key.info.KeyRingInfo;
@ -26,13 +26,14 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
@Test @Test
public void generateA_primaryB_revokeA_cantSecondaryA() public void generateA_primaryB_revokeA_cantSecondaryA()
throws PGPException { throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("A")
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey()
.modernKeyRing("A");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
Date now = new Date(); Date now = new Date();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys, now); KeyRingInfo info = api.inspect(secretKeys, now);
assertFalse(info.isHardRevoked("A")); assertFalse(info.isHardRevoked("A"));
assertFalse(info.isHardRevoked("B")); assertFalse(info.isHardRevoked("B"));
assertIsPrimaryUserId("A", info); assertIsPrimaryUserId("A", info);
@ -41,10 +42,10 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
// One hour later // One hour later
Date oneHourLater = new Date(now.getTime() + millisInHour); Date oneHourLater = new Date(now.getTime() + millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, oneHourLater) secretKeys = api.modify(secretKeys, oneHourLater)
.addPrimaryUserId("B", protector) .addPrimaryUserId("B", protector)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, oneHourLater); info = api.inspect(secretKeys, oneHourLater);
assertIsPrimaryUserId("B", info); assertIsPrimaryUserId("B", info);
assertIsNotPrimaryUserId("A", info); assertIsNotPrimaryUserId("A", info);
@ -52,10 +53,10 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
// Two hours later // Two hours later
Date twoHoursLater = new Date(now.getTime() + 2 * millisInHour); Date twoHoursLater = new Date(now.getTime() + 2 * millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, twoHoursLater) secretKeys = api.modify(secretKeys, twoHoursLater)
.revokeUserId("A", protector) // hard revoke A .revokeUserId("A", protector) // hard revoke A
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, twoHoursLater); info = api.inspect(secretKeys, twoHoursLater);
assertTrue(info.isHardRevoked("A")); assertTrue(info.isHardRevoked("A"));
assertFalse(info.isHardRevoked("B")); assertFalse(info.isHardRevoked("B"));
@ -65,71 +66,71 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
// Three hours later // Three hours later
Date threeHoursLater = new Date(now.getTime() + 3 * millisInHour); Date threeHoursLater = new Date(now.getTime() + 3 * millisInHour);
PGPSecretKeyRing finalSecretKeys = secretKeys; OpenPGPKey finalSecretKeys = secretKeys;
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
PGPainless.modifyKeyRing(finalSecretKeys, threeHoursLater).addUserId("A", protector)); api.modify(finalSecretKeys, threeHoursLater).addUserId("A", protector));
} }
@Test @Test
public void generateA_primaryExpire_isExpired() { public void generateA_primaryExpire_isExpired() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("A") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("A");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertIsPrimaryUserId("A", info); assertIsPrimaryUserId("A", info);
Date now = new Date(); Date now = new Date();
Date later = new Date(now.getTime() + millisInHour); Date later = new Date(now.getTime() + millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, now) secretKeys = api.modify(secretKeys, now)
.setExpirationDate(later, protector) // expire the whole key .setExpirationDate(later, protector) // expire the whole key
.done(); .done();
Date evenLater = new Date(now.getTime() + 2 * millisInHour); Date evenLater = new Date(now.getTime() + 2 * millisInHour);
info = PGPainless.inspectKeyRing(secretKeys, evenLater); info = api.inspect(secretKeys, evenLater);
assertFalse(info.isUserIdValid("A")); // is expired by now assertFalse(info.isUserIdValid("A")); // is expired by now
} }
@Test @Test
public void generateA_primaryB_primaryExpire_bIsStillPrimary() { public void generateA_primaryB_primaryExpire_bIsStillPrimary() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("A") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("A");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
Date now = new Date(); Date now = new Date();
// Generate key with primary user-id A // Generate key with primary user-id A
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertIsPrimaryUserId("A", info); assertIsPrimaryUserId("A", info);
// later set primary user-id to B // later set primary user-id to B
Date t1 = new Date(now.getTime() + millisInHour); Date t1 = new Date(now.getTime() + millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1) secretKeys = api.modify(secretKeys, t1)
.addPrimaryUserId("B", protector) .addPrimaryUserId("B", protector)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, t1); info = api.inspect(secretKeys, t1);
assertIsPrimaryUserId("B", info); assertIsPrimaryUserId("B", info);
assertIsNotPrimaryUserId("A", info); assertIsNotPrimaryUserId("A", info);
// Even later expire the whole key // Even later expire the whole key
Date t2 = new Date(now.getTime() + 2 * millisInHour); Date t2 = new Date(now.getTime() + 2 * millisInHour);
Date expiration = new Date(now.getTime() + 10 * millisInHour); Date expiration = new Date(now.getTime() + 10 * millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t2) secretKeys = api.modify(secretKeys, t2)
.setExpirationDate(expiration, protector) // expire the whole key in 1 hour .setExpirationDate(expiration, protector) // expire the whole key in 1 hour
.done(); .done();
Date t3 = new Date(now.getTime() + 3 * millisInHour); Date t3 = new Date(now.getTime() + 3 * millisInHour);
info = PGPainless.inspectKeyRing(secretKeys, t3); info = api.inspect(secretKeys, t3);
assertIsValid("A", info); assertIsValid("A", info);
assertIsValid("B", info); assertIsValid("B", info);
assertIsPrimaryUserId("B", info); assertIsPrimaryUserId("B", info);
assertIsNotPrimaryUserId("A", info); assertIsNotPrimaryUserId("A", info);
info = PGPainless.inspectKeyRing(secretKeys, expiration); info = api.inspect(secretKeys, expiration);
assertIsPrimaryUserId("B", info); // B is still primary, even though assertIsPrimaryUserId("B", info); // B is still primary, even though
assertFalse(info.isUserIdValid("A")); // key is expired by now assertFalse(info.isUserIdValid("A")); // key is expired by now
assertFalse(info.isUserIdValid("B")); assertFalse(info.isUserIdValid("B"));
@ -137,23 +138,23 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
@Test @Test
public void generateA_expire_certify() { public void generateA_expire_certify() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("A") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("A");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
Date now = new Date(); Date now = new Date();
Date t1 = new Date(now.getTime() + millisInHour); Date t1 = new Date(now.getTime() + millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, now) secretKeys = api.modify(secretKeys, now)
.setExpirationDate(t1, protector) .setExpirationDate(t1, protector)
.done(); .done();
Date t2 = new Date(now.getTime() + 2 * millisInHour); Date t2 = new Date(now.getTime() + 2 * millisInHour);
Date t4 = new Date(now.getTime() + 4 * millisInHour); Date t4 = new Date(now.getTime() + 4 * millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t2) secretKeys = api.modify(secretKeys, t2)
.setExpirationDate(t4, protector) .setExpirationDate(t4, protector)
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertIsValid("A", info); assertIsValid("A", info);
assertIsPrimaryUserId("A", info); assertIsPrimaryUserId("A", info);
} }
@ -161,28 +162,28 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
@Test @Test
public void generateA_expire_primaryB_expire_isPrimaryB() public void generateA_expire_primaryB_expire_isPrimaryB()
throws PGPException { throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("A") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("A");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
Date now = new Date(); Date now = new Date();
Date t1 = new Date(now.getTime() + millisInHour); Date t1 = new Date(now.getTime() + millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1) secretKeys = api.modify(secretKeys, t1)
.setExpirationDate(t1, protector) .setExpirationDate(t1, protector)
.done(); .done();
Date t2 = new Date(now.getTime() + 2 * millisInHour); Date t2 = new Date(now.getTime() + 2 * millisInHour);
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys, t2); KeyRingInfo info = api.inspect(secretKeys, t2);
assertIsPrimaryUserId("A", info); assertIsPrimaryUserId("A", info);
assertIsNotValid("A", info); // A is expired assertIsNotValid("A", info); // A is expired
secretKeys = PGPainless.modifyKeyRing(secretKeys, t2) secretKeys = api.modify(secretKeys, t2)
.addPrimaryUserId("B", protector) .addPrimaryUserId("B", protector)
.done(); .done();
Date t3 = new Date(now.getTime() + 3 * millisInHour); Date t3 = new Date(now.getTime() + 3 * millisInHour);
info = PGPainless.inspectKeyRing(secretKeys, t3); info = api.inspect(secretKeys, t3);
assertIsPrimaryUserId("B", info); assertIsPrimaryUserId("B", info);
assertIsNotValid("B", info); // A and B are still expired assertIsNotValid("B", info); // A and B are still expired
@ -190,19 +191,19 @@ public class ChangePrimaryUserIdAndExpirationDatesTest {
Date t4 = new Date(now.getTime() + 4 * millisInHour); Date t4 = new Date(now.getTime() + 4 * millisInHour);
Date t5 = new Date(now.getTime() + 5 * millisInHour); Date t5 = new Date(now.getTime() + 5 * millisInHour);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t3) secretKeys = api.modify(secretKeys, t3)
.setExpirationDate(t5, protector) .setExpirationDate(t5, protector)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, t4); info = api.inspect(secretKeys, t4);
assertIsValid("B", info); assertIsValid("B", info);
assertIsValid("A", info); // A got re-validated when changing exp date assertIsValid("A", info); // A got re-validated when changing exp date
assertIsPrimaryUserId("B", info); assertIsPrimaryUserId("B", info);
secretKeys = PGPainless.modifyKeyRing(secretKeys, t4) secretKeys = api.modify(secretKeys, t4)
.addUserId("A", protector) // re-certify A as non-primary user-id .addUserId("A", protector) // re-certify A as non-primary user-id
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, t4); info = api.inspect(secretKeys, t4);
assertIsValid("B", info); assertIsValid("B", info);
assertIsValid("A", info); assertIsValid("A", info);

View file

@ -15,8 +15,8 @@ import java.util.Iterator;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPImplementation; import org.bouncycastle.openpgp.api.OpenPGPImplementation;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor; import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
@ -35,8 +35,8 @@ import org.pgpainless.util.Passphrase;
public class ChangeSecretKeyRingPassphraseTest { public class ChangeSecretKeyRingPassphraseTest {
private final PGPSecretKeyRing keyRing = PGPainless.generateKeyRing().simpleEcKeyRing("password@encryp.ted", "weakPassphrase") private final OpenPGPKey keyRing = PGPainless.getInstance()
.getPGPSecretKeyRing(); .generateKey().simpleEcKeyRing("password@encryp.ted", "weakPassphrase");
public ChangeSecretKeyRingPassphraseTest() { public ChangeSecretKeyRingPassphraseTest() {
} }
@ -44,66 +44,64 @@ public class ChangeSecretKeyRingPassphraseTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void changePassphraseOfWholeKeyRingTest() throws PGPException { public void changePassphraseOfWholeKeyRingTest() throws PGPException {
PGPainless api = PGPainless.getInstance();
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) OpenPGPKey secretKeys = api.modify(keyRing)
.changePassphraseFromOldPassphrase(Passphrase.fromPassword("weakPassphrase")) .changePassphraseFromOldPassphrase(Passphrase.fromPassword("weakPassphrase"))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("1337p455phr453")) .toNewPassphrase(Passphrase.fromPassword("1337p455phr453"))
.done(); .done();
PGPSecretKeyRing changedPassphraseKeyRing = secretKeys;
assertEquals(KeyRingProtectionSettings.secureDefaultSettings().getEncryptionAlgorithm().getAlgorithmId(), assertEquals(KeyRingProtectionSettings.secureDefaultSettings().getEncryptionAlgorithm().getAlgorithmId(),
changedPassphraseKeyRing.getSecretKey().getKeyEncryptionAlgorithm()); secretKeys.getPGPSecretKeyRing().getSecretKey().getKeyEncryptionAlgorithm());
assertThrows(PGPException.class, () -> assertThrows(PGPException.class, () ->
signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.emptyPassphrase()), signDummyMessageWithKeysAndPassphrase(api, secretKeys, Passphrase.emptyPassphrase()),
"Unlocking secret key ring with empty passphrase MUST fail."); "Unlocking secret key ring with empty passphrase MUST fail.");
assertThrows(PGPException.class, () -> assertThrows(PGPException.class, () ->
signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.fromPassword("weakPassphrase")), signDummyMessageWithKeysAndPassphrase(api, secretKeys, Passphrase.fromPassword("weakPassphrase")),
"Unlocking secret key ring with old passphrase MUST fail."); "Unlocking secret key ring with old passphrase MUST fail.");
assertDoesNotThrow(() -> signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.fromPassword("1337p455phr453")), assertDoesNotThrow(() -> signDummyMessageWithKeysAndPassphrase(api, secretKeys, Passphrase.fromPassword("1337p455phr453")),
"Unlocking the secret key ring with the new passphrase MUST succeed."); "Unlocking the secret key ring with the new passphrase MUST succeed.");
} }
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void changePassphraseOfWholeKeyRingToEmptyPassphrase() throws PGPException, IOException { public void changePassphraseOfWholeKeyRingToEmptyPassphrase() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) PGPainless api = PGPainless.getInstance();
OpenPGPKey changedPassphraseKeyRing = api.modify(keyRing)
.changePassphraseFromOldPassphrase(Passphrase.fromPassword("weakPassphrase")) .changePassphraseFromOldPassphrase(Passphrase.fromPassword("weakPassphrase"))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNoPassphrase() .toNoPassphrase()
.done(); .done();
PGPSecretKeyRing changedPassphraseKeyRing = secretKeys;
assertEquals(SymmetricKeyAlgorithm.NULL.getAlgorithmId(), assertEquals(SymmetricKeyAlgorithm.NULL.getAlgorithmId(),
changedPassphraseKeyRing.getSecretKey().getKeyEncryptionAlgorithm()); changedPassphraseKeyRing.getPGPSecretKeyRing().getSecretKey().getKeyEncryptionAlgorithm());
signDummyMessageWithKeysAndPassphrase(changedPassphraseKeyRing, Passphrase.emptyPassphrase()); signDummyMessageWithKeysAndPassphrase(api, changedPassphraseKeyRing, Passphrase.emptyPassphrase());
} }
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void changePassphraseOfSingleSubkeyToNewPassphrase() throws PGPException { public void changePassphraseOfSingleSubkeyToNewPassphrase() throws PGPException {
PGPainless api = PGPainless.getInstance();
Iterator<PGPSecretKey> keys = keyRing.getSecretKeys(); Iterator<PGPSecretKey> keys = keyRing.getPGPSecretKeyRing().getSecretKeys();
PGPSecretKey primaryKey = keys.next(); PGPSecretKey primaryKey = keys.next();
PGPSecretKey subKey = keys.next(); PGPSecretKey subKey = keys.next();
extractPrivateKey(primaryKey, Passphrase.fromPassword("weakPassphrase")); extractPrivateKey(primaryKey, Passphrase.fromPassword("weakPassphrase"));
extractPrivateKey(subKey, Passphrase.fromPassword("weakPassphrase")); extractPrivateKey(subKey, Passphrase.fromPassword("weakPassphrase"));
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) OpenPGPKey secretKeys = api.modify(keyRing)
.changeSubKeyPassphraseFromOldPassphrase(subKey.getPublicKey().getKeyIdentifier(), .changeSubKeyPassphraseFromOldPassphrase(subKey.getPublicKey().getKeyIdentifier(),
Passphrase.fromPassword("weakPassphrase")) Passphrase.fromPassword("weakPassphrase"))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("subKeyPassphrase")) .toNewPassphrase(Passphrase.fromPassword("subKeyPassphrase"))
.done(); .done();
keys = secretKeys.getSecretKeys(); keys = secretKeys.getPGPSecretKeyRing().getSecretKeys();
primaryKey = keys.next(); primaryKey = keys.next();
subKey = keys.next(); subKey = keys.next();
@ -124,18 +122,18 @@ public class ChangeSecretKeyRingPassphraseTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void changePassphraseOfSingleSubkeyToEmptyPassphrase() throws PGPException { public void changePassphraseOfSingleSubkeyToEmptyPassphrase() throws PGPException {
PGPainless api = PGPainless.getInstance();
Iterator<PGPSecretKey> keys = keyRing.getSecretKeys(); Iterator<PGPSecretKey> keys = keyRing.getPGPSecretKeyRing().getSecretKeys();
PGPSecretKey primaryKey = keys.next(); PGPSecretKey primaryKey = keys.next();
PGPSecretKey subKey = keys.next(); PGPSecretKey subKey = keys.next();
PGPSecretKeyRing secretKeys = PGPainless.modifyKeyRing(keyRing) OpenPGPKey secretKeys = api.modify(keyRing)
.changeSubKeyPassphraseFromOldPassphrase(subKey.getKeyIdentifier(), Passphrase.fromPassword("weakPassphrase")) .changeSubKeyPassphraseFromOldPassphrase(subKey.getKeyIdentifier(), Passphrase.fromPassword("weakPassphrase"))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNoPassphrase() .toNoPassphrase()
.done(); .done();
keys = secretKeys.getSecretKeys(); keys = secretKeys.getPGPSecretKeyRing().getSecretKeys();
primaryKey = keys.next(); primaryKey = keys.next();
subKey = keys.next(); subKey = keys.next();
@ -176,13 +174,13 @@ public class ChangeSecretKeyRingPassphraseTest {
UnlockSecretKey.unlockSecretKey(secretKey, decryptor); UnlockSecretKey.unlockSecretKey(secretKey, decryptor);
} }
private void signDummyMessageWithKeysAndPassphrase(PGPSecretKeyRing keyRing, Passphrase passphrase) throws IOException, PGPException { private void signDummyMessageWithKeysAndPassphrase(PGPainless api, OpenPGPKey key, Passphrase passphrase) throws IOException, PGPException {
String dummyMessage = "dummy"; String dummyMessage = "dummy";
ByteArrayOutputStream dummy = new ByteArrayOutputStream(); ByteArrayOutputStream dummy = new ByteArrayOutputStream();
EncryptionStream stream = PGPainless.encryptAndOrSign().onOutputStream(dummy) EncryptionStream stream = api.generateMessage().onOutputStream(dummy)
.withOptions(ProducerOptions.sign(SigningOptions.get() .withOptions(ProducerOptions.sign(SigningOptions.get()
.addInlineSignature(PasswordBasedSecretKeyRingProtector.forKey(keyRing, passphrase), .addInlineSignature(PasswordBasedSecretKeyRingProtector.forKey(key, passphrase),
keyRing, DocumentSignatureType.BINARY_DOCUMENT))); key, DocumentSignatureType.BINARY_DOCUMENT)));
Streams.pipeAll(new ByteArrayInputStream(dummyMessage.getBytes()), stream); Streams.pipeAll(new ByteArrayInputStream(dummyMessage.getBytes()), stream);
stream.close(); stream.close();

View file

@ -4,8 +4,8 @@
package org.pgpainless.key.modification; package org.pgpainless.key.modification;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.JUtils; import org.junit.JUtils;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -25,26 +25,27 @@ public class ChangeSubkeyExpirationTimeTest {
@Test @Test
public void changeExpirationTimeOfSubkey() { public void changeExpirationTimeOfSubkey() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
Date now = secretKeys.getPublicKey().getCreationTime(); Date now = secretKeys.getPrimaryKey().getCreationTime();
Date inAnHour = new Date(now.getTime() + 1000 * 60 * 60); Date inAnHour = new Date(now.getTime() + 1000 * 60 * 60);
OpenPGPCertificate.OpenPGPComponentKey encryptionKey = PGPainless.inspectKeyRing(secretKeys) OpenPGPCertificate.OpenPGPComponentKey encryptionKey = api.inspect(secretKeys)
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0); .getEncryptionSubkeys(EncryptionPurpose.ANY).get(0);
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.setExpirationDateOfSubkey( .setExpirationDateOfSubkey(
inAnHour, inAnHour,
encryptionKey.getKeyIdentifier().getKeyId(), encryptionKey.getKeyIdentifier(),
SecretKeyRingProtector.unprotectedKeys()) SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
JUtils.assertDateEquals(inAnHour, PGPainless.inspectKeyRing(secretKeys) JUtils.assertDateEquals(inAnHour, api.inspect(secretKeys)
.getSubkeyExpirationDate(OpenPgpFingerprint.of(encryptionKey.getPGPPublicKey()))); .getSubkeyExpirationDate(OpenPgpFingerprint.of(encryptionKey.getPGPPublicKey())));
} }
@Test @Test
public void changeExpirationTimeOfExpiredSubkey() throws IOException { public void changeExpirationTimeOfExpiredSubkey() throws IOException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing( PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = api.readKey().parseKey(
"-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
"Version: PGPainless\n" + "Version: PGPainless\n" +
"Comment: CA52 4D5D E3D8 9CD9 105B BA45 3761 076B C6B5 3000\n" + "Comment: CA52 4D5D E3D8 9CD9 105B BA45 3761 076B C6B5 3000\n" +
@ -79,13 +80,13 @@ public class ChangeSubkeyExpirationTimeTest {
OpenPgpFingerprint encryptionSubkey = new OpenPgpV4Fingerprint("2E541354A23C9943375EC27A3EF133ED8720D636"); OpenPgpFingerprint encryptionSubkey = new OpenPgpV4Fingerprint("2E541354A23C9943375EC27A3EF133ED8720D636");
JUtils.assertDateEquals( JUtils.assertDateEquals(
DateUtil.parseUTCDate("2023-12-07 16:29:46 UTC"), DateUtil.parseUTCDate("2023-12-07 16:29:46 UTC"),
PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey)); api.inspect(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
// re-validate the subkey by setting its expiry to null (no expiry) // re-validate the subkey by setting its expiry to null (no expiry)
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.setExpirationDateOfSubkey(null, encryptionSubkey.getKeyId(), SecretKeyRingProtector.unprotectedKeys()) .setExpirationDateOfSubkey(null, encryptionSubkey.getKeyIdentifier(), SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
assertNull(PGPainless.inspectKeyRing(secretKeys).getSubkeyExpirationDate(encryptionSubkey)); assertNull(api.inspect(secretKeys).getSubkeyExpirationDate(encryptionSubkey));
} }
} }

View file

@ -17,9 +17,9 @@ import java.nio.charset.StandardCharsets;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -73,9 +73,10 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
@Test @Test
public void manualReplaceUserIdWithFixedVersionDoesNotHinderEncryptionCapability() throws IOException, PGPException { public void manualReplaceUserIdWithFixedVersionDoesNotHinderEncryptionCapability() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
PGPSecretKeyRing modified = PGPainless.modifyKeyRing(secretKeys) OpenPGPKey modified = api.modify(secretKeys)
.addUserId(userIdAfter, new SelfSignatureSubpackets.Callback() { .addUserId(userIdAfter, new SelfSignatureSubpackets.Callback() {
@Override @Override
public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) { public void modifyHashedSubpackets(SelfSignatureSubpackets hashedSubpackets) {
@ -85,8 +86,8 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
.removeUserId(userIdBefore, protector) .removeUserId(userIdBefore, protector)
.done(); .done();
KeyRingInfo before = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo before = api.inspect(secretKeys);
KeyRingInfo after = PGPainless.inspectKeyRing(modified); KeyRingInfo after = api.inspect(modified);
assertEquals(userIdBefore, before.getPrimaryUserId()); assertEquals(userIdBefore, before.getPrimaryUserId());
assertEquals(userIdAfter, after.getPrimaryUserId()); assertEquals(userIdAfter, after.getPrimaryUserId());
@ -104,34 +105,38 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
@Test @Test
public void testReplaceUserId_missingOldUserIdThrows() throws IOException { public void testReplaceUserId_missingOldUserIdThrows() throws IOException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY); PGPainless api = PGPainless.getInstance();
assertThrows(NoSuchElementException.class, () -> PGPainless.modifyKeyRing(secretKeys) OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
assertThrows(NoSuchElementException.class, () -> api.modify(secretKeys)
.replaceUserId("missing", userIdAfter, SecretKeyRingProtector.unprotectedKeys())); .replaceUserId("missing", userIdAfter, SecretKeyRingProtector.unprotectedKeys()));
} }
@Test @Test
public void testReplaceUserId_emptyOldUserIdThrows() throws IOException { public void testReplaceUserId_emptyOldUserIdThrows() throws IOException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY); PGPainless api = PGPainless.getInstance();
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
assertThrows(IllegalArgumentException.class, () -> api.modify(secretKeys)
.replaceUserId(" ", userIdAfter, SecretKeyRingProtector.unprotectedKeys())); .replaceUserId(" ", userIdAfter, SecretKeyRingProtector.unprotectedKeys()));
} }
@Test @Test
public void testReplaceUserId_emptyNewUserIdThrows() throws IOException { public void testReplaceUserId_emptyNewUserIdThrows() throws IOException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY); PGPainless api = PGPainless.getInstance();
assertThrows(IllegalArgumentException.class, () -> PGPainless.modifyKeyRing(secretKeys) OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
assertThrows(IllegalArgumentException.class, () -> api.modify(secretKeys)
.replaceUserId(userIdBefore, " ", SecretKeyRingProtector.unprotectedKeys())); .replaceUserId(userIdBefore, " ", SecretKeyRingProtector.unprotectedKeys()));
} }
@Test @Test
public void testReplaceImplicitUserIdDoesNotBreakStuff() throws IOException, PGPException { public void testReplaceImplicitUserIdDoesNotBreakStuff() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(SECRET_KEY); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = api.readKey().parseKey(SECRET_KEY);
PGPSecretKeyRing edited = PGPainless.modifyKeyRing(secretKeys) OpenPGPKey edited = api.modify(secretKeys)
.replaceUserId(userIdBefore, userIdAfter, SecretKeyRingProtector.unprotectedKeys()) .replaceUserId(userIdBefore, userIdAfter, SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(edited); KeyRingInfo info = api.inspect(edited);
assertTrue(info.isUserIdValid(userIdAfter)); assertTrue(info.isUserIdValid(userIdAfter));
assertEquals(userIdAfter, info.getPrimaryUserId()); assertEquals(userIdAfter, info.getPrimaryUserId());
@ -139,10 +144,10 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
assertNotNull(latestCertification); assertNotNull(latestCertification);
assertTrue(latestCertification.getHashedSubPackets().isPrimaryUserID()); assertTrue(latestCertification.getHashedSubPackets().isPrimaryUserID());
PGPPublicKeyRing cert = PGPainless.extractCertificate(edited); OpenPGPCertificate cert = edited.toCertificate();
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign() EncryptionStream encryptionStream = api.generateMessage()
.onOutputStream(out) .onOutputStream(out)
.withOptions(ProducerOptions.encrypt(EncryptionOptions.get() .withOptions(ProducerOptions.encrypt(EncryptionOptions.get()
.addRecipient(cert))); .addRecipient(cert)));
@ -151,7 +156,7 @@ public class FixUserIdDoesNotBreakEncryptionCapabilityTest {
encryptionStream.close(); encryptionStream.close();
EncryptionResult result = encryptionStream.getResult(); EncryptionResult result = encryptionStream.getResult();
assertTrue(result.isEncryptedFor(cert)); assertTrue(result.isEncryptedFor(cert.getPGPPublicKeyRing()));
ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
ByteArrayOutputStream plain = new ByteArrayOutputStream(); ByteArrayOutputStream plain = new ByteArrayOutputStream();

View file

@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException; import java.io.IOException;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
@ -166,17 +166,18 @@ public class GnuDummyS2KChangePassphraseTest {
@Test @Test
public void testChangePassphraseToNoPassphraseIgnoresGnuDummyS2KKeys() throws PGPException, IOException { public void testChangePassphraseToNoPassphraseIgnoresGnuDummyS2KKeys() throws PGPException, IOException {
PGPSecretKeyRing secretKey = PGPainless.readKeyRing().secretKeyRing(KEY_WITH_GNU_DUMMY_S2K_PRIMARY_KEY); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKey = api.readKey().parseKey(KEY_WITH_GNU_DUMMY_S2K_PRIMARY_KEY);
assertFalse(PGPainless.inspectKeyRing(secretKey).isFullyDecrypted()); assertFalse(api.inspect(secretKey).isFullyDecrypted());
secretKey = PGPainless.modifyKeyRing(secretKey) secretKey = api.modify(secretKey)
.changePassphraseFromOldPassphrase(passphrase) .changePassphraseFromOldPassphrase(passphrase)
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNoPassphrase() .toNoPassphrase()
.done(); .done();
assertTrue(PGPainless.inspectKeyRing(secretKey).isFullyDecrypted()); assertTrue(api.inspect(secretKey).isFullyDecrypted());
} }
} }

View file

@ -10,9 +10,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.util.Date; import java.util.Date;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPSignatureSubpacketVector; import org.bouncycastle.openpgp.PGPSignatureSubpacketVector;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -26,11 +26,11 @@ public class OldSignatureSubpacketsArePreservedOnNewSigTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void verifyOldSignatureSubpacketsArePreservedOnNewExpirationDateSig() { public void verifyOldSignatureSubpacketsArePreservedOnNewExpirationDateSig() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.simpleEcKeyRing("Alice <alice@wonderland.lit>") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .simpleEcKeyRing("Alice <alice@wonderland.lit>");
PGPSignature oldSignature = PGPainless.inspectKeyRing(secretKeys).getLatestUserIdCertification("Alice <alice@wonderland.lit>"); PGPSignature oldSignature = api.inspect(secretKeys).getLatestUserIdCertification("Alice <alice@wonderland.lit>");
assertNotNull(oldSignature); assertNotNull(oldSignature);
PGPSignatureSubpacketVector oldPackets = oldSignature.getHashedSubPackets(); PGPSignatureSubpacketVector oldPackets = oldSignature.getHashedSubPackets();
@ -40,10 +40,10 @@ public class OldSignatureSubpacketsArePreservedOnNewSigTest {
Date t1 = new Date(now.getTime() + millisInHour); Date t1 = new Date(now.getTime() + millisInHour);
Date expiration = new Date(now.getTime() + 5 * 24 * millisInHour); // in 5 days Date expiration = new Date(now.getTime() + 5 * 24 * millisInHour); // in 5 days
secretKeys = PGPainless.modifyKeyRing(secretKeys, t1) secretKeys = api.modify(secretKeys, t1)
.setExpirationDate(expiration, new UnprotectedKeysProtector()) .setExpirationDate(expiration, new UnprotectedKeysProtector())
.done(); .done();
PGPSignature newSignature = PGPainless.inspectKeyRing(secretKeys, t1).getLatestUserIdCertification("Alice <alice@wonderland.lit>"); PGPSignature newSignature = api.inspect(secretKeys, t1).getLatestUserIdCertification("Alice <alice@wonderland.lit>");
assertNotNull(newSignature); assertNotNull(newSignature);
PGPSignatureSubpacketVector newPackets = newSignature.getHashedSubPackets(); PGPSignatureSubpacketVector newPackets = newSignature.getHashedSubPackets();

View file

@ -10,7 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.Map; import java.util.Map;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.EncryptionPurpose; import org.pgpainless.algorithm.EncryptionPurpose;
@ -28,31 +28,31 @@ public class RefuseToAddWeakSubkeyTest {
@Test @Test
public void testEditorRefusesToAddWeakSubkey() { public void testEditorRefusesToAddWeakSubkey() {
PGPainless api = PGPainless.getInstance();
// ensure default policy is set // ensure default policy is set
Policy oldPolicy = PGPainless.getPolicy(); Policy oldPolicy = api.getAlgorithmPolicy();
Policy adjusted = oldPolicy.copy().withPublicKeyAlgorithmPolicy( Policy adjusted = oldPolicy.copy().withPublicKeyAlgorithmPolicy(
Policy.PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy() Policy.PublicKeyAlgorithmPolicy.bsi2021PublicKeyAlgorithmPolicy()
).build(); ).build();
PGPainless.getInstance().setAlgorithmPolicy(adjusted); api.setAlgorithmPolicy(adjusted);
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() OpenPGPKey secretKeys = api.generateKey()
.modernKeyRing("Alice") .modernKeyRing("Alice");
.getPGPSecretKeyRing(); SecretKeyRingEditorInterface editor = api.modify(secretKeys);
SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys);
KeySpec spec = KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.ENCRYPT_COMMS).build(); KeySpec spec = KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.ENCRYPT_COMMS).build();
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
editor.addSubKey(spec, Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys())); editor.addSubKey(spec, Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys()));
PGPainless.getInstance().setAlgorithmPolicy(oldPolicy); api.setAlgorithmPolicy(oldPolicy);
} }
@Test @Test
public void testEditorAllowsToAddWeakSubkeyIfCompliesToPublicKeyAlgorithmPolicy() { public void testEditorAllowsToAddWeakSubkeyIfCompliesToPublicKeyAlgorithmPolicy() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("Alice") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("Alice");
Policy oldPolicy = PGPainless.getPolicy(); Policy oldPolicy = api.getAlgorithmPolicy();
// set weak policy // set weak policy
Map<PublicKeyAlgorithm, Integer> minimalBitStrengths = new EnumMap<>(PublicKeyAlgorithm.class); Map<PublicKeyAlgorithm, Integer> minimalBitStrengths = new EnumMap<>(PublicKeyAlgorithm.class);
@ -75,11 +75,11 @@ public class RefuseToAddWeakSubkeyTest {
minimalBitStrengths.put(PublicKeyAlgorithm.DIFFIE_HELLMAN, 2000); minimalBitStrengths.put(PublicKeyAlgorithm.DIFFIE_HELLMAN, 2000);
// §7.2.2 // §7.2.2
minimalBitStrengths.put(PublicKeyAlgorithm.ECDH, 250); minimalBitStrengths.put(PublicKeyAlgorithm.ECDH, 250);
PGPainless.getInstance().setAlgorithmPolicy(oldPolicy.copy() api.setAlgorithmPolicy(oldPolicy.copy()
.withPublicKeyAlgorithmPolicy(new Policy.PublicKeyAlgorithmPolicy(minimalBitStrengths)) .withPublicKeyAlgorithmPolicy(new Policy.PublicKeyAlgorithmPolicy(minimalBitStrengths))
.build()); .build());
SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys); SecretKeyRingEditorInterface editor = api.modify(secretKeys);
KeySpec spec = KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.ENCRYPT_COMMS) KeySpec spec = KeySpec.getBuilder(KeyType.RSA(RsaLength._1024), KeyFlag.ENCRYPT_COMMS)
.setKeyCreationDate(editor.getReferenceTime()) // The key gets created after we instantiate the editor. .setKeyCreationDate(editor.getReferenceTime()) // The key gets created after we instantiate the editor.
.build(); .build();
@ -87,9 +87,9 @@ public class RefuseToAddWeakSubkeyTest {
secretKeys = editor.addSubKey(spec, Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys()) secretKeys = editor.addSubKey(spec, Passphrase.emptyPassphrase(), SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
assertEquals(2, PGPainless.inspectKeyRing(secretKeys).getEncryptionSubkeys(EncryptionPurpose.ANY).size()); assertEquals(2, api.inspect(secretKeys).getEncryptionSubkeys(EncryptionPurpose.ANY).size());
// reset default policy // reset default policy
PGPainless.getInstance().setAlgorithmPolicy(oldPolicy); api.setAlgorithmPolicy(oldPolicy);
} }
} }

View file

@ -15,9 +15,10 @@ import java.io.IOException;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.api.OpenPGPSignature;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.key.TestKeys; import org.pgpainless.key.TestKeys;
@ -30,9 +31,10 @@ public class RevocationCertificateTest {
@Test @Test
public void createRevocationCertificateTest() throws PGPException, IOException { public void createRevocationCertificateTest() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getEmilKey();
PGPSignature revocation = PGPainless.modifyKeyRing(secretKeys) OpenPGPSignature revocation = api.modify(secretKeys)
.createRevocation(SecretKeyRingProtector.unprotectedKeys(), .createRevocation(SecretKeyRingProtector.unprotectedKeys(),
RevocationAttributes.createKeyRevocation() RevocationAttributes.createKeyRevocation()
.withReason(RevocationAttributes.Reason.KEY_RETIRED) .withReason(RevocationAttributes.Reason.KEY_RETIRED)
@ -40,66 +42,68 @@ public class RevocationCertificateTest {
assertNotNull(revocation); assertNotNull(revocation);
assertTrue(PGPainless.inspectKeyRing(secretKeys).isKeyValidlyBound(secretKeys.getPublicKey().getKeyID())); assertTrue(api.inspect(secretKeys).isKeyValidlyBound(secretKeys.getKeyIdentifier()));
// merge key and revocation certificate // merge key and revocation certificate
PGPSecretKeyRing revokedKey = KeyRingUtils.keysPlusSecretKey( PGPSecretKeyRing revokedKey = KeyRingUtils.keysPlusSecretKey(
secretKeys, secretKeys.getPGPSecretKeyRing(),
KeyRingUtils.secretKeyPlusSignature(secretKeys.getSecretKey(), revocation)); KeyRingUtils.secretKeyPlusSignature(secretKeys.getPrimarySecretKey().getPGPSecretKey(), revocation.getSignature()));
assertFalse(PGPainless.inspectKeyRing(revokedKey).isKeyValidlyBound(secretKeys.getPublicKey().getKeyID())); assertFalse(api.inspect(api.toKey(revokedKey)).isKeyValidlyBound(secretKeys.getKeyIdentifier()));
} }
@Test @Test
public void createMinimalRevocationCertificateTest() throws PGPException, IOException { public void createMinimalRevocationCertificateTest() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getEmilKey();
PGPPublicKeyRing minimalRevocationCert = PGPainless.modifyKeyRing(secretKeys).createMinimalRevocationCertificate( OpenPGPCertificate minimalRevocationCert = api.modify(secretKeys).createMinimalRevocationCertificate(
SecretKeyRingProtector.unprotectedKeys(), SecretKeyRingProtector.unprotectedKeys(),
RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED).withoutDescription()); RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED).withoutDescription());
assertEquals(1, minimalRevocationCert.size()); assertEquals(1, minimalRevocationCert.getPGPKeyRing().size());
PGPPublicKey key = minimalRevocationCert.getPublicKey(); PGPPublicKey key = minimalRevocationCert.getPrimaryKey().getPGPPublicKey();
assertEquals(secretKeys.getPublicKey().getKeyID(), key.getKeyID()); assertEquals(secretKeys.getKeyIdentifier(), key.getKeyIdentifier());
assertEquals(1, CollectionUtils.iteratorToList(key.getSignatures()).size()); assertEquals(1, CollectionUtils.iteratorToList(key.getSignatures()).size());
assertFalse(key.getUserIDs().hasNext()); assertFalse(key.getUserIDs().hasNext());
assertFalse(key.getUserAttributes().hasNext()); assertFalse(key.getUserAttributes().hasNext());
assertNull(key.getTrustData()); assertNull(key.getTrustData());
PGPPublicKeyRing originalCert = PGPainless.extractCertificate(secretKeys); OpenPGPCertificate originalCert = secretKeys.toCertificate();
PGPPublicKeyRing mergedCert = PGPainless.mergeCertificate(originalCert, minimalRevocationCert); OpenPGPCertificate mergedCert = api.mergeCertificate(originalCert, minimalRevocationCert);
assertTrue(PGPainless.inspectKeyRing(mergedCert).getRevocationState().isSoftRevocation()); assertTrue(api.inspect(mergedCert).getRevocationState().isSoftRevocation());
} }
@Test @Test
public void createMinimalRevocationCertificateForFreshKeyTest() { public void createMinimalRevocationCertificateForFreshKeyTest() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice <alice@example.org>") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice <alice@example.org>");
PGPPublicKeyRing minimalRevocationCert = PGPainless.modifyKeyRing(secretKeys).createMinimalRevocationCertificate( OpenPGPCertificate minimalRevocationCert = api.modify(secretKeys).createMinimalRevocationCertificate(
SecretKeyRingProtector.unprotectedKeys(), SecretKeyRingProtector.unprotectedKeys(),
RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED).withoutDescription()); RevocationAttributes.createKeyRevocation().withReason(RevocationAttributes.Reason.KEY_RETIRED).withoutDescription());
assertEquals(1, minimalRevocationCert.size()); assertEquals(1, minimalRevocationCert.getKeys().size());
PGPPublicKey key = minimalRevocationCert.getPublicKey(); PGPPublicKey key = minimalRevocationCert.getPGPPublicKeyRing().getPublicKey();
assertEquals(secretKeys.getPublicKey().getKeyID(), key.getKeyID()); assertEquals(secretKeys.getKeyIdentifier(), key.getKeyIdentifier());
assertEquals(1, CollectionUtils.iteratorToList(key.getSignatures()).size()); assertEquals(1, CollectionUtils.iteratorToList(key.getSignatures()).size());
assertFalse(key.getUserIDs().hasNext()); assertFalse(key.getUserIDs().hasNext());
assertFalse(key.getUserAttributes().hasNext()); assertFalse(key.getUserAttributes().hasNext());
assertNull(key.getTrustData()); assertNull(key.getTrustData());
PGPPublicKeyRing originalCert = PGPainless.extractCertificate(secretKeys); OpenPGPCertificate originalCert = secretKeys.toCertificate();
PGPPublicKeyRing mergedCert = PGPainless.mergeCertificate(originalCert, minimalRevocationCert); OpenPGPCertificate mergedCert = api.mergeCertificate(originalCert, minimalRevocationCert);
assertTrue(PGPainless.inspectKeyRing(mergedCert).getRevocationState().isSoftRevocation()); assertTrue(api.inspect(mergedCert).getRevocationState().isSoftRevocation());
} }
@Test @Test
public void createMinimalRevocationCertificate_wrongReason() throws PGPException, IOException { public void createMinimalRevocationCertificate_wrongReason() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getEmilKey();
assertThrows(IllegalArgumentException.class, assertThrows(IllegalArgumentException.class,
() -> PGPainless.modifyKeyRing(secretKeys).createMinimalRevocationCertificate( () -> api.modify(secretKeys).createMinimalRevocationCertificate(
SecretKeyRingProtector.unprotectedKeys(), SecretKeyRingProtector.unprotectedKeys(),
RevocationAttributes.createCertificateRevocation() RevocationAttributes.createCertificateRevocation()
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID) .withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)

View file

@ -7,13 +7,14 @@ package org.pgpainless.key.modification;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.Arrays; import java.util.Collections;
import org.bouncycastle.bcpg.ArmoredOutputStream; import org.bouncycastle.bcpg.ArmoredOutputStream;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -24,7 +25,7 @@ import org.pgpainless.util.TestAllImplementations;
/** /**
* Test that makes sure that PGPainless can deal with keys that carry a key * Test that makes sure that PGPainless can deal with keys that carry a key
* signature of type 0x10 (generic certification). * signature of type 0x10 (generic certification).
* * <p>
* Originally PGPainless would only handle keys with key signature type * Originally PGPainless would only handle keys with key signature type
* 0x13 (positive certification) and would otherwise crash when negotiating * 0x13 (positive certification) and would otherwise crash when negotiating
* algorithms, esp. when revoking a key. * algorithms, esp. when revoking a key.
@ -70,23 +71,26 @@ public class RevokeKeyWithGenericCertificationSignatureTest {
} }
private KeyPair revokeKey(String priv) throws IOException, PGPException { private KeyPair revokeKey(String priv) throws IOException, PGPException {
byte[] armoredBytes = priv.getBytes(StandardCharsets.UTF_8); PGPainless api = PGPainless.getInstance();
PGPSecretKeyRing r = PGPainless.readKeyRing() OpenPGPKey key = api.readKey().parseKey(priv);
.secretKeyRing(armoredBytes); OpenPGPKey onlyPrimaryKey = api.toKey(
PGPSecretKey secretKey = r.getSecretKey(); new PGPSecretKeyRing(
Collections.singletonList(key.getPrimarySecretKey().getPGPSecretKey())
)
);
// this is not ideal, but still valid usage // this is not ideal, but still valid usage
PGPSecretKeyRing secretKeyRing = OpenPGPKey revokedPrimaryKey =
PGPainless.modifyKeyRing(new PGPSecretKeyRing(Arrays.asList(secretKey))) api.modify(onlyPrimaryKey)
.revoke(new UnprotectedKeysProtector()).done(); .revoke(new UnprotectedKeysProtector()).done();
PGPPublicKey pkr = secretKeyRing.getPublicKeys().next(); PGPPublicKey pkr = revokedPrimaryKey.getPGPSecretKeyRing().getPublicKeys().next();
ByteArrayOutputStream pubOutBytes = new ByteArrayOutputStream(); ByteArrayOutputStream pubOutBytes = new ByteArrayOutputStream();
try (ArmoredOutputStream pubOut = ArmoredOutputStreamFactory.get(pubOutBytes)) { try (ArmoredOutputStream pubOut = ArmoredOutputStreamFactory.get(pubOutBytes)) {
pkr.encode(pubOut); pkr.encode(pubOut);
} }
pubOutBytes.close(); pubOutBytes.close();
PGPSecretKey skr = secretKeyRing.getSecretKeys().next(); PGPSecretKey skr = revokedPrimaryKey.getPGPSecretKeyRing().getSecretKeys().next();
ByteArrayOutputStream secOutBytes = new ByteArrayOutputStream(); ByteArrayOutputStream secOutBytes = new ByteArrayOutputStream();
try (ArmoredOutputStream privOut = ArmoredOutputStreamFactory.get(secOutBytes)) { try (ArmoredOutputStream privOut = ArmoredOutputStreamFactory.get(secOutBytes)) {
skr.encode(privOut); skr.encode(privOut);

View file

@ -7,7 +7,7 @@ package org.pgpainless.key.modification;
import java.io.IOException; import java.io.IOException;
import java.util.Date; import java.util.Date;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.JUtils; import org.junit.JUtils;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -99,16 +99,17 @@ public class RevokeKeyWithoutPreferredAlgorithmsOnPrimaryKey {
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void testChangingExpirationTimeWithKeyWithoutPrefAlgos() public void testChangingExpirationTimeWithKeyWithoutPrefAlgos()
throws IOException { throws IOException {
PGPainless api = PGPainless.getInstance();
Date expirationDate = DateUtil.now(); Date expirationDate = DateUtil.now();
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(KEY); OpenPGPKey secretKeys = api.readKey().parseKey(KEY);
SecretKeyRingProtector protector = new UnprotectedKeysProtector(); SecretKeyRingProtector protector = new UnprotectedKeysProtector();
SecretKeyRingEditorInterface modify = PGPainless.modifyKeyRing(secretKeys) SecretKeyRingEditorInterface modify = api.modify(secretKeys)
.setExpirationDate(expirationDate, protector); .setExpirationDate(expirationDate, protector);
secretKeys = modify.done(); secretKeys = modify.done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
JUtils.assertDateEquals(expirationDate, info.getPrimaryKeyExpirationDate()); JUtils.assertDateEquals(expirationDate, info.getPrimaryKeyExpirationDate());
} }

View file

@ -19,8 +19,9 @@ import org.bouncycastle.bcpg.sig.IssuerFingerprint;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.openpgp.api.OpenPGPSignature;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestTemplate; import org.junit.jupiter.api.TestTemplate;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
@ -33,7 +34,6 @@ import org.pgpainless.key.modification.secretkeyring.SecretKeyRingEditorInterfac
import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector; import org.pgpainless.key.protection.PasswordBasedSecretKeyRingProtector;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets; import org.pgpainless.signature.subpackets.RevocationSignatureSubpackets;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
import org.pgpainless.util.TestAllImplementations; import org.pgpainless.util.TestAllImplementations;
@ -43,10 +43,11 @@ public class RevokeSubKeyTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void revokeSukeyTest() throws IOException, PGPException { public void revokeSubkeyTest() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
Iterator<PGPSecretKey> keysIterator = secretKeys.iterator(); Iterator<PGPSecretKey> keysIterator = secretKeys.getPGPSecretKeyRing().iterator();
PGPSecretKey primaryKey = keysIterator.next(); PGPSecretKey primaryKey = keysIterator.next();
PGPSecretKey subKey = keysIterator.next(); PGPSecretKey subKey = keysIterator.next();
@ -55,10 +56,10 @@ public class RevokeSubKeyTest {
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
.forKey(secretKeys, Passphrase.fromPassword("password123")); .forKey(secretKeys, Passphrase.fromPassword("password123"));
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.revokeSubKey(new OpenPgpV4Fingerprint(subKey), protector) .revokeSubKey(new OpenPgpV4Fingerprint(subKey), protector)
.done(); .done();
keysIterator = secretKeys.iterator(); keysIterator = secretKeys.getPGPSecretKeyRing().iterator();
primaryKey = keysIterator.next(); primaryKey = keysIterator.next();
subKey = keysIterator.next(); subKey = keysIterator.next();
@ -68,19 +69,20 @@ public class RevokeSubKeyTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void detachedRevokeSubkeyTest() throws IOException, PGPException { public void detachedRevokeSubkeyTest() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = TestKeys.getCryptieKey();
OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(secretKeys); OpenPgpV4Fingerprint fingerprint = new OpenPgpV4Fingerprint(secretKeys);
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector.forKey(secretKeys, Passphrase.fromPassword("password123")); SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector.forKey(secretKeys, Passphrase.fromPassword("password123"));
PGPSignature revocationCertificate = PGPainless.modifyKeyRing(secretKeys) OpenPGPSignature revocationCertificate = api.modify(secretKeys)
.createRevocation(fingerprint, protector, RevocationAttributes.createKeyRevocation() .createRevocation(fingerprint, protector, RevocationAttributes.createKeyRevocation()
.withReason(RevocationAttributes.Reason.KEY_RETIRED) .withReason(RevocationAttributes.Reason.KEY_RETIRED)
.withDescription("Key no longer used.")); .withDescription("Key no longer used."));
PGPPublicKey publicKey = secretKeys.getPublicKey(); PGPPublicKey publicKey = secretKeys.getPGPSecretKeyRing().getPublicKey();
assertFalse(publicKey.hasRevocation()); assertFalse(publicKey.hasRevocation());
publicKey = PGPPublicKey.addCertification(publicKey, revocationCertificate); publicKey = PGPPublicKey.addCertification(publicKey, revocationCertificate.getSignature());
assertTrue(publicKey.hasRevocation()); assertTrue(publicKey.hasRevocation());
} }
@ -88,19 +90,20 @@ public class RevokeSubKeyTest {
@TestTemplate @TestTemplate
@ExtendWith(TestAllImplementations.class) @ExtendWith(TestAllImplementations.class)
public void testRevocationSignatureTypeCorrect() throws IOException, PGPException { public void testRevocationSignatureTypeCorrect() throws IOException, PGPException {
PGPSecretKeyRing secretKeys = TestKeys.getCryptieSecretKeyRing(); PGPainless api = PGPainless.getInstance();
Iterator<PGPPublicKey> keysIterator = secretKeys.getPublicKeys(); OpenPGPKey secretKeys = TestKeys.getCryptieKey();
Iterator<PGPPublicKey> keysIterator = secretKeys.getPGPKeyRing().getPublicKeys();
PGPPublicKey primaryKey = keysIterator.next(); PGPPublicKey primaryKey = keysIterator.next();
PGPPublicKey subKey = keysIterator.next(); PGPPublicKey subKey = keysIterator.next();
SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector SecretKeyRingProtector protector = PasswordBasedSecretKeyRingProtector
.forKey(secretKeys, Passphrase.fromPassword("password123")); .forKey(secretKeys, Passphrase.fromPassword("password123"));
SecretKeyRingEditorInterface editor = PGPainless.modifyKeyRing(secretKeys); SecretKeyRingEditorInterface editor = api.modify(secretKeys);
PGPSignature keyRevocation = editor.createRevocation(primaryKey.getKeyID(), protector, (RevocationAttributes) null); OpenPGPSignature keyRevocation = editor.createRevocation(primaryKey.getKeyIdentifier(), protector, (RevocationAttributes) null);
PGPSignature subkeyRevocation = editor.createRevocation(subKey.getKeyID(), protector, (RevocationAttributes) null); OpenPGPSignature subkeyRevocation = editor.createRevocation(subKey.getKeyIdentifier(), protector, (RevocationAttributes) null);
assertEquals(SignatureType.KEY_REVOCATION.getCode(), keyRevocation.getSignatureType()); assertEquals(SignatureType.KEY_REVOCATION.getCode(), keyRevocation.getSignature().getSignatureType());
assertEquals(SignatureType.SUBKEY_REVOCATION.getCode(), subkeyRevocation.getSignatureType()); assertEquals(SignatureType.SUBKEY_REVOCATION.getCode(), subkeyRevocation.getSignature().getSignatureType());
} }
@Test @Test
@ -126,39 +129,39 @@ public class RevokeSubKeyTest {
@Test @Test
public void inspectSubpacketsOnDefaultRevocationSignature() public void inspectSubpacketsOnDefaultRevocationSignature()
throws PGPException { throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
PGPPublicKey encryptionSubkey = PGPainless.inspectKeyRing(secretKeys) PGPPublicKey encryptionSubkey = api.inspect(secretKeys)
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getPGPPublicKey(); .getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getPGPPublicKey();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.revokeSubKey(encryptionSubkey.getKeyID(), protector) .revokeSubKey(encryptionSubkey.getKeyIdentifier(), protector)
.done(); .done();
encryptionSubkey = secretKeys.getPublicKey(encryptionSubkey.getKeyID()); encryptionSubkey = secretKeys.getPGPSecretKeyRing().getPublicKey(encryptionSubkey.getKeyIdentifier());
PGPSignature revocation = encryptionSubkey.getSignaturesOfType(SignatureType.SUBKEY_REVOCATION.getCode()).next(); PGPSignature revocation = encryptionSubkey.getSignaturesOfType(SignatureType.SUBKEY_REVOCATION.getCode()).next();
assertNotNull(revocation); assertNotNull(revocation);
assertArrayEquals( assertArrayEquals(
secretKeys.getPublicKey().getFingerprint(), secretKeys.getPGPSecretKeyRing().getPublicKey().getFingerprint(),
revocation.getHashedSubPackets().getIssuerFingerprint().getFingerprint()); revocation.getHashedSubPackets().getIssuerFingerprint().getFingerprint());
assertEquals(secretKeys.getPublicKey().getKeyID(), assertEquals(secretKeys.getPGPSecretKeyRing().getPublicKey().getKeyID(),
revocation.getHashedSubPackets().getIssuerKeyID()); revocation.getHashedSubPackets().getIssuerKeyID());
assertNull(SignatureSubpacketsUtil.getRevocationReason(revocation)); assertNull(SignatureSubpacketsUtil.getRevocationReason(revocation));
assertTrue(SignatureUtils.isHardRevocation(revocation)); assertTrue(revocation.isHardRevocation());
} }
@Test @Test
public void inspectSubpacketsOnModifiedRevocationSignature() { public void inspectSubpacketsOnModifiedRevocationSignature() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("Alice") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().modernKeyRing("Alice");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
PGPPublicKey encryptionSubkey = PGPainless.inspectKeyRing(secretKeys) PGPPublicKey encryptionSubkey = api.inspect(secretKeys)
.getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getPGPPublicKey(); .getEncryptionSubkeys(EncryptionPurpose.ANY).get(0).getPGPPublicKey();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.revokeSubKey(encryptionSubkey.getKeyID(), protector, new RevocationSignatureSubpackets.Callback() { .revokeSubKey(encryptionSubkey.getKeyIdentifier(), protector, new RevocationSignatureSubpackets.Callback() {
@Override @Override
public void modifyHashedSubpackets(RevocationSignatureSubpackets hashedSubpackets) { public void modifyHashedSubpackets(RevocationSignatureSubpackets hashedSubpackets) {
hashedSubpackets.setRevocationReason( hashedSubpackets.setRevocationReason(
@ -171,14 +174,14 @@ public class RevokeSubKeyTest {
}) })
.done(); .done();
encryptionSubkey = secretKeys.getPublicKey(encryptionSubkey.getKeyID()); encryptionSubkey = secretKeys.getPGPSecretKeyRing().getPublicKey(encryptionSubkey.getKeyIdentifier());
PGPSignature revocation = encryptionSubkey.getSignaturesOfType(SignatureType.SUBKEY_REVOCATION.getCode()).next(); PGPSignature revocation = encryptionSubkey.getSignaturesOfType(SignatureType.SUBKEY_REVOCATION.getCode()).next();
assertNotNull(revocation); assertNotNull(revocation);
assertNull(revocation.getHashedSubPackets().getIssuerFingerprint()); assertNull(revocation.getHashedSubPackets().getIssuerFingerprint());
assertEquals(secretKeys.getPublicKey().getKeyID(), assertEquals(secretKeys.getKeyIdentifier().getKeyId(),
revocation.getHashedSubPackets().getIssuerKeyID()); revocation.getHashedSubPackets().getIssuerKeyID());
assertNotNull(SignatureSubpacketsUtil.getRevocationReason(revocation)); assertNotNull(SignatureSubpacketsUtil.getRevocationReason(revocation));
assertFalse(SignatureUtils.isHardRevocation(revocation)); assertFalse(revocation.isHardRevocation());
} }
} }

View file

@ -13,46 +13,45 @@ import java.util.Date;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature; import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.key.info.KeyRingInfo; import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.util.RevocationAttributes; import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.util.selection.userid.SelectUserId;
public class RevokeUserIdsTest { public class RevokeUserIdsTest {
@Test @Test
public void revokeWithSelectUserId() throws PGPException { public void revokeWithSelectUserId() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("Alice <alice@pgpainless.org>") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("Alice <alice@pgpainless.org>");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId("Allice <alice@example.org>", protector) .addUserId("Allice <alice@example.org>", protector)
.addUserId("Alice <alice@example.org>", protector) .addUserId("Alice <alice@example.org>", protector)
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>")); assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
assertTrue(info.isUserIdValid("Allice <alice@example.org>")); assertTrue(info.isUserIdValid("Allice <alice@example.org>"));
assertTrue(info.isUserIdValid("Alice <alice@example.org>")); assertTrue(info.isUserIdValid("Alice <alice@example.org>"));
Date n1 = new Date(info.getCreationDate().getTime() + 1000); // 1 sec later Date n1 = new Date(info.getCreationDate().getTime() + 1000); // 1 sec later
secretKeys = PGPainless.modifyKeyRing(secretKeys, n1) secretKeys = api.modify(secretKeys, n1)
.revokeUserIds( .revokeUserIds(
SelectUserId.containsEmailAddress("alice@example.org"),
protector, protector,
RevocationAttributes.createCertificateRevocation() RevocationAttributes.createCertificateRevocation()
.withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID) .withReason(RevocationAttributes.Reason.USER_ID_NO_LONGER_VALID)
.withoutDescription()) .withoutDescription(),
uid -> uid.contains("alice@example.org"))
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, n1); info = api.inspect(secretKeys, n1);
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>")); assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
assertFalse(info.isUserIdValid("Allice <alice@example.org>")); assertFalse(info.isUserIdValid("Allice <alice@example.org>"));
assertFalse(info.isUserIdValid("Alice <alice@example.org>")); assertFalse(info.isUserIdValid("Alice <alice@example.org>"));
@ -60,28 +59,28 @@ public class RevokeUserIdsTest {
@Test @Test
public void removeUserId() throws PGPException { public void removeUserId() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("Alice <alice@pgpainless.org>") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("Alice <alice@pgpainless.org>");
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys(); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId("Allice <alice@example.org>", protector) .addUserId("Allice <alice@example.org>", protector)
.addUserId("Alice <alice@example.org>", protector) .addUserId("Alice <alice@example.org>", protector)
.done(); .done();
KeyRingInfo info = PGPainless.inspectKeyRing(secretKeys); KeyRingInfo info = api.inspect(secretKeys);
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>")); assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
assertTrue(info.isUserIdValid("Allice <alice@example.org>")); assertTrue(info.isUserIdValid("Allice <alice@example.org>"));
assertTrue(info.isUserIdValid("Alice <alice@example.org>")); assertTrue(info.isUserIdValid("Alice <alice@example.org>"));
Date n1 = new Date(info.getCreationDate().getTime() + 1000); Date n1 = new Date(info.getCreationDate().getTime() + 1000);
secretKeys = PGPainless.modifyKeyRing(secretKeys, n1) secretKeys = api.modify(secretKeys, n1)
.removeUserId("Allice <alice@example.org>", protector) .removeUserId("Allice <alice@example.org>", protector)
.done(); .done();
info = PGPainless.inspectKeyRing(secretKeys, n1); info = api.inspect(secretKeys, n1);
assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>")); assertTrue(info.isUserIdValid("Alice <alice@pgpainless.org>"));
assertFalse(info.isUserIdValid("Allice <alice@example.org>")); assertFalse(info.isUserIdValid("Allice <alice@example.org>"));
assertTrue(info.isUserIdValid("Alice <alice@example.org>")); assertTrue(info.isUserIdValid("Alice <alice@example.org>"));
@ -95,14 +94,14 @@ public class RevokeUserIdsTest {
@Test @Test
public void emptySelectionYieldsNoSuchElementException() { public void emptySelectionYieldsNoSuchElementException() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("Alice <alice@pgpainless.org>") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("Alice <alice@pgpainless.org>");
assertThrows(NoSuchElementException.class, () -> assertThrows(NoSuchElementException.class, () ->
PGPainless.modifyKeyRing(secretKeys).revokeUserIds( api.modify(secretKeys).revokeUserIds(
SelectUserId.containsEmailAddress("alice@example.org"),
SecretKeyRingProtector.unprotectedKeys(), SecretKeyRingProtector.unprotectedKeys(),
(RevocationAttributes) null)); (RevocationAttributes) null,
uid -> uid.contains("alice@example.org")));
} }
} }

View file

@ -16,6 +16,7 @@ import org.bouncycastle.bcpg.SecretKeyPacket;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKey; import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -67,27 +68,27 @@ public class S2KUsageFixTest {
@Test @Test
public void verifyOutFixInChangePassphraseWorks() public void verifyOutFixInChangePassphraseWorks()
throws PGPException { throws PGPException {
PGPSecretKeyRing before = PGPainless.generateKeyRing().modernKeyRing("Alice", "before") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey before = api.generateKey().modernKeyRing("Alice", "before");
for (PGPSecretKey key : before) { for (PGPSecretKey key : before.getPGPSecretKeyRing()) {
assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage()); assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage());
} }
PGPSecretKeyRing unprotected = PGPainless.modifyKeyRing(before) OpenPGPKey unprotected = api.modify(before)
.changePassphraseFromOldPassphrase(Passphrase.fromPassword("before")) .changePassphraseFromOldPassphrase(Passphrase.fromPassword("before"))
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNoPassphrase() .toNoPassphrase()
.done(); .done();
for (PGPSecretKey key : unprotected) { for (PGPSecretKey key : unprotected.getPGPSecretKeyRing()) {
assertEquals(SecretKeyPacket.USAGE_NONE, key.getS2KUsage()); assertEquals(SecretKeyPacket.USAGE_NONE, key.getS2KUsage());
} }
PGPSecretKeyRing after = PGPainless.modifyKeyRing(unprotected) OpenPGPKey after = api.modify(unprotected)
.changePassphraseFromOldPassphrase(Passphrase.emptyPassphrase()) .changePassphraseFromOldPassphrase(Passphrase.emptyPassphrase())
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword("after")) .toNewPassphrase(Passphrase.fromPassword("after"))
.done(); .done();
for (PGPSecretKey key : after) { for (PGPSecretKey key : after.getPGPSecretKeyRing()) {
assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage()); assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage());
} }
} }
@ -95,18 +96,19 @@ public class S2KUsageFixTest {
@Test @Test
public void testFixS2KUsageFrom_USAGE_CHECKSUM_to_USAGE_SHA1() public void testFixS2KUsageFrom_USAGE_CHECKSUM_to_USAGE_SHA1()
throws IOException, PGPException { throws IOException, PGPException {
PGPSecretKeyRing keys = PGPainless.readKeyRing().secretKeyRing(KEY_WITH_USAGE_CHECKSUM); PGPainless api = PGPainless.getInstance();
OpenPGPKey keys = api.readKey().parseKey(KEY_WITH_USAGE_CHECKSUM);
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("after")); SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("after"));
PGPSecretKeyRing fixed = S2KUsageFix.replaceUsageChecksumWithUsageSha1(keys, protector); PGPSecretKeyRing fixed = S2KUsageFix.replaceUsageChecksumWithUsageSha1(keys.getPGPSecretKeyRing(), protector);
for (PGPSecretKey key : fixed) { for (PGPSecretKey key : fixed) {
assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage()); assertEquals(SecretKeyPacket.USAGE_SHA1, key.getS2KUsage());
} }
testCanStillDecrypt(keys, protector); testCanStillDecrypt(api.toKey(fixed), protector);
} }
private void testCanStillDecrypt(PGPSecretKeyRing keys, SecretKeyRingProtector protector) private void testCanStillDecrypt(OpenPGPKey keys, SecretKeyRingProtector protector)
throws PGPException, IOException { throws PGPException, IOException {
ByteArrayInputStream in = new ByteArrayInputStream(MESSAGE.getBytes(StandardCharsets.UTF_8)); ByteArrayInputStream in = new ByteArrayInputStream(MESSAGE.getBytes(StandardCharsets.UTF_8));
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify() DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()

View file

@ -34,6 +34,7 @@ import org.bouncycastle.openpgp.PGPSignatureGenerator;
import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator; import org.bouncycastle.openpgp.PGPSignatureSubpacketGenerator;
import org.bouncycastle.openpgp.api.OpenPGPCertificate; import org.bouncycastle.openpgp.api.OpenPGPCertificate;
import org.bouncycastle.openpgp.api.OpenPGPImplementation; import org.bouncycastle.openpgp.api.OpenPGPImplementation;
import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.CompressionAlgorithm;
@ -43,7 +44,6 @@ import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.key.TestKeys; import org.pgpainless.key.TestKeys;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnlockSecretKey; import org.pgpainless.key.protection.UnlockSecretKey;
import org.pgpainless.policy.Policy;
import org.pgpainless.signature.consumer.SignaturePicker; import org.pgpainless.signature.consumer.SignaturePicker;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil; import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
@ -51,17 +51,17 @@ public class SignatureSubpacketsUtilTest {
@Test @Test
public void testGetKeyExpirationTimeAsDate() { public void testGetKeyExpirationTimeAsDate() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.modernKeyRing("Expire") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .modernKeyRing("Expire");
Date expiration = Date.from(new Date().toInstant().plus(365, ChronoUnit.DAYS)); Date expiration = Date.from(new Date().toInstant().plus(365, ChronoUnit.DAYS));
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.setExpirationDate(expiration, SecretKeyRingProtector.unprotectedKeys()) .setExpirationDate(expiration, SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
PGPSignature expirationSig = SignaturePicker.pickCurrentUserIdCertificationSignature( PGPSignature expirationSig = SignaturePicker.pickCurrentUserIdCertificationSignature(
secretKeys, "Expire", Policy.getInstance(), new Date()); secretKeys.getPGPSecretKeyRing(), "Expire", api.getAlgorithmPolicy(), new Date());
OpenPGPCertificate.OpenPGPComponentKey notTheRightKey = PGPainless.inspectKeyRing(secretKeys).getSigningSubkeys().get(0); OpenPGPCertificate.OpenPGPComponentKey notTheRightKey = api.inspect(secretKeys).getSigningSubkeys().get(0);
assertThrows(IllegalArgumentException.class, () -> assertThrows(IllegalArgumentException.class, () ->
SignatureSubpacketsUtil.getKeyExpirationTimeAsDate(expirationSig, notTheRightKey.getPGPPublicKey())); SignatureSubpacketsUtil.getKeyExpirationTimeAsDate(expirationSig, notTheRightKey.getPGPPublicKey()));
@ -69,18 +69,19 @@ public class SignatureSubpacketsUtilTest {
@Test @Test
public void testGetRevocable() throws PGPException, IOException { public void testGetRevocable() throws PGPException, IOException {
PGPSecretKeyRing secretKeys = TestKeys.getEmilSecretKeyRing(); OpenPGPKey secretKeys = TestKeys.getEmilKey();
PGPPrivateKey certKey = UnlockSecretKey.unlockSecretKey(secretKeys.getSecretKey(), SecretKeyRingProtector.unprotectedKeys()); PGPPrivateKey certKey = UnlockSecretKey.unlockSecretKey(secretKeys.getPrimarySecretKey().getPGPSecretKey(),
SecretKeyRingProtector.unprotectedKeys());
PGPSignatureGenerator generator = getSignatureGenerator(certKey, SignatureType.CASUAL_CERTIFICATION); PGPSignatureGenerator generator = getSignatureGenerator(certKey, SignatureType.CASUAL_CERTIFICATION);
PGPSignature withoutRevocable = generator.generateCertification(secretKeys.getPublicKey()); PGPSignature withoutRevocable = generator.generateCertification(secretKeys.getPrimaryKey().getPGPPublicKey());
assertNull(SignatureSubpacketsUtil.getRevocable(withoutRevocable)); assertNull(SignatureSubpacketsUtil.getRevocable(withoutRevocable));
generator = getSignatureGenerator(certKey, SignatureType.CASUAL_CERTIFICATION); generator = getSignatureGenerator(certKey, SignatureType.CASUAL_CERTIFICATION);
PGPSignatureSubpacketGenerator hashed = new PGPSignatureSubpacketGenerator(); PGPSignatureSubpacketGenerator hashed = new PGPSignatureSubpacketGenerator();
hashed.setRevocable(true, true); hashed.setRevocable(true, true);
generator.setHashedSubpackets(hashed.generate()); generator.setHashedSubpackets(hashed.generate());
PGPSignature withRevocable = generator.generateCertification(secretKeys.getPublicKey()); PGPSignature withRevocable = generator.generateCertification(secretKeys.getPrimaryKey().getPGPPublicKey());
assertNotNull(SignatureSubpacketsUtil.getRevocable(withRevocable)); assertNotNull(SignatureSubpacketsUtil.getRevocable(withRevocable));
} }

View file

@ -14,7 +14,7 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
@ -24,17 +24,17 @@ public class SelectUserIdTest {
@Test @Test
public void testSelectUserIds() throws PGPException { public void testSelectUserIds() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing() PGPainless api = PGPainless.getInstance();
.simpleEcKeyRing("<alice@wonderland.lit>") OpenPGPKey secretKeys = api.generateKey()
.getPGPSecretKeyRing(); .simpleEcKeyRing("<alice@wonderland.lit>");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId( .addUserId(
UserId.builder().withName("Alice Liddell").noComment() UserId.builder().withName("Alice Liddell").noComment()
.withEmail("crazy@the-rabbit.hole").build(), .withEmail("crazy@the-rabbit.hole").build(),
SecretKeyRingProtector.unprotectedKeys()) SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds(); List<String> userIds = api.inspect(secretKeys).getValidUserIds();
List<String> validEmail = userIds.stream().filter(SelectUserId.and( List<String> validEmail = userIds.stream().filter(SelectUserId.and(
SelectUserId.validUserId(secretKeys), SelectUserId.validUserId(secretKeys),
SelectUserId.containsEmailAddress("alice@wonderland.lit") SelectUserId.containsEmailAddress("alice@wonderland.lit")
@ -54,14 +54,14 @@ public class SelectUserIdTest {
@Test @Test
public void testContainsSubstring() throws PGPException { public void testContainsSubstring() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("wine drinker") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("wine drinker");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId("this is not a quine", SecretKeyRingProtector.unprotectedKeys()) .addUserId("this is not a quine", SecretKeyRingProtector.unprotectedKeys())
.addUserId("this is not a crime", SecretKeyRingProtector.unprotectedKeys()) .addUserId("this is not a crime", SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds(); List<String> userIds = api.inspect(secretKeys).getValidUserIds();
List<String> containSubstring = userIds.stream().filter(SelectUserId.containsSubstring("ine")).collect(Collectors.toList()); List<String> containSubstring = userIds.stream().filter(SelectUserId.containsSubstring("ine")).collect(Collectors.toList());
assertEquals(Arrays.asList("wine drinker", "this is not a quine"), containSubstring); assertEquals(Arrays.asList("wine drinker", "this is not a quine"), containSubstring);
@ -69,9 +69,9 @@ public class SelectUserIdTest {
@Test @Test
public void testContainsEmailAddress() { public void testContainsEmailAddress() {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("Alice <alice@wonderland.lit>") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("Alice <alice@wonderland.lit>");
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds(); List<String> userIds = api.inspect(secretKeys).getValidUserIds();
assertEquals("Alice <alice@wonderland.lit>", userIds.stream().filter( assertEquals("Alice <alice@wonderland.lit>", userIds.stream().filter(
SelectUserId.containsEmailAddress("alice@wonderland.lit")).findFirst().get()); SelectUserId.containsEmailAddress("alice@wonderland.lit")).findFirst().get());
@ -83,15 +83,15 @@ public class SelectUserIdTest {
@Test @Test
public void testAndOrNot() throws PGPException { public void testAndOrNot() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("Alice <alice@wonderland.lit>") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("Alice <alice@wonderland.lit>");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId("Alice <another@email.address>", SecretKeyRingProtector.unprotectedKeys()) .addUserId("Alice <another@email.address>", SecretKeyRingProtector.unprotectedKeys())
.addUserId("<crazy@the-rabbit.hole>", SecretKeyRingProtector.unprotectedKeys()) .addUserId("<crazy@the-rabbit.hole>", SecretKeyRingProtector.unprotectedKeys())
.addUserId("Crazy Girl <alice@wonderland.lit>", SecretKeyRingProtector.unprotectedKeys()) .addUserId("Crazy Girl <alice@wonderland.lit>", SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds(); List<String> userIds = api.inspect(secretKeys).getValidUserIds();
List<String> or = userIds.stream().filter(SelectUserId.or( List<String> or = userIds.stream().filter(SelectUserId.or(
SelectUserId.containsEmailAddress("alice@wonderland.lit"), SelectUserId.containsEmailAddress("alice@wonderland.lit"),
@ -110,12 +110,12 @@ public class SelectUserIdTest {
@Test @Test
public void testFirstMatch() throws PGPException { public void testFirstMatch() throws PGPException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().simpleEcKeyRing("First UserID") PGPainless api = PGPainless.getInstance();
.getPGPSecretKeyRing(); OpenPGPKey secretKeys = api.generateKey().simpleEcKeyRing("First UserID");
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.addUserId("Second UserID", SecretKeyRingProtector.unprotectedKeys()) .addUserId("Second UserID", SecretKeyRingProtector.unprotectedKeys())
.done(); .done();
List<String> userIds = PGPainless.inspectKeyRing(secretKeys).getValidUserIds(); List<String> userIds = api.inspect(secretKeys).getValidUserIds();
assertEquals("First UserID", userIds.stream().filter(SelectUserId.validUserId(secretKeys)).findFirst().get()); assertEquals("First UserID", userIds.stream().filter(SelectUserId.validUserId(secretKeys)).findFirst().get());
assertEquals("Second UserID", userIds.stream().filter(SelectUserId.containsSubstring("Second")).findFirst().get()); assertEquals("Second UserID", userIds.stream().filter(SelectUserId.containsSubstring("Second")).findFirst().get());
} }

View file

@ -9,10 +9,11 @@ import java.io.InputStream
import java.io.OutputStream import java.io.OutputStream
import java.lang.RuntimeException import java.lang.RuntimeException
import org.bouncycastle.openpgp.PGPException import org.bouncycastle.openpgp.PGPException
import org.bouncycastle.openpgp.PGPPublicKeyRing
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection import org.bouncycastle.openpgp.PGPPublicKeyRingCollection
import org.bouncycastle.openpgp.api.OpenPGPCertificate
import org.pgpainless.PGPainless import org.pgpainless.PGPainless
import org.pgpainless.bouncycastle.extensions.openPgpFingerprint import org.pgpainless.bouncycastle.extensions.openPgpFingerprint
import org.pgpainless.bouncycastle.extensions.toOpenPGPCertificate
import org.pgpainless.exception.WrongPassphraseException import org.pgpainless.exception.WrongPassphraseException
import org.pgpainless.key.util.KeyRingUtils import org.pgpainless.key.util.KeyRingUtils
import org.pgpainless.key.util.RevocationAttributes import org.pgpainless.key.util.RevocationAttributes
@ -38,7 +39,7 @@ class RevokeKeyImpl : RevokeKey {
secretKeyRings.forEach { protector.addSecretKey(it) } secretKeyRings.forEach { protector.addSecretKey(it) }
val revocationCertificates = mutableListOf<PGPPublicKeyRing>() val revocationCertificates = mutableListOf<OpenPGPCertificate>()
secretKeyRings.forEach { secretKeys -> secretKeyRings.forEach { secretKeys ->
val editor = PGPainless.modifyKeyRing(secretKeys) val editor = PGPainless.modifyKeyRing(secretKeys)
try { try {
@ -53,7 +54,8 @@ class RevokeKeyImpl : RevokeKey {
val certificate = PGPainless.extractCertificate(secretKeys) val certificate = PGPainless.extractCertificate(secretKeys)
val revocation = editor.createRevocation(protector, attributes) val revocation = editor.createRevocation(protector, attributes)
revocationCertificates.add( revocationCertificates.add(
KeyRingUtils.injectCertification(certificate, revocation)) KeyRingUtils.injectCertification(certificate, revocation.signature)
.toOpenPGPCertificate())
} }
} catch (e: WrongPassphraseException) { } catch (e: WrongPassphraseException) {
throw SOPGPException.KeyIsProtected( throw SOPGPException.KeyIsProtected(
@ -67,7 +69,8 @@ class RevokeKeyImpl : RevokeKey {
return object : Ready() { return object : Ready() {
override fun writeTo(outputStream: OutputStream) { override fun writeTo(outputStream: OutputStream) {
val collection = PGPPublicKeyRingCollection(revocationCertificates) val collection =
PGPPublicKeyRingCollection(revocationCertificates.map { it.pgpPublicKeyRing })
if (armor) { if (armor) {
val armorOut = ArmoredOutputStreamFactory.get(outputStream) val armorOut = ArmoredOutputStreamFactory.get(outputStream)
collection.encode(armorOut) collection.encode(armorOut)

View file

@ -7,7 +7,7 @@ package sop.testsuite.pgpainless.operation;
import org.bouncycastle.bcpg.KeyIdentifier; import org.bouncycastle.bcpg.KeyIdentifier;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.api.OpenPGPKey;
import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -32,13 +32,13 @@ public class PGPainlessChangeKeyPasswordTest extends ChangeKeyPasswordTest {
@ParameterizedTest @ParameterizedTest
@MethodSource("provideInstances") @MethodSource("provideInstances")
public void changePasswordOfKeyWithSeparateSubkeyPasswords(SOP sop) throws IOException, PGPException { public void changePasswordOfKeyWithSeparateSubkeyPasswords(SOP sop) throws IOException, PGPException {
PGPSecretKeyRing secretKeys = PGPainless.buildKeyRing() PGPainless api = PGPainless.getInstance();
OpenPGPKey secretKeys = PGPainless.buildKeyRing()
.setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER)) .setPrimaryKey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.CERTIFY_OTHER))
.addSubkey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA)) .addSubkey(KeySpec.getBuilder(KeyType.EDDSA_LEGACY(EdDSALegacyCurve._Ed25519), KeyFlag.SIGN_DATA))
.addSubkey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE)) .addSubkey(KeySpec.getBuilder(KeyType.XDH_LEGACY(XDHLegacySpec._X25519), KeyFlag.ENCRYPT_COMMS, KeyFlag.ENCRYPT_STORAGE))
.build() .build();
.getPGPSecretKeyRing(); Iterator<PGPPublicKey> keys = secretKeys.getPGPSecretKeyRing().getPublicKeys();
Iterator<PGPPublicKey> keys = secretKeys.getPublicKeys();
KeyIdentifier primaryKeyId = keys.next().getKeyIdentifier(); KeyIdentifier primaryKeyId = keys.next().getKeyIdentifier();
KeyIdentifier signingKeyId = keys.next().getKeyIdentifier(); KeyIdentifier signingKeyId = keys.next().getKeyIdentifier();
KeyIdentifier encryptKeyId = keys.next().getKeyIdentifier(); KeyIdentifier encryptKeyId = keys.next().getKeyIdentifier();
@ -47,7 +47,7 @@ public class PGPainlessChangeKeyPasswordTest extends ChangeKeyPasswordTest {
String p2 = "0r4ng3"; String p2 = "0r4ng3";
String p3 = "dr4g0n"; String p3 = "dr4g0n";
secretKeys = PGPainless.modifyKeyRing(secretKeys) secretKeys = api.modify(secretKeys)
.changeSubKeyPassphraseFromOldPassphrase(primaryKeyId, Passphrase.emptyPassphrase()) .changeSubKeyPassphraseFromOldPassphrase(primaryKeyId, Passphrase.emptyPassphrase())
.withSecureDefaultSettings() .withSecureDefaultSettings()
.toNewPassphrase(Passphrase.fromPassword(p1)) .toNewPassphrase(Passphrase.fromPassword(p1))