mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-19 10:52:05 +01:00
Kotlin conversion: KeyInfo
This commit is contained in:
parent
b6e47d7739
commit
8fe9d250a8
5 changed files with 143 additions and 141 deletions
|
@ -1,139 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2020 Paul Schaub <vanitasvitae@fsfe.org>, 2021 Flowcrypt a.s.
|
|
||||||
//
|
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
package org.pgpainless.key.info;
|
|
||||||
|
|
||||||
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
|
|
||||||
import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers;
|
|
||||||
import org.bouncycastle.bcpg.ECDHPublicBCPGKey;
|
|
||||||
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey;
|
|
||||||
import org.bouncycastle.bcpg.ECPublicBCPGKey;
|
|
||||||
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey;
|
|
||||||
import org.bouncycastle.bcpg.S2K;
|
|
||||||
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil;
|
|
||||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
|
||||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
|
||||||
import org.pgpainless.algorithm.PublicKeyAlgorithm;
|
|
||||||
import org.pgpainless.key.generation.type.eddsa.EdDSACurve;
|
|
||||||
|
|
||||||
public class KeyInfo {
|
|
||||||
|
|
||||||
private final PGPSecretKey secretKey;
|
|
||||||
private final PGPPublicKey publicKey;
|
|
||||||
|
|
||||||
public KeyInfo(PGPSecretKey secretKey) {
|
|
||||||
this.secretKey = secretKey;
|
|
||||||
this.publicKey = secretKey.getPublicKey();
|
|
||||||
}
|
|
||||||
|
|
||||||
public KeyInfo(PGPPublicKey publicKey) {
|
|
||||||
this.publicKey = publicKey;
|
|
||||||
this.secretKey = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCurveName() {
|
|
||||||
return getCurveName(publicKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns indication that a contained secret key is encrypted.
|
|
||||||
*
|
|
||||||
* @return true if secret key is encrypted, false if secret key is not encrypted or there is public key only.
|
|
||||||
*/
|
|
||||||
public boolean isEncrypted() {
|
|
||||||
return secretKey != null && isEncrypted(secretKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns indication that a contained secret key is not encrypted.
|
|
||||||
*
|
|
||||||
* @return true if secret key is not encrypted or there is public key only, false if secret key is encrypted.
|
|
||||||
*/
|
|
||||||
public boolean isDecrypted() {
|
|
||||||
return secretKey == null || isDecrypted(secretKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns indication that a contained secret key has S2K of a type GNU_DUMMY_S2K.
|
|
||||||
*
|
|
||||||
* @return true if secret key has S2K of a type GNU_DUMMY_S2K, false if there is public key only,
|
|
||||||
* or S2K on the secret key is absent or not of a type GNU_DUMMY_S2K.
|
|
||||||
*/
|
|
||||||
public boolean hasDummyS2K() {
|
|
||||||
return secretKey != null && hasDummyS2K(secretKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getCurveName(PGPPublicKey publicKey) {
|
|
||||||
PublicKeyAlgorithm algorithm = PublicKeyAlgorithm.requireFromId(publicKey.getAlgorithm());
|
|
||||||
ECPublicBCPGKey key;
|
|
||||||
switch (algorithm) {
|
|
||||||
case ECDSA: {
|
|
||||||
key = (ECDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ECDH: {
|
|
||||||
key = (ECDHPublicBCPGKey) publicKey.getPublicKeyPacket().getKey();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case EDDSA: {
|
|
||||||
key = (EdDSAPublicBCPGKey) publicKey.getPublicKeyPacket().getKey();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Not an elliptic curve public key (" + algorithm + ")");
|
|
||||||
}
|
|
||||||
return getCurveName(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String getCurveName(ECPublicBCPGKey key) {
|
|
||||||
ASN1ObjectIdentifier identifier = key.getCurveOID();
|
|
||||||
|
|
||||||
String curveName = ECUtil.getCurveName(identifier);
|
|
||||||
if (curveName != null) {
|
|
||||||
return curveName;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Workaround for ECUtil not recognizing ed25519
|
|
||||||
// see https://github.com/bcgit/bc-java/issues/1087
|
|
||||||
// UPDATE: Apparently 1087 is not fixed properly with BC 1.71
|
|
||||||
// See https://github.com/bcgit/bc-java/issues/1142
|
|
||||||
// TODO: Remove once BC comes out with a fix.
|
|
||||||
if (identifier.equals(GNUObjectIdentifiers.Ed25519)) {
|
|
||||||
return EdDSACurve._Ed25519.getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns indication that a secret key is encrypted.
|
|
||||||
*
|
|
||||||
* @param secretKey A secret key to examine.
|
|
||||||
* @return true if secret key is encrypted, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean isEncrypted(PGPSecretKey secretKey) {
|
|
||||||
return secretKey.getS2KUsage() != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns indication that a secret key is not encrypted.
|
|
||||||
*
|
|
||||||
* @param secretKey A secret key to examine.
|
|
||||||
* @return true if secret key is encrypted, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean isDecrypted(PGPSecretKey secretKey) {
|
|
||||||
return secretKey.getS2KUsage() == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns indication that a secret key has S2K of a type GNU_DUMMY_S2K.
|
|
||||||
*
|
|
||||||
* @param secretKey A secret key to examine.
|
|
||||||
* @return true if secret key has S2K of a type GNU_DUMMY_S2K, false otherwise.
|
|
||||||
*/
|
|
||||||
public static boolean hasDummyS2K(PGPSecretKey secretKey) {
|
|
||||||
final S2K s2k = secretKey.getS2K();
|
|
||||||
return s2k != null && s2k.getType() == S2K.GNU_DUMMY_S2K;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.bouncycastle.extensions
|
||||||
|
|
||||||
|
import org.bouncycastle.asn1.gnu.GNUObjectIdentifiers
|
||||||
|
import org.bouncycastle.bcpg.ECDHPublicBCPGKey
|
||||||
|
import org.bouncycastle.bcpg.ECDSAPublicBCPGKey
|
||||||
|
import org.bouncycastle.bcpg.EdDSAPublicBCPGKey
|
||||||
|
import org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey
|
||||||
|
import org.pgpainless.algorithm.PublicKeyAlgorithm
|
||||||
|
import org.pgpainless.key.generation.type.eddsa.EdDSACurve
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For secret keys of types [PublicKeyAlgorithm.ECDSA], [PublicKeyAlgorithm.ECDH] and [PublicKeyAlgorithm.EDDSA],
|
||||||
|
* this method returns the name of the underlying elliptic curve.
|
||||||
|
*
|
||||||
|
* For other key types or unknown curves, this method throws an [IllegalArgumentException].
|
||||||
|
*
|
||||||
|
* @return curve name
|
||||||
|
*/
|
||||||
|
fun PGPPublicKey.getCurveName(): String {
|
||||||
|
PublicKeyAlgorithm.requireFromId(algorithm)
|
||||||
|
.let {
|
||||||
|
when (it) {
|
||||||
|
PublicKeyAlgorithm.ECDSA -> publicKeyPacket.key as ECDSAPublicBCPGKey
|
||||||
|
PublicKeyAlgorithm.ECDH -> publicKeyPacket.key as ECDHPublicBCPGKey
|
||||||
|
PublicKeyAlgorithm.EDDSA -> publicKeyPacket.key as EdDSAPublicBCPGKey
|
||||||
|
else -> throw IllegalArgumentException("No an elliptic curve public key ($it).")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.let { if (it.curveOID == GNUObjectIdentifiers.Ed25519) return EdDSACurve._Ed25519.curveName else it.curveOID}
|
||||||
|
.let { it to ECUtil.getCurveName(it) }
|
||||||
|
.let { if (it.second != null) return it.second else throw IllegalArgumentException("Unknown curve: ${it.first}") }
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.bouncycastle.extensions
|
||||||
|
|
||||||
|
import org.bouncycastle.bcpg.S2K
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns indication that the secret key is encrypted.
|
||||||
|
*
|
||||||
|
* @return true if secret key is encrypted, false otherwise.
|
||||||
|
*/
|
||||||
|
fun PGPSecretKey?.isEncrypted(): Boolean = (this != null) && (s2KUsage != 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns indication that the secret key is not encrypted.
|
||||||
|
*
|
||||||
|
* @return true if secret key is encrypted, false otherwise.
|
||||||
|
*/
|
||||||
|
fun PGPSecretKey?.isDecrypted(): Boolean = (this == null) || (s2KUsage == 0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns indication that the secret key has S2K of a type GNU_DUMMY_S2K.
|
||||||
|
*
|
||||||
|
* @return true if secret key has S2K of type GNU_DUMMY_S2K, false otherwise.
|
||||||
|
*/
|
||||||
|
fun PGPSecretKey?.hasDummyS2K(): Boolean = (this != null) && (s2K?.type == S2K.GNU_DUMMY_S2K)
|
|
@ -0,0 +1,75 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023 Paul Schaub <vanitasvitae@fsfe.org>, 2021 Flowcrypt a.s.
|
||||||
|
//
|
||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
package org.pgpainless.key.info
|
||||||
|
|
||||||
|
import org.bouncycastle.extensions.getCurveName
|
||||||
|
import org.bouncycastle.extensions.hasDummyS2K
|
||||||
|
import org.bouncycastle.extensions.isDecrypted
|
||||||
|
import org.bouncycastle.extensions.isEncrypted
|
||||||
|
import org.bouncycastle.openpgp.PGPPublicKey
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKey
|
||||||
|
|
||||||
|
@Deprecated("Deprecated in favor of extension functions to PGPSecretKey and PGPPublicKey.")
|
||||||
|
class KeyInfo private constructor(
|
||||||
|
val secretKey: PGPSecretKey?,
|
||||||
|
val publicKey: PGPPublicKey) {
|
||||||
|
|
||||||
|
constructor(secretKey: PGPSecretKey): this(secretKey, secretKey.publicKey)
|
||||||
|
constructor(publicKey: PGPPublicKey): this(null, publicKey)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the name of the elliptic curve used by this key, or throw an [IllegalArgumentException] if the key
|
||||||
|
* is not based on elliptic curves, or on an unknown curve.
|
||||||
|
*/
|
||||||
|
@Deprecated("Deprecated in favor of calling getCurveName() on the PGPPublicKey itself.",
|
||||||
|
ReplaceWith("publicKey.getCurveName()"))
|
||||||
|
val curveName: String
|
||||||
|
get() = publicKey.getCurveName()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if the secret key is encrypted.
|
||||||
|
* This method returns false, if the secret key is null.
|
||||||
|
*/
|
||||||
|
@Deprecated("Deprecated in favor of calling isEncrypted() on the PGPSecretKey itself.",
|
||||||
|
ReplaceWith("secretKey.isEncrypted()"))
|
||||||
|
val isEncrypted: Boolean
|
||||||
|
get() = secretKey?.isEncrypted() ?: false
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if the secret key is decrypted.
|
||||||
|
* This method returns true, if the secret key is null.
|
||||||
|
*/
|
||||||
|
@Deprecated("Deprecated in favor of calling isDecrypted() on the PGPSecretKey itself.",
|
||||||
|
ReplaceWith("secretKey.isDecrypted()"))
|
||||||
|
val isDecrypted: Boolean
|
||||||
|
get() = secretKey?.isDecrypted() ?: true
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if the secret key is using the GNU_DUMMY_S2K s2k type.
|
||||||
|
* This method returns false, if the secret key is null.
|
||||||
|
*/
|
||||||
|
@Deprecated("Deprecated in favor of calling hasDummyS2K() on the PGPSecretKey itself.",
|
||||||
|
ReplaceWith("secretKey.hasDummyS2K()"))
|
||||||
|
val hasDummyS2K: Boolean
|
||||||
|
@JvmName("hasDummyS2K")
|
||||||
|
get() = secretKey?.hasDummyS2K() ?: false
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
@Deprecated("Deprecated in favor of calling isEncrypted() on the PGPSecretKey itself.",
|
||||||
|
ReplaceWith("secretKey.isEncrypted()"))
|
||||||
|
fun isEncrypted(secretKey: PGPSecretKey?) = secretKey.isEncrypted()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@Deprecated("Deprecated in favor of calling isDecrypted() on the PGPSecretKey itself.",
|
||||||
|
ReplaceWith("secretKey.isDecrypted()"))
|
||||||
|
fun isDecrypted(secretKey: PGPSecretKey?) = secretKey.isDecrypted()
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
@Deprecated("Deprecated in favor of calling hasDummyS2K() on the PGPSecretKey itself.",
|
||||||
|
ReplaceWith("secretKey.hasDummyS2K()"))
|
||||||
|
fun hasDummyS2K(secretKey: PGPSecretKey?) = secretKey.hasDummyS2K()
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
package org.pgpainless.key.protection
|
package org.pgpainless.key.protection
|
||||||
|
|
||||||
import openpgp.openPgpKeyId
|
import openpgp.openPgpKeyId
|
||||||
|
import org.bouncycastle.extensions.isEncrypted
|
||||||
import org.bouncycastle.openpgp.PGPException
|
import org.bouncycastle.openpgp.PGPException
|
||||||
import org.bouncycastle.openpgp.PGPPrivateKey
|
import org.bouncycastle.openpgp.PGPPrivateKey
|
||||||
import org.bouncycastle.openpgp.PGPSecretKey
|
import org.bouncycastle.openpgp.PGPSecretKey
|
||||||
|
@ -13,7 +14,6 @@ import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor
|
||||||
import org.pgpainless.PGPainless
|
import org.pgpainless.PGPainless
|
||||||
import org.pgpainless.exception.KeyIntegrityException
|
import org.pgpainless.exception.KeyIntegrityException
|
||||||
import org.pgpainless.exception.WrongPassphraseException
|
import org.pgpainless.exception.WrongPassphraseException
|
||||||
import org.pgpainless.key.info.KeyInfo
|
|
||||||
import org.pgpainless.key.util.PublicKeyParameterValidationUtil
|
import org.pgpainless.key.util.PublicKeyParameterValidationUtil
|
||||||
import org.pgpainless.util.Passphrase
|
import org.pgpainless.util.Passphrase
|
||||||
import kotlin.jvm.Throws
|
import kotlin.jvm.Throws
|
||||||
|
@ -25,7 +25,7 @@ class UnlockSecretKey {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Throws(PGPException::class, KeyIntegrityException::class)
|
@Throws(PGPException::class, KeyIntegrityException::class)
|
||||||
fun unlockSecretKey(secretKey: PGPSecretKey, protector: SecretKeyRingProtector): PGPPrivateKey {
|
fun unlockSecretKey(secretKey: PGPSecretKey, protector: SecretKeyRingProtector): PGPPrivateKey {
|
||||||
return if (KeyInfo.isEncrypted(secretKey)) {
|
return if (secretKey.isEncrypted()) {
|
||||||
unlockSecretKey(secretKey, protector.getDecryptor(secretKey.keyID))
|
unlockSecretKey(secretKey, protector.getDecryptor(secretKey.keyID))
|
||||||
} else {
|
} else {
|
||||||
unlockSecretKey(secretKey, null as PBESecretKeyDecryptor?)
|
unlockSecretKey(secretKey, null as PBESecretKeyDecryptor?)
|
||||||
|
|
Loading…
Reference in a new issue