Improve Key Generation API
This commit is contained in:
parent
20002efbf6
commit
b4240ac9f7
|
@ -0,0 +1,24 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package openpgp
|
||||||
|
|
||||||
|
import org.pgpainless.util.Passphrase
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension function to convert a nullable [CharSequence] into an [Array]. Iff [this] is `null`,
|
||||||
|
* then return an empty array, otherwise return an array only consisting of [this].
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
fun CharSequence?.toArray(): Array<CharSequence> = this?.let { arrayOf(it) } ?: emptyArray()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a [Passphrase] from this [CharSequence]. Iff [this] is `null` or blank, then this method
|
||||||
|
* returns [Passphrase.emptyPassphrase], otherwise it returns [Passphrase.fromPassword].
|
||||||
|
*
|
||||||
|
* @return passphrase
|
||||||
|
*/
|
||||||
|
fun CharSequence?.toPassphrase(): Passphrase =
|
||||||
|
this?.let { Passphrase.fromPassword(it) } ?: Passphrase.emptyPassphrase()
|
|
@ -15,6 +15,7 @@ import org.pgpainless.encryption_signing.EncryptionBuilder
|
||||||
import org.pgpainless.key.certification.CertifyCertificate
|
import org.pgpainless.key.certification.CertifyCertificate
|
||||||
import org.pgpainless.key.generation.KeyRingBuilder
|
import org.pgpainless.key.generation.KeyRingBuilder
|
||||||
import org.pgpainless.key.generation.KeyRingTemplates
|
import org.pgpainless.key.generation.KeyRingTemplates
|
||||||
|
import org.pgpainless.key.generation.OpenPgpKeyGenerator
|
||||||
import org.pgpainless.key.info.KeyRingInfo
|
import org.pgpainless.key.info.KeyRingInfo
|
||||||
import org.pgpainless.key.modification.secretkeyring.SecretKeyRingEditor
|
import org.pgpainless.key.modification.secretkeyring.SecretKeyRingEditor
|
||||||
import org.pgpainless.key.parsing.KeyRingReader
|
import org.pgpainless.key.parsing.KeyRingReader
|
||||||
|
@ -26,19 +27,30 @@ class PGPainless private constructor() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
/** Generate an OpenPGP key. */
|
||||||
|
@JvmOverloads
|
||||||
|
@JvmStatic
|
||||||
|
fun generateOpenPgpKey(policy: Policy = getPolicy()) = OpenPgpKeyGenerator(policy)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a fresh OpenPGP key ring from predefined templates.
|
* Generate a fresh OpenPGP key ring from predefined templates.
|
||||||
*
|
*
|
||||||
* @return templates
|
* @return templates
|
||||||
*/
|
*/
|
||||||
@JvmStatic fun generateKeyRing() = KeyRingTemplates()
|
@Deprecated(
|
||||||
|
"Deprecated in favor of new API",
|
||||||
|
ReplaceWith("generateOpenPgpKey().buildV4Key().fromTemplate()"))
|
||||||
|
@JvmStatic
|
||||||
|
fun generateKeyRing() = KeyRingTemplates()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build a custom OpenPGP key ring.
|
* Build a custom OpenPGP key ring.
|
||||||
*
|
*
|
||||||
* @return builder
|
* @return builder
|
||||||
*/
|
*/
|
||||||
@JvmStatic fun buildKeyRing() = KeyRingBuilder()
|
@Deprecated("Deprecated in favor of new API", ReplaceWith("generateOpenPgpKey()"))
|
||||||
|
@JvmStatic
|
||||||
|
fun buildKeyRing() = KeyRingBuilder()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read an existing OpenPGP key ring.
|
* Read an existing OpenPGP key ring.
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
|
|
||||||
package org.pgpainless.key.generation
|
package org.pgpainless.key.generation
|
||||||
|
|
||||||
|
import openpgp.toArray
|
||||||
|
import openpgp.toPassphrase
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
import org.bouncycastle.openpgp.PGPSecretKeyRing
|
||||||
import org.pgpainless.algorithm.KeyFlag
|
import org.pgpainless.algorithm.KeyFlag
|
||||||
import org.pgpainless.key.generation.type.KeyType
|
import org.pgpainless.key.generation.type.KeyType
|
||||||
|
@ -30,15 +32,13 @@ class KeyRingTemplates {
|
||||||
length: RsaLength,
|
length: RsaLength,
|
||||||
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
||||||
): PGPSecretKeyRing =
|
): PGPSecretKeyRing =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
OpenPgpKeyGenerator()
|
||||||
.setPrimaryKey(KeyType.RSA(length), listOf(KeyFlag.CERTIFY_OTHER)) {
|
.buildV4Key()
|
||||||
if (userId != null) {
|
.fromTemplate()
|
||||||
addUserId(userId)
|
.composedRsa(
|
||||||
}
|
userId = userId.toArray(),
|
||||||
}
|
length = length,
|
||||||
.addSigningSubkey(KeyType.RSA(length))
|
protector = SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
|
||||||
.addEncryptionSubkey(KeyType.RSA(length))
|
|
||||||
.build(passphrase)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an RSA OpenPGP key consisting of an RSA primary key used for certification, a
|
* Generate an RSA OpenPGP key consisting of an RSA primary key used for certification, a
|
||||||
|
@ -50,14 +50,11 @@ class KeyRingTemplates {
|
||||||
* keys.
|
* keys.
|
||||||
* @return key
|
* @return key
|
||||||
*/
|
*/
|
||||||
fun rsaKeyRing(userId: CharSequence?, length: RsaLength, password: String?): PGPSecretKeyRing =
|
fun rsaKeyRing(
|
||||||
password.let {
|
userId: CharSequence?,
|
||||||
if (it.isNullOrBlank()) {
|
length: RsaLength,
|
||||||
rsaKeyRing(userId, length, Passphrase.emptyPassphrase())
|
password: CharSequence?
|
||||||
} else {
|
): PGPSecretKeyRing = rsaKeyRing(userId, length, password.toPassphrase())
|
||||||
rsaKeyRing(userId, length, Passphrase.fromPassword(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The
|
* Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The
|
||||||
|
@ -75,19 +72,13 @@ class KeyRingTemplates {
|
||||||
length: RsaLength,
|
length: RsaLength,
|
||||||
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
||||||
): PGPSecretKeyRing =
|
): PGPSecretKeyRing =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
OpenPgpKeyGenerator()
|
||||||
.setPrimaryKey(
|
.buildV4Key()
|
||||||
KeyType.RSA(length),
|
.fromTemplate()
|
||||||
listOf(
|
.singleRsa(
|
||||||
KeyFlag.CERTIFY_OTHER,
|
userId = userId.toArray(),
|
||||||
KeyFlag.SIGN_DATA,
|
length = length,
|
||||||
KeyFlag.ENCRYPT_COMMS,
|
protector = SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
|
||||||
KeyFlag.ENCRYPT_STORAGE)) {
|
|
||||||
if (userId != null) {
|
|
||||||
addUserId(userId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.build(passphrase)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The
|
* Creates a simple RSA KeyPair of length {@code length} with user-id {@code userId}. The
|
||||||
|
@ -99,14 +90,8 @@ class KeyRingTemplates {
|
||||||
* @param password Password of the key. Can be null or blank for unencrypted keys.
|
* @param password Password of the key. Can be null or blank for unencrypted keys.
|
||||||
* @return {@link PGPSecretKeyRing} containing the KeyPair.
|
* @return {@link PGPSecretKeyRing} containing the KeyPair.
|
||||||
*/
|
*/
|
||||||
fun simpleRsaKeyRing(userId: CharSequence?, length: RsaLength, password: String?) =
|
fun simpleRsaKeyRing(userId: CharSequence?, length: RsaLength, password: CharSequence?) =
|
||||||
password.let {
|
simpleRsaKeyRing(userId, length, password.toPassphrase())
|
||||||
if (it.isNullOrBlank()) {
|
|
||||||
simpleRsaKeyRing(userId, length, Passphrase.emptyPassphrase())
|
|
||||||
} else {
|
|
||||||
simpleRsaKeyRing(userId, length, Passphrase.fromPassword(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a key ring consisting of an ed25519 EdDSA primary key and a X25519 XDH subkey. The
|
* Creates a key ring consisting of an ed25519 EdDSA primary key and a X25519 XDH subkey. The
|
||||||
|
@ -122,7 +107,8 @@ class KeyRingTemplates {
|
||||||
userId: CharSequence?,
|
userId: CharSequence?,
|
||||||
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
||||||
): PGPSecretKeyRing =
|
): PGPSecretKeyRing =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
OpenPgpKeyGenerator()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(
|
.setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519),
|
KeyType.EDDSA(EdDSACurve._Ed25519),
|
||||||
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) {
|
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) {
|
||||||
|
@ -142,14 +128,8 @@ class KeyRingTemplates {
|
||||||
* @param password Password of the private key. Can be null or blank for an unencrypted key.
|
* @param password Password of the private key. Can be null or blank for an unencrypted key.
|
||||||
* @return {@link PGPSecretKeyRing} containing the key pairs.
|
* @return {@link PGPSecretKeyRing} containing the key pairs.
|
||||||
*/
|
*/
|
||||||
fun simpleEcKeyRing(userId: CharSequence?, password: String?): PGPSecretKeyRing =
|
fun simpleEcKeyRing(userId: CharSequence?, password: CharSequence?): PGPSecretKeyRing =
|
||||||
password.let {
|
simpleEcKeyRing(userId, password.toPassphrase())
|
||||||
if (it.isNullOrBlank()) {
|
|
||||||
simpleEcKeyRing(userId, Passphrase.emptyPassphrase())
|
|
||||||
} else {
|
|
||||||
simpleEcKeyRing(userId, Passphrase.fromPassword(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to
|
* Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to
|
||||||
|
@ -164,17 +144,12 @@ class KeyRingTemplates {
|
||||||
userId: CharSequence?,
|
userId: CharSequence?,
|
||||||
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
passphrase: Passphrase = Passphrase.emptyPassphrase()
|
||||||
): PGPSecretKeyRing =
|
): PGPSecretKeyRing =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
OpenPgpKeyGenerator()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) {
|
.buildV4Key()
|
||||||
if (userId != null) {
|
.fromTemplate()
|
||||||
addUserId(userId)
|
.ed25519Curve25519(
|
||||||
}
|
userId = userId.toArray(),
|
||||||
}
|
protector = SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
|
||||||
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
|
|
||||||
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
|
||||||
.build(
|
|
||||||
if (passphrase.isEmpty) SecretKeyRingProtector.unprotectedKeys()
|
|
||||||
else SecretKeyRingProtector.unlockAnyKeyWith(passphrase))
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to
|
* Generate a modern PGP key ring consisting of an ed25519 EdDSA primary key which is used to
|
||||||
|
@ -184,12 +159,6 @@ class KeyRingTemplates {
|
||||||
* @param password passphrase for the private key. Can be null or blank for an unencrypted key.
|
* @param password passphrase for the private key. Can be null or blank for an unencrypted key.
|
||||||
* @return key ring
|
* @return key ring
|
||||||
*/
|
*/
|
||||||
fun modernKeyRing(userId: CharSequence?, password: String?): PGPSecretKeyRing =
|
fun modernKeyRing(userId: CharSequence?, password: CharSequence?): PGPSecretKeyRing =
|
||||||
password.let {
|
modernKeyRing(userId, password.toPassphrase())
|
||||||
if (it.isNullOrBlank()) {
|
|
||||||
modernKeyRing(userId, Passphrase.emptyPassphrase())
|
|
||||||
} else {
|
|
||||||
modernKeyRing(userId, Passphrase.fromPassword(it))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.pgpainless.bouncycastle.extensions.plusCertification
|
||||||
import org.pgpainless.implementation.ImplementationFactory
|
import org.pgpainless.implementation.ImplementationFactory
|
||||||
import org.pgpainless.key.generation.DefinePrimaryKey.PrimaryKeyBuilder
|
import org.pgpainless.key.generation.DefinePrimaryKey.PrimaryKeyBuilder
|
||||||
import org.pgpainless.key.generation.DefineSubkeys.SubkeyBuilder
|
import org.pgpainless.key.generation.DefineSubkeys.SubkeyBuilder
|
||||||
|
import org.pgpainless.key.generation.OpenPgpKeyTemplates.Companion.v4
|
||||||
import org.pgpainless.key.generation.type.KeyType
|
import org.pgpainless.key.generation.type.KeyType
|
||||||
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
|
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
|
||||||
import org.pgpainless.key.generation.type.rsa.RsaLength
|
import org.pgpainless.key.generation.type.rsa.RsaLength
|
||||||
|
@ -37,8 +38,16 @@ import org.pgpainless.signature.builder.SubkeyBindingSignatureBuilder
|
||||||
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
|
import org.pgpainless.signature.subpackets.SelfSignatureSubpackets
|
||||||
import org.pgpainless.util.Passphrase
|
import org.pgpainless.util.Passphrase
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function block that is applied to the OpenPGP [PrimaryKeyBuilder]. Within this block, you add
|
||||||
|
* User-IDs, User-Attributes and Direct-Key signatures on the primary key.
|
||||||
|
*/
|
||||||
typealias PrimaryKeyBlock = (PrimaryKeyBuilder.() -> Unit)
|
typealias PrimaryKeyBlock = (PrimaryKeyBuilder.() -> Unit)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function block that is applied to an OpenPGP [SubkeyBuilder]. Here you typically add
|
||||||
|
* subkey-binding signatures.
|
||||||
|
*/
|
||||||
typealias SubkeyBlock = (SubkeyBuilder.() -> Unit)
|
typealias SubkeyBlock = (SubkeyBuilder.() -> Unit)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,25 +63,20 @@ typealias SubkeyBlock = (SubkeyBuilder.() -> Unit)
|
||||||
* You can switch from the opinionated API to the unopinionated API by calling `unopinionated()` on
|
* You can switch from the opinionated API to the unopinionated API by calling `unopinionated()` on
|
||||||
* the builder.
|
* the builder.
|
||||||
*/
|
*/
|
||||||
class OpenPgpKeyGenerator internal constructor() {
|
class OpenPgpKeyGenerator(private val policy: Policy = PGPainless.getPolicy()) {
|
||||||
|
|
||||||
companion object {
|
/**
|
||||||
/**
|
* Build a version 4 OpenPGP secret key.
|
||||||
* Build a version 4 OpenPGP secret key.
|
*
|
||||||
*
|
* @param creationTime creation time for the secret key
|
||||||
* @param policy policy to ensure algorithm compliance and to determine default algorithms
|
* @param preferences suite of algorithm preferences and enabled features
|
||||||
* @param creationTime creation time for the secret key
|
*/
|
||||||
* @param preferences suite of algorithm preferences and enabled features
|
@JvmOverloads
|
||||||
*/
|
fun buildV4Key(
|
||||||
@JvmStatic
|
creationTime: Date = Date(),
|
||||||
@JvmOverloads
|
preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
|
||||||
fun buildV4Key(
|
): OpinionatedDefinePrimaryKeyV4 {
|
||||||
policy: Policy = PGPainless.getPolicy(),
|
return OpinionatedDefinePrimaryKeyV4(policy, creationTime, preferences)
|
||||||
creationTime: Date = Date(),
|
|
||||||
preferences: AlgorithmSuite = policy.keyGenerationAlgorithmSuite
|
|
||||||
): OpinionatedDefinePrimaryKeyV4 {
|
|
||||||
return OpinionatedDefinePrimaryKeyV4(policy, creationTime, preferences)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -211,6 +215,14 @@ internal constructor(val policy: Policy, val creationTime: Date, val preferences
|
||||||
// Do nothing
|
// Do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a [OpenPgpKeyTemplates] object which provides factory methods for generating OpenPGP
|
||||||
|
* keys from templates.
|
||||||
|
*
|
||||||
|
* @return templates
|
||||||
|
*/
|
||||||
|
abstract fun fromTemplate(): OpenPgpKeyTemplates
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that can be applied to the primary key.
|
* Function that can be applied to the primary key.
|
||||||
*
|
*
|
||||||
|
@ -1094,11 +1106,13 @@ class PrimaryKeyBuilderV4 internal constructor(keyPair: PGPKeyPair, builder: Def
|
||||||
this.keyPair
|
this.keyPair
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun fromTemplate(): OpenPgpKeyTemplates.V4 = v4()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Templates for OpenPGP key generation. */
|
/** Templates for OpenPGP key generation. */
|
||||||
class OpenPgpKeyTemplates private constructor() {
|
open class OpenPgpKeyTemplates private constructor() {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
|
@ -1111,7 +1125,7 @@ class OpenPgpKeyTemplates private constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Templates for version 4 OpenPGP keys. Version 4 keys are compliant to RFC4880. */
|
/** Templates for version 4 OpenPGP keys. Version 4 keys are compliant to RFC4880. */
|
||||||
class V4 internal constructor() {
|
class V4 : OpenPgpKeyTemplates() {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an OpenPGP key that consists of an Ed25519 primary key used for certification of
|
* Generate an OpenPGP key that consists of an Ed25519 primary key used for certification of
|
||||||
|
@ -1123,9 +1137,11 @@ class OpenPgpKeyTemplates private constructor() {
|
||||||
*/
|
*/
|
||||||
fun ed25519Curve25519(
|
fun ed25519Curve25519(
|
||||||
vararg userId: CharSequence,
|
vararg userId: CharSequence,
|
||||||
creationTime: Date = Date()
|
creationTime: Date = Date(),
|
||||||
|
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
|
||||||
): PGPSecretKeyRing =
|
): PGPSecretKeyRing =
|
||||||
OpenPgpKeyGenerator.buildV4Key(creationTime = creationTime)
|
OpenPgpKeyGenerator()
|
||||||
|
.buildV4Key(creationTime = creationTime)
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
// Add UserIDs
|
// Add UserIDs
|
||||||
userId.forEachIndexed { index, uid ->
|
userId.forEachIndexed { index, uid ->
|
||||||
|
@ -1145,7 +1161,7 @@ class OpenPgpKeyTemplates private constructor() {
|
||||||
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.addSigningSubkey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
// encryption key
|
// encryption key
|
||||||
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
|
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
|
||||||
.build()
|
.build(protector)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an OpenPGP key that consists of an RSA primary key used for certification of
|
* Generate an OpenPGP key that consists of an RSA primary key used for certification of
|
||||||
|
@ -1159,9 +1175,11 @@ class OpenPgpKeyTemplates private constructor() {
|
||||||
fun composedRsa(
|
fun composedRsa(
|
||||||
vararg userId: CharSequence,
|
vararg userId: CharSequence,
|
||||||
creationTime: Date = Date(),
|
creationTime: Date = Date(),
|
||||||
length: RsaLength = RsaLength._4096
|
length: RsaLength = RsaLength._4096,
|
||||||
|
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
|
||||||
): PGPSecretKeyRing =
|
): PGPSecretKeyRing =
|
||||||
OpenPgpKeyGenerator.buildV4Key(creationTime = creationTime)
|
OpenPgpKeyGenerator()
|
||||||
|
.buildV4Key(creationTime = creationTime)
|
||||||
.setPrimaryKey(KeyType.RSA(length)) {
|
.setPrimaryKey(KeyType.RSA(length)) {
|
||||||
// Add UserIDs
|
// Add UserIDs
|
||||||
userId.forEachIndexed { index, uid ->
|
userId.forEachIndexed { index, uid ->
|
||||||
|
@ -1181,7 +1199,7 @@ class OpenPgpKeyTemplates private constructor() {
|
||||||
.addSigningSubkey(KeyType.RSA(length))
|
.addSigningSubkey(KeyType.RSA(length))
|
||||||
// encryption key
|
// encryption key
|
||||||
.addEncryptionSubkey(KeyType.RSA(length))
|
.addEncryptionSubkey(KeyType.RSA(length))
|
||||||
.build()
|
.build(protector)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate an OpenPGP key consisting of a single RSA key that is used for certification of
|
* Generate an OpenPGP key consisting of a single RSA key that is used for certification of
|
||||||
|
@ -1194,9 +1212,11 @@ class OpenPgpKeyTemplates private constructor() {
|
||||||
fun singleRsa(
|
fun singleRsa(
|
||||||
vararg userId: CharSequence,
|
vararg userId: CharSequence,
|
||||||
creationTime: Date = Date(),
|
creationTime: Date = Date(),
|
||||||
length: RsaLength = RsaLength._4096
|
length: RsaLength = RsaLength._4096,
|
||||||
|
protector: SecretKeyRingProtector = SecretKeyRingProtector.unprotectedKeys()
|
||||||
): PGPSecretKeyRing =
|
): PGPSecretKeyRing =
|
||||||
OpenPgpKeyGenerator.buildV4Key(creationTime = creationTime)
|
OpenPgpKeyGenerator()
|
||||||
|
.buildV4Key(creationTime = creationTime)
|
||||||
.setPrimaryKey(KeyType.RSA(length)) {
|
.setPrimaryKey(KeyType.RSA(length)) {
|
||||||
userId.forEach { addUserId(it) }
|
userId.forEach { addUserId(it) }
|
||||||
addDirectKeySignature(
|
addDirectKeySignature(
|
||||||
|
@ -1208,6 +1228,6 @@ class OpenPgpKeyTemplates private constructor() {
|
||||||
KeyFlag.ENCRYPT_STORAGE)
|
KeyFlag.ENCRYPT_STORAGE)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
.build()
|
.build(protector)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ import org.pgpainless.PGPainless
|
||||||
import org.pgpainless.algorithm.HashAlgorithm
|
import org.pgpainless.algorithm.HashAlgorithm
|
||||||
import org.pgpainless.algorithm.KeyFlag
|
import org.pgpainless.algorithm.KeyFlag
|
||||||
import org.pgpainless.bouncycastle.extensions.directKeySignatures
|
import org.pgpainless.bouncycastle.extensions.directKeySignatures
|
||||||
import org.pgpainless.key.generation.OpenPgpKeyGenerator
|
|
||||||
import org.pgpainless.key.generation.type.KeyType
|
import org.pgpainless.key.generation.type.KeyType
|
||||||
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
|
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
|
||||||
import org.pgpainless.key.generation.type.xdh.XDHSpec
|
import org.pgpainless.key.generation.type.xdh.XDHSpec
|
||||||
|
@ -21,19 +20,26 @@ class KeyWithInacceptableSelfSignatureTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `key with inacceptable self-signature is not usable`() {
|
fun `key with inacceptable self-signature is not usable`() {
|
||||||
val genPolicy = Policy().apply {
|
val genPolicy =
|
||||||
certificationSignatureHashAlgorithmPolicy = Policy.HashAlgorithmPolicy(
|
Policy().apply {
|
||||||
HashAlgorithm.SHA1, listOf(HashAlgorithm.SHA1))
|
certificationSignatureHashAlgorithmPolicy =
|
||||||
}
|
Policy.HashAlgorithmPolicy(HashAlgorithm.SHA1, listOf(HashAlgorithm.SHA1))
|
||||||
|
}
|
||||||
|
|
||||||
val key = OpenPgpKeyGenerator.buildV4Key(genPolicy)
|
val key =
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA))
|
PGPainless.generateOpenPgpKey(genPolicy)
|
||||||
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
|
.buildV4Key()
|
||||||
.build()
|
.setPrimaryKey(
|
||||||
|
KeyType.EDDSA(EdDSACurve._Ed25519),
|
||||||
|
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA))
|
||||||
|
.addEncryptionSubkey(KeyType.XDH(XDHSpec._X25519))
|
||||||
|
.build()
|
||||||
|
|
||||||
assertEquals(HashAlgorithm.SHA1,
|
assertEquals(
|
||||||
key.publicKey.directKeySignatures.single().hashAlgorithm
|
HashAlgorithm.SHA1,
|
||||||
.let { HashAlgorithm.requireFromId(it) })
|
key.publicKey.directKeySignatures.single().hashAlgorithm.let {
|
||||||
|
HashAlgorithm.requireFromId(it)
|
||||||
|
})
|
||||||
|
|
||||||
val info = PGPainless.inspectKeyRing(key)
|
val info = PGPainless.inspectKeyRing(key)
|
||||||
assertFalse(info.isUsableForSigning)
|
assertFalse(info.isUsableForSigning)
|
||||||
|
|
|
@ -24,7 +24,8 @@ class MalformedKeyGenerationTest {
|
||||||
fun malformedPrimaryUserIdSubpacket() {
|
fun malformedPrimaryUserIdSubpacket() {
|
||||||
val userId = "Alice <alice@pgpainless.org>"
|
val userId = "Alice <alice@pgpainless.org>"
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key(Policy())
|
PGPainless.generateOpenPgpKey(Policy())
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId(
|
addUserId(
|
||||||
userId,
|
userId,
|
||||||
|
@ -43,7 +44,8 @@ class MalformedKeyGenerationTest {
|
||||||
@Test
|
@Test
|
||||||
fun malformedExportableSubpacket() {
|
fun malformedExportableSubpacket() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key(Policy())
|
PGPainless.generateOpenPgpKey(Policy())
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId(
|
addUserId(
|
||||||
"Alice <alice@pgpainless.org>",
|
"Alice <alice@pgpainless.org>",
|
||||||
|
@ -62,7 +64,8 @@ class MalformedKeyGenerationTest {
|
||||||
@Test
|
@Test
|
||||||
fun malformedRevocableSubpacket() {
|
fun malformedRevocableSubpacket() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key(Policy())
|
PGPainless.generateOpenPgpKey(Policy())
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId(
|
addUserId(
|
||||||
"Alice <alice@pgpainless.org>",
|
"Alice <alice@pgpainless.org>",
|
||||||
|
@ -82,7 +85,8 @@ class MalformedKeyGenerationTest {
|
||||||
fun primaryUserIdOnDirectKeySig() {
|
fun primaryUserIdOnDirectKeySig() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(
|
.setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519),
|
KeyType.EDDSA(EdDSACurve._Ed25519),
|
||||||
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) {
|
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.SIGN_DATA)) {
|
||||||
|
|
|
@ -38,7 +38,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `minimal call with opinionated builder adds a default DK sig but no user info`() {
|
fun `minimal call with opinionated builder adds a default DK sig but no user info`() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -55,7 +56,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `minimal call with unopinionated builder does not add a default DK sig`() {
|
fun `minimal call with unopinionated builder does not add a default DK sig`() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.unopinionated()
|
.unopinionated()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.build()
|
.build()
|
||||||
|
@ -68,7 +70,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `adding a direct-key signature with the opinionated builder omits the default DK sig`() {
|
fun `adding a direct-key signature with the opinionated builder omits the default DK sig`() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addDirectKeySignature() // "overwrites" the default dk sig
|
addDirectKeySignature() // "overwrites" the default dk sig
|
||||||
}
|
}
|
||||||
|
@ -82,7 +85,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `adding two user-ids will mark the first one as primary`() {
|
fun `adding two user-ids will mark the first one as primary`() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId("Primary <primary@example.com>")
|
addUserId("Primary <primary@example.com>")
|
||||||
addUserId("Non Primary <non-primary@example.com>")
|
addUserId("Non Primary <non-primary@example.com>")
|
||||||
|
@ -96,7 +100,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `adding two user-ids but mark the first as non-primary will mark the second one as primary`() {
|
fun `adding two user-ids but mark the first as non-primary will mark the second one as primary`() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId(
|
addUserId(
|
||||||
"Non Primary <non-primary@example.com>",
|
"Non Primary <non-primary@example.com>",
|
||||||
|
@ -126,7 +131,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
.generate()
|
.generate()
|
||||||
|
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserAttribute(attr1) // primary, since it is the first
|
addUserAttribute(attr1) // primary, since it is the first
|
||||||
addUserAttribute(attr2) // non-primary
|
addUserAttribute(attr2) // non-primary
|
||||||
|
@ -160,7 +166,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
.generate()
|
.generate()
|
||||||
|
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId(userId)
|
addUserId(userId)
|
||||||
addUserAttribute(userAttribute)
|
addUserAttribute(userAttribute)
|
||||||
|
@ -186,7 +193,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `adding signing key will add embedded back-signature`() {
|
fun `adding signing key will add embedded back-signature`() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.SIGN_DATA))
|
.addSubkey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.SIGN_DATA))
|
||||||
.build()
|
.build()
|
||||||
|
@ -205,7 +213,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun testUnopinionatedV4() {
|
fun testUnopinionatedV4() {
|
||||||
// Unopinionated
|
// Unopinionated
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.unopinionated()
|
.unopinionated()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addDirectKeySignature()
|
addDirectKeySignature()
|
||||||
|
@ -221,7 +230,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun testOpinionatedV4() {
|
fun testOpinionatedV4() {
|
||||||
// Opinionated
|
// Opinionated
|
||||||
val time = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
val time = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
||||||
OpenPgpKeyGenerator.buildV4Key(creationTime = time)
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key(creationTime = time)
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), listOf(KeyFlag.CERTIFY_OTHER)) {
|
||||||
addUserId("Alice <alice@pgpainless.org>")
|
addUserId("Alice <alice@pgpainless.org>")
|
||||||
}
|
}
|
||||||
|
@ -254,7 +264,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun test() {
|
fun test() {
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.RSA(RsaLength._3072), keyFlags = listOf(KeyFlag.CERTIFY_OTHER))
|
.setPrimaryKey(KeyType.RSA(RsaLength._3072), keyFlags = listOf(KeyFlag.CERTIFY_OTHER))
|
||||||
.build()
|
.build()
|
||||||
.toAsciiArmor()
|
.toAsciiArmor()
|
||||||
|
@ -268,7 +279,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) })
|
Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) })
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
// opinionated builder verifies PK parameters
|
// opinionated builder verifies PK parameters
|
||||||
.setPrimaryKey(KeyType.RSA(RsaLength._2048)) // too weak
|
.setPrimaryKey(KeyType.RSA(RsaLength._2048)) // too weak
|
||||||
}
|
}
|
||||||
|
@ -280,7 +292,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
policy.publicKeyAlgorithmPolicy =
|
policy.publicKeyAlgorithmPolicy =
|
||||||
Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) })
|
Policy.PublicKeyAlgorithmPolicy(buildMap { put(PublicKeyAlgorithm.RSA_GENERAL, 3072) })
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.unopinionated() // unopinionated builder allows for non-compliant configurations
|
.unopinionated() // unopinionated builder allows for non-compliant configurations
|
||||||
.setPrimaryKey(KeyType.RSA(RsaLength._2048))
|
.setPrimaryKey(KeyType.RSA(RsaLength._2048))
|
||||||
}
|
}
|
||||||
|
@ -288,7 +301,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `skip default DirectKey signature will not add one`() {
|
fun `skip default DirectKey signature will not add one`() {
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { skipDefaultSignature() }
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) { skipDefaultSignature() }
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -304,7 +318,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun `opinionated add UserID with weak hash algorithm fails`() {
|
fun `opinionated add UserID with weak hash algorithm fails`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1)
|
addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1)
|
||||||
}
|
}
|
||||||
|
@ -314,7 +328,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `unopinionated add UserID with weak hash algorithm is okay`() {
|
fun `unopinionated add UserID with weak hash algorithm is okay`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy).unopinionated().setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key().unopinionated().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1)
|
addUserId("Alice <alice@example.org>", hashAlgorithm = HashAlgorithm.SHA1)
|
||||||
}
|
}
|
||||||
|
@ -324,7 +338,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun `opinionated add UserAttribute with weak hash algorithm fails`() {
|
fun `opinionated add UserAttribute with weak hash algorithm fails`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserAttribute(
|
addUserAttribute(
|
||||||
PGPUserAttributeSubpacketVectorGenerator().generate(),
|
PGPUserAttributeSubpacketVectorGenerator().generate(),
|
||||||
|
@ -336,7 +350,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `unopinionated add UserAttribute with weak hash algorithm is okay`() {
|
fun `unopinionated add UserAttribute with weak hash algorithm is okay`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy).unopinionated().setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key().unopinionated().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserAttribute(
|
addUserAttribute(
|
||||||
PGPUserAttributeSubpacketVectorGenerator().generate(),
|
PGPUserAttributeSubpacketVectorGenerator().generate(),
|
||||||
|
@ -348,7 +362,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun `opinionated add DK sig with weak hash algorithm fails`() {
|
fun `opinionated add DK sig with weak hash algorithm fails`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1)
|
addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1)
|
||||||
}
|
}
|
||||||
|
@ -358,7 +372,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
@Test
|
@Test
|
||||||
fun `unopinionated add DK sig with weak hash algorithm is okay`() {
|
fun `unopinionated add DK sig with weak hash algorithm is okay`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy).unopinionated().setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key().unopinionated().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1)
|
addDirectKeySignature(hashAlgorithm = HashAlgorithm.SHA1)
|
||||||
}
|
}
|
||||||
|
@ -371,7 +385,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1).setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId("Alice <alice@example.org>", bindingTime = t0)
|
addUserId("Alice <alice@example.org>", bindingTime = t0)
|
||||||
}
|
}
|
||||||
|
@ -384,7 +398,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1).unopinionated().setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).unopinionated().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserId("Alice <alice@example.org>", bindingTime = t0)
|
addUserId("Alice <alice@example.org>", bindingTime = t0)
|
||||||
}
|
}
|
||||||
|
@ -397,7 +411,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1).setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserAttribute(
|
addUserAttribute(
|
||||||
PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0)
|
PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0)
|
||||||
|
@ -411,7 +425,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1).unopinionated().setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).unopinionated().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addUserAttribute(
|
addUserAttribute(
|
||||||
PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0)
|
PGPUserAttributeSubpacketVectorGenerator().generate(), bindingTime = t0)
|
||||||
|
@ -425,7 +439,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1).setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addDirectKeySignature(bindingTime = t0)
|
addDirectKeySignature(bindingTime = t0)
|
||||||
}
|
}
|
||||||
|
@ -438,7 +452,7 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1).unopinionated().setPrimaryKey(
|
PGPainless.generateOpenPgpKey(policy).buildV4Key(t1).unopinionated().setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addDirectKeySignature(bindingTime = t0)
|
addDirectKeySignature(bindingTime = t0)
|
||||||
}
|
}
|
||||||
|
@ -451,7 +465,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key(t1)
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
|
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
|
||||||
}
|
}
|
||||||
|
@ -463,7 +478,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key(t1)
|
||||||
.unopinionated()
|
.unopinionated()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
|
.addSubkey(KeyType.XDH(XDHSpec._X25519), null, t0)
|
||||||
|
@ -476,7 +492,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key(t1)
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) }
|
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) }
|
||||||
}
|
}
|
||||||
|
@ -488,7 +505,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
val t0 = DateUtil.parseUTCDate("2024-01-01 00:00:00 UTC")
|
||||||
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
val t1 = DateUtil.parseUTCDate("2024-02-01 00:00:00 UTC")
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy, t1)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key(t1)
|
||||||
.unopinionated()
|
.unopinionated()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) }
|
.addSubkey(KeyType.XDH(XDHSpec._X25519)) { addBindingSignature(bindingTime = t0) }
|
||||||
|
@ -499,7 +517,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(KeyType.XDH(XDHSpec._X25519)) {
|
.addSubkey(KeyType.XDH(XDHSpec._X25519)) {
|
||||||
addBindingSignature(hashAlgorithm = HashAlgorithm.SHA1)
|
addBindingSignature(hashAlgorithm = HashAlgorithm.SHA1)
|
||||||
|
@ -511,7 +530,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun `unopinionated add subkey with weak binding signature hash algorithm is okay`() {
|
fun `unopinionated add subkey with weak binding signature hash algorithm is okay`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.unopinionated()
|
.unopinionated()
|
||||||
.addSubkey(KeyType.XDH(XDHSpec._X25519)) {
|
.addSubkey(KeyType.XDH(XDHSpec._X25519)) {
|
||||||
|
@ -524,7 +544,9 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy).setPrimaryKey(KeyType.XDH(XDHSpec._X25519))
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
|
.setPrimaryKey(KeyType.XDH(XDHSpec._X25519))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -533,7 +555,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(
|
.setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519),
|
KeyType.EDDSA(EdDSACurve._Ed25519),
|
||||||
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.ENCRYPT_STORAGE))
|
listOf(KeyFlag.CERTIFY_OTHER, KeyFlag.ENCRYPT_STORAGE))
|
||||||
|
@ -544,7 +567,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun `unopinionated set primary key to sign-only algorithm but with encryption flag is okay`() {
|
fun `unopinionated set primary key to sign-only algorithm but with encryption flag is okay`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.unopinionated()
|
.unopinionated()
|
||||||
.setPrimaryKey(
|
.setPrimaryKey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519),
|
KeyType.EDDSA(EdDSACurve._Ed25519),
|
||||||
|
@ -556,7 +580,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), keyFlags = null)
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519), keyFlags = null)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -568,7 +593,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(
|
.addSubkey(
|
||||||
KeyType.XDH(XDHSpec._X25519), listOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.SIGN_DATA))
|
KeyType.XDH(XDHSpec._X25519), listOf(KeyFlag.ENCRYPT_COMMS, KeyFlag.SIGN_DATA))
|
||||||
|
@ -580,7 +606,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
assertThrows<IllegalArgumentException> {
|
assertThrows<IllegalArgumentException> {
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.addSubkey(
|
.addSubkey(
|
||||||
KeyType.EDDSA(EdDSACurve._Ed25519),
|
KeyType.EDDSA(EdDSACurve._Ed25519),
|
||||||
|
@ -592,7 +619,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun `unopinionated add sign-only sukey but with additional encryption flag is okay`() {
|
fun `unopinionated add sign-only sukey but with additional encryption flag is okay`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519))
|
||||||
.unopinionated()
|
.unopinionated()
|
||||||
.addSubkey(
|
.addSubkey(
|
||||||
|
@ -609,7 +637,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
"ffd8ffe000104a46494600010101004800480000ffdb004300030202020202030202020303030304060404040404080606050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b080001000101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9")
|
"ffd8ffe000104a46494600010101004800480000ffdb004300030202020202030202020303030304060404040404080606050609080a0a090809090a0c0f0c0a0b0e0b09090d110d0e0f101011100a0c12131210130f101010ffc9000b080001000101011100ffcc000600101005ffda0008010100003f00d2cf20ffd9")
|
||||||
|
|
||||||
val key =
|
val key =
|
||||||
OpenPgpKeyGenerator.buildV4Key()
|
PGPainless.generateOpenPgpKey()
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addImageAttribute(jpegBytes.inputStream())
|
addImageAttribute(jpegBytes.inputStream())
|
||||||
}
|
}
|
||||||
|
@ -622,7 +651,8 @@ class OpenPgpKeyGeneratorTest {
|
||||||
fun `generate key with expiration time`() {
|
fun `generate key with expiration time`() {
|
||||||
val policy = Policy()
|
val policy = Policy()
|
||||||
|
|
||||||
OpenPgpKeyGenerator.buildV4Key(policy)
|
PGPainless.generateOpenPgpKey(policy)
|
||||||
|
.buildV4Key()
|
||||||
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
.setPrimaryKey(KeyType.EDDSA(EdDSACurve._Ed25519)) {
|
||||||
addDirectKeySignature(
|
addDirectKeySignature(
|
||||||
SelfSignatureSubpackets.applyHashed {
|
SelfSignatureSubpackets.applyHashed {
|
||||||
|
|
Loading…
Reference in New Issue