mirror of
https://github.com/pgpainless/pgpainless.git
synced 2025-12-05 11:51:09 +01:00
YubikeyDataDecryptorFactory: WIP with SECP521r1 keys
This commit is contained in:
parent
f26d91d41f
commit
89bce1ca14
2 changed files with 63 additions and 5 deletions
|
|
@ -12,6 +12,7 @@ import org.bouncycastle.bcpg.KeyIdentifier
|
|||
import org.bouncycastle.bcpg.PublicKeyAlgorithmTags
|
||||
import org.bouncycastle.bcpg.PublicKeyPacket
|
||||
import org.bouncycastle.crypto.params.KeyParameter
|
||||
import org.bouncycastle.jce.ECNamedCurveTable
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.bouncycastle.openpgp.PGPPublicKey
|
||||
import org.bouncycastle.openpgp.operator.PGPPad
|
||||
|
|
@ -21,9 +22,11 @@ import org.bouncycastle.openpgp.operator.bc.BcPGPDigestCalculatorProvider
|
|||
import org.bouncycastle.openpgp.operator.bc.BcPublicKeyDataDecryptorFactory
|
||||
import org.bouncycastle.openpgp.operator.bc.RFC6637KDFCalculator
|
||||
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter
|
||||
import org.pgpainless.bouncycastle.extensions.getCurveName
|
||||
import org.pgpainless.decryption_verification.HardwareSecurity
|
||||
import org.pgpainless.key.OpenPgpV4Fingerprint
|
||||
import org.pgpainless.key.SubkeyIdentifier
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.util.*
|
||||
|
||||
class YubikeyDataDecryptorFactory(
|
||||
|
|
@ -32,6 +35,10 @@ class YubikeyDataDecryptorFactory(
|
|||
) : HardwareSecurity.HardwareDataDecryptorFactory(subkeyIdentifier, callback) {
|
||||
|
||||
companion object {
|
||||
|
||||
@JvmStatic
|
||||
val LOGGER = LoggerFactory.getLogger(YubikeyDataDecryptorFactory::class.java)
|
||||
|
||||
val ADMIN_PIN: CharArray = "12345678".toCharArray()
|
||||
val USER_PIN: CharArray = "123456".toCharArray()
|
||||
|
||||
|
|
@ -42,8 +49,7 @@ class YubikeyDataDecryptorFactory(
|
|||
pubkey: PGPPublicKey
|
||||
): HardwareSecurity.HardwareDataDecryptorFactory {
|
||||
val openpgpSession = OpenPgpSession(smartCardConnection)
|
||||
// openpgpSession.verifyAdminPin(ADMIN_PIN)
|
||||
val decKeyIdentifier: SubkeyIdentifier = SubkeyIdentifier(OpenPgpV4Fingerprint(pubkey))
|
||||
val decKeyIdentifier = SubkeyIdentifier(OpenPgpV4Fingerprint(pubkey))
|
||||
|
||||
val isRSAKey = pubkey.algorithm == PublicKeyAlgorithmTags.RSA_GENERAL
|
||||
|| pubkey.algorithm == PublicKeyAlgorithmTags.RSA_SIGN
|
||||
|
|
@ -60,13 +66,18 @@ class YubikeyDataDecryptorFactory(
|
|||
openpgpSession.verifyAdminPin(ADMIN_PIN)
|
||||
openpgpSession.verifyUserPin(USER_PIN, true)
|
||||
|
||||
LOGGER.debug("Attempt decryption with key {}", keyIdentifier)
|
||||
|
||||
if(isRSAKey) {
|
||||
// easy
|
||||
LOGGER.debug("Key is RSA key of length {}", pubkey.bitStrength)
|
||||
val decryptedSessionKey = openpgpSession.decrypt(sessionKeyData)
|
||||
return decryptedSessionKey
|
||||
} else {
|
||||
// meh...
|
||||
val curveName = pubkey.getCurveName()
|
||||
val ecPubKey: ECDHPublicBCPGKey = pubkey.publicKeyPacket.key as ECDHPublicBCPGKey
|
||||
LOGGER.debug("Key is ECDH key over curve $curveName")
|
||||
// split session data into peer key and encrypted session key
|
||||
|
||||
// peer key
|
||||
|
|
@ -83,9 +94,8 @@ class YubikeyDataDecryptorFactory(
|
|||
System.arraycopy(sessionKeyData, 2 + pLen + 1, keyEnc, 0, keyLen)
|
||||
|
||||
// perform ECDH key agreement via the Yubikey
|
||||
val x9Params =
|
||||
org.bouncycastle.asn1.x9.ECNamedCurveTable.getByOIDLazy(ecPubKey.curveOID)
|
||||
val publicPoint = x9Params.curve.decodePoint(pEnc)
|
||||
val params = ECNamedCurveTable.getParameterSpec(curveName)
|
||||
val publicPoint = params.curve.decodePoint(pEnc)
|
||||
val peerKey = JcaPGPKeyConverter().setProvider(BouncyCastleProvider())
|
||||
.getPublicKey(
|
||||
PGPPublicKey(
|
||||
|
|
|
|||
|
|
@ -5,15 +5,20 @@ import com.yubico.yubikit.core.smartcard.SmartCardConnection
|
|||
import com.yubico.yubikit.desktop.CompositeDevice
|
||||
import com.yubico.yubikit.desktop.YubiKitManager
|
||||
import com.yubico.yubikit.openpgp.OpenPgpSession
|
||||
import org.bouncycastle.jce.ECNamedCurveTable
|
||||
import org.bouncycastle.jce.provider.BouncyCastleProvider
|
||||
import org.bouncycastle.openpgp.PGPUtil
|
||||
import org.bouncycastle.openpgp.api.bc.BcOpenPGPImplementation
|
||||
import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter
|
||||
import org.gnupg.GnuPGDummyKeyUtil
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertNotNull
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.pgpainless.PGPainless
|
||||
import org.pgpainless.algorithm.KeyFlag
|
||||
import org.pgpainless.algorithm.OpenPGPKeyVersion
|
||||
import org.pgpainless.bouncycastle.extensions.getCurveName
|
||||
import org.pgpainless.bouncycastle.extensions.toOpenPGPKey
|
||||
import org.pgpainless.decryption_verification.ConsumerOptions
|
||||
import org.pgpainless.encryption_signing.EncryptionOptions
|
||||
|
|
@ -119,6 +124,7 @@ class YubikeyTest {
|
|||
|
||||
@Test
|
||||
fun test() {
|
||||
println(CERT)
|
||||
val api = PGPainless(BcOpenPGPImplementation())
|
||||
val key = api.readKey().parseKey(KEY)
|
||||
|
||||
|
|
@ -171,4 +177,46 @@ class YubikeyTest {
|
|||
assertEquals("Hello, World!\n", String(msg))
|
||||
}
|
||||
}
|
||||
|
||||
val pubKeyAscii = // "modernKeyRing"
|
||||
"""
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: C68A 9140 9A00 3C55 5D8A 62A5 D3ED 03F9 FF75 68D4
|
||||
Comment: john doe <j.doe@example.com>
|
||||
|
||||
mDMEaR7iehYJKwYBBAHaRw8BAQdA5XMRsc8HUXiJkjtOSCj86v+OeemU41U08Lmi
|
||||
2PQ3Tnm0HGpvaG4gZG9lIDxqLmRvZUBleGFtcGxlLmNvbT7CnwQTFgoAUQkQ0+0D
|
||||
+f91aNQWoQTGipFAmgA8VV2KYqXT7QP5/3Vo1AWCaR7iegKbAQUVCgkICwUWAgMB
|
||||
AAQLCQgHCScJAQkCCQMIAQKeCQWJCWYBgAKZAQAAFecBALy6FxELczpihvkVJPa2
|
||||
iaV7zDcfFBvX4KyTr506hxufAP4ixT59d/QRMWmuRN6QRkRcgduLaw2l/Hs/zBuV
|
||||
tQjHDsKfBBMWCgBRApsBBRUKCQgLBRYCAwEABAsJCAcJJwkBCQIJAwgBAp4JCRDT
|
||||
7QP5/3Vo1BahBMaKkUCaADxVXYpipdPtA/n/dWjUBYJpHuJ7BYkAAAAAApkBAAAK
|
||||
SQD9FpbJAinkmaeHluaKmiCp0HggoGF8aji9rDqSvUDtnWsA/i5I1eZ0rPvxZc6z
|
||||
pIbfRHdbdgOTmTZEOOz82GQVmsMLuDgEaR7iehIKKwYBBAGXVQEFAQEHQHc9W+J1
|
||||
IPl7nekdLrx5SLdvYnNNocULlqqLoDgN3fV4AwEIB8J4BBgWCgAqCRDT7QP5/3Vo
|
||||
1BahBMaKkUCaADxVXYpipdPtA/n/dWjUBYJpHuJ6ApsMAACh/AEA1r+JB8uhMX7N
|
||||
l4B3QOF9zLmUXhihRvE0tyY3cCCwUrYA/2yqF1mA8dHsDuDnWEUYxgX+ZpYBXr+P
|
||||
j9ZKl/HoNeIOuDMEaR7iehYJKwYBBAHaRw8BAQdAQPTWzF21MpuSRjclxeAS+lZH
|
||||
ulTwm/HsOaVpur8vSZ/CwC8EGBYKAKEJENPtA/n/dWjUFqEExoqRQJoAPFVdimKl
|
||||
0+0D+f91aNQFgmke4noCmwJ2IAQZFgoAHQWCaR7iehYhBMqKZfP+EDi1iRE58a14
|
||||
HgK5jFyDAAoJEK14HgK5jFyDoRUA/0GmLpBUVFSEdbSh+o7tz6xncAIjkm20LWIy
|
||||
PF81ilR9AP0a/MVoE9ivY7HK9uu79cc2Y5IratjiXRpamYqODQutAQAA848A/Ro1
|
||||
SfAfFAmMDfcbuKvpQEK/d4T3455End3ohd5TXb7VAP9/wMxzLJ1K5mE6LTQ5Hw4b
|
||||
m9XtYRYVHugI27XFacaFAg==
|
||||
=3yy3
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
||||
""".trimIndent()
|
||||
|
||||
@Test
|
||||
fun getx9ParamsTest() {
|
||||
val certificate = org.bouncycastle.openpgp.api.OpenPGPKeyReader().parseCertificate(pubKeyAscii.toByteArray())
|
||||
val pubKey = certificate.getEncryptionKeys().first().getPGPPublicKey()
|
||||
|
||||
assertTrue(pubKey.isEncryptionKey())
|
||||
|
||||
val ecPubKey = pubKey.getPublicKeyPacket().getKey() as org.bouncycastle.bcpg.ECDHPublicBCPGKey
|
||||
val params = ECNamedCurveTable.getParameterSpec(pubKey.getCurveName())
|
||||
|
||||
assertNotNull(params) // fails
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue