diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java index ccdea777b4..52ca458e0b 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/PGPKeyConverter.java @@ -74,6 +74,11 @@ protected PGPKeyConverter() * SHA2-256 * AES-128 * + * + * Curve448 + * SHA2-512 + * AES-256 + * * */ protected PGPKdfParameters implGetKdfParameters(ASN1ObjectIdentifier curveID, PGPAlgorithmParameters algorithmParameters) @@ -89,7 +94,8 @@ else if (curveID.equals(SECObjectIdentifiers.secp384r1) || curveID.equals(TeleTr { return new PGPKdfParameters(HashAlgorithmTags.SHA384, SymmetricKeyAlgorithmTags.AES_192); } - else if (curveID.equals(SECObjectIdentifiers.secp521r1) || curveID.equals(TeleTrusTObjectIdentifiers.brainpoolP512r1)) + else if (curveID.equals(SECObjectIdentifiers.secp521r1) || curveID.equals(TeleTrusTObjectIdentifiers.brainpoolP512r1) + || curveID.equals(EdECObjectIdentifiers.id_X448)) { return new PGPKdfParameters(HashAlgorithmTags.SHA512, SymmetricKeyAlgorithmTags.AES_256); } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java index 23ab52f0e4..c7a3b5237b 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/bc/BcPGPKeyConverter.java @@ -122,40 +122,58 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey) { ECDHPublicBCPGKey ecdhPub = (ECDHPublicBCPGKey)pubPk.getKey(); + // Legacy XDH on Curve25519 (legacy X25519) + // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 if (CryptlibObjectIdentifiers.curvey25519.equals(ecdhPub.getCurveOID())) { return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX())))); } + // Legacy X448 (1.3.101.111) + else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID())) + { + return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_X448, + Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX())))); + } + // NIST, Brainpool etc. else { return implGetPrivateKeyEC(ecdhPub, (ECSecretBCPGKey)privPk); } } + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, X25519SecretBCPGKey.LENGTH, - Arrays.reverseInPlace(privPk.getEncoded()))); + privPk.getEncoded())); } + // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_X448, X448SecretBCPGKey.LENGTH, - Arrays.reverseInPlace(privPk.getEncoded()))); + privPk.getEncoded())); } case PublicKeyAlgorithmTags.ECDSA: - return implGetPrivateKeyEC((ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk); + { + return implGetPrivateKeyEC((ECDSAPublicBCPGKey) pubPk.getKey(), (ECSecretBCPGKey) privPk); + } + // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { + // Legacy Ed448 (1.3.101.113) if (((EdDSAPublicBCPGKey)pubPk.getKey()).getCurveOID().equals(EdECObjectIdentifiers.id_Ed448)) { return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed448, Ed448.SECRET_KEY_SIZE, privPk); } + // Legacy Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) return implGetPrivateKeyPKCS8(EdECObjectIdentifiers.id_Ed25519, Ed25519.SECRET_KEY_SIZE, privPk); } + // Modern Ed22519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519, Ed25519SecretBCPGKey.LENGTH, privPk.getEncoded())); } + // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return PrivateKeyFactory.createKey(getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448, Ed448SecretBCPGKey.LENGTH, privPk.getEncoded())); @@ -178,7 +196,7 @@ public AsymmetricKeyParameter getPrivateKey(PGPPrivateKey privKey) rsaPriv.getPrimeExponentQ(), rsaPriv.getCrtCoefficient()); } default: - throw new PGPException("unknown public key algorithm encountered"); + throw new PGPException("unknown public key algorithm encountered: " + pubPk.getAlgorithm()); } } catch (PGPException e) @@ -209,6 +227,8 @@ public AsymmetricKeyParameter getPublicKey(PGPPublicKey publicKey) { ECDHPublicBCPGKey ecdhK = (ECDHPublicBCPGKey)publicPk.getKey(); + // Legacy XDH on Curve25519 (legacy X25519) + // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 if (ecdhK.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519)) { byte[] pEnc = BigIntegers.asUnsignedByteArray(ecdhK.getEncodedPoint()); @@ -219,22 +239,37 @@ public AsymmetricKeyParameter getPublicKey(PGPPublicKey publicKey) } return implGetPublicKeyX509(EdECObjectIdentifiers.id_X25519, pEnc, 1); } + // Legacy X448 (1.3.101.111) + else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448)) + { + byte[] pEnc = BigIntegers.asUnsignedByteArray(ecdhK.getEncodedPoint()); + // skip the 0x40 header byte. + if (pEnc.length < 1 || 0x40 != pEnc[0]) + { + throw new IllegalArgumentException("Invalid X448 public key"); + } + return implGetPublicKeyX509(EdECObjectIdentifiers.id_X448, pEnc, 1); + } else { return implGetPublicKeyEC(ecdhK); } } + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return implGetPublicKeyX509((X25519PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_X25519); } + // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return implGetPublicKeyX509((X448PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_X448); } case PublicKeyAlgorithmTags.ECDSA: + { return implGetPublicKeyEC((ECDSAPublicBCPGKey)publicPk.getKey()); - + } + // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { EdDSAPublicBCPGKey eddsaK = (EdDSAPublicBCPGKey)publicPk.getKey(); @@ -246,29 +281,35 @@ public AsymmetricKeyParameter getPublicKey(PGPPublicKey publicKey) throw new IllegalArgumentException("Invalid EdDSA public key"); } - if (pEnc[0] == 0x40 && !eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448)) + // Legacy Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) + if (!eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448)) { - return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, 1); + return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed25519, pEnc, pEnc[0] == 0x40 ? 1 : 0); } - else if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448)) + // Legacy Ed448 (1.3.101.113) + if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448)) { - return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed448, pEnc, 0); + return implGetPublicKeyX509(EdECObjectIdentifiers.id_Ed448, pEnc, pEnc[0] == 0x40 ? 1 : 0); } throw new IllegalArgumentException("Invalid EdDSA public key"); } + // Modern Ed22519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return implGetPublicKeyX509((Ed25519PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_Ed25519); } + // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return implGetPublicKeyX509((Ed448PublicBCPGKey)publicPk.getKey(), EdECObjectIdentifiers.id_Ed448); } case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: - ElGamalPublicBCPGKey elK = (ElGamalPublicBCPGKey)publicPk.getKey(); + { + ElGamalPublicBCPGKey elK = (ElGamalPublicBCPGKey) publicPk.getKey(); return new ElGamalPublicKeyParameters(elK.getY(), new ElGamalParameters(elK.getP(), elK.getG())); + } case PublicKeyAlgorithmTags.RSA_ENCRYPT: case PublicKeyAlgorithmTags.RSA_GENERAL: @@ -279,7 +320,7 @@ else if (eddsaK.getCurveOID().equals(EdECObjectIdentifiers.id_Ed448)) } default: - throw new PGPException("unknown public key algorithm encountered"); + throw new PGPException("unknown public key algorithm encountered: " + publicKey.getAlgorithm()); } } catch (PGPException e) @@ -304,37 +345,59 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter pr } case PublicKeyAlgorithmTags.ECDH: { + // Legacy XDH on Curve25519 (legacy X25519) + // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 if (privKey instanceof X25519PrivateKeyParameters) { return new ECSecretBCPGKey(new BigInteger(1, Arrays.reverseInPlace(((X25519PrivateKeyParameters)privKey).getEncoded()))); } + // Legacy X448 (1.3.101.111) + else if (privKey instanceof X448PrivateKeyParameters) + { + return new ECSecretBCPGKey(new BigInteger(1, Arrays.reverseInPlace(((X448PrivateKeyParameters)privKey).getEncoded()))); + } + // NIST, Brainpool etc. else { ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey; return new ECSecretBCPGKey(ecK.getD()); } } + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { - return new X25519SecretBCPGKey(Arrays.reverseInPlace(((X25519PrivateKeyParameters)privKey).getEncoded())); + return new X25519SecretBCPGKey(((X25519PrivateKeyParameters)privKey).getEncoded()); } + // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { - return new X448SecretBCPGKey(Arrays.reverseInPlace(((X448PrivateKeyParameters)privKey).getEncoded())); + return new X448SecretBCPGKey(((X448PrivateKeyParameters)privKey).getEncoded()); } case PublicKeyAlgorithmTags.ECDSA: { ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey; return new ECSecretBCPGKey(ecK.getD()); } + // Legacy EdDSA case PublicKeyAlgorithmTags.EDDSA_LEGACY: { - return new EdSecretBCPGKey(new BigInteger(1, ((Ed25519PrivateKeyParameters)privKey).getEncoded())); + // Legacy Ed25519 (1.3.101.112 & 1.3.6.1.4.1.11591.15.1) + if (privKey instanceof Ed25519PrivateKeyParameters) + { + return new EdSecretBCPGKey(new BigInteger(1, ((Ed25519PrivateKeyParameters)privKey).getEncoded())); + } + // Legacy Ed448 (1.3.101.113) + else + { + return new EdSecretBCPGKey(new BigInteger(1, ((Ed448PrivateKeyParameters) privKey).getEncoded())); + } } + // Modern Ed22519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return new Ed25519SecretBCPGKey(((Ed25519PrivateKeyParameters)privKey).getEncoded()); } + // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return new Ed448SecretBCPGKey(((Ed448PrivateKeyParameters)privKey).getEncoded()); @@ -354,98 +417,133 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pubKey, AsymmetricKeyParameter pr } default: - throw new PGPException("unknown key class"); + throw new PGPException("unknown public key algorithm encountered: " + pubKey.getAlgorithm()); } } private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters, AsymmetricKeyParameter pubKey) throws PGPException { - if (pubKey instanceof RSAKeyParameters) + switch (algorithm) { - RSAKeyParameters rK = (RSAKeyParameters)pubKey; - return new RSAPublicBCPGKey(rK.getModulus(), rK.getExponent()); - } - else if (pubKey instanceof DSAPublicKeyParameters) - { - DSAPublicKeyParameters dK = (DSAPublicKeyParameters)pubKey; - DSAParameters dP = dK.getParameters(); - return new DSAPublicBCPGKey(dP.getP(), dP.getQ(), dP.getG(), dK.getY()); - } - else if (pubKey instanceof ElGamalPublicKeyParameters) - { - ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters)pubKey; - ElGamalParameters eS = eK.getParameters(); - return new ElGamalPublicBCPGKey(eS.getP(), eS.getG(), eK.getY()); - } - else if (pubKey instanceof ECPublicKeyParameters) - { - ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey; + case PublicKeyAlgorithmTags.RSA_GENERAL: + case PublicKeyAlgorithmTags.RSA_ENCRYPT: + case PublicKeyAlgorithmTags.RSA_SIGN: + { + RSAKeyParameters rK = (RSAKeyParameters)pubKey; + return new RSAPublicBCPGKey(rK.getModulus(), rK.getExponent()); + } + case PublicKeyAlgorithmTags.DSA: + { + DSAPublicKeyParameters dK = (DSAPublicKeyParameters)pubKey; + DSAParameters dP = dK.getParameters(); + return new DSAPublicBCPGKey(dP.getP(), dP.getQ(), dP.getG(), dK.getY()); + } + case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: + case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: + { + ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters)pubKey; + ElGamalParameters eS = eK.getParameters(); + return new ElGamalPublicBCPGKey(eS.getP(), eS.getG(), eK.getY()); + } + // NIST, Brainpool, Legacy X25519, Legacy X448 + case PublicKeyAlgorithmTags.ECDH: + { + // Legacy X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) + if (pubKey instanceof X25519PublicKeyParameters) + { + byte[] pointEnc = new byte[1 + X25519PublicKeyParameters.KEY_SIZE]; + pointEnc[0] = 0x40; + ((X25519PublicKeyParameters)pubKey).encode(pointEnc, 1); - // TODO Should we have a way to recognize named curves when the name is missing? - ECNamedDomainParameters parameters = (ECNamedDomainParameters)ecK.getParameters(); + PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters); - if (algorithm == PGPPublicKey.ECDH) - { + return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, pointEnc), + kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); + } + // Legacy X448 (1.3.101.111) + if (pubKey instanceof X448PublicKeyParameters) + { + byte[] pointEnc = new byte[1 + X448PublicKeyParameters.KEY_SIZE]; + pointEnc[0] = 0x40; + ((X448PublicKeyParameters)pubKey).encode(pointEnc, 1); + + PGPKdfParameters kdfParams = implGetKdfParameters(EdECObjectIdentifiers.id_X448, algorithmParameters); + + return new ECDHPublicBCPGKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, pointEnc), + kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); + } + // NIST, Brainpool etc. + ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey; + ECNamedDomainParameters parameters = (ECNamedDomainParameters)ecK.getParameters(); PGPKdfParameters kdfParams = implGetKdfParameters(parameters.getName(), algorithmParameters); return new ECDHPublicBCPGKey(parameters.getName(), ecK.getQ(), kdfParams.getHashAlgorithm(), - kdfParams.getSymmetricWrapAlgorithm()); + kdfParams.getSymmetricWrapAlgorithm()); } - else if (algorithm == PGPPublicKey.ECDSA) + case PublicKeyAlgorithmTags.ECDSA: { + ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey; + ECNamedDomainParameters parameters = (ECNamedDomainParameters)ecK.getParameters(); return new ECDSAPublicBCPGKey(parameters.getName(), ecK.getQ()); } - else + // Legacy Ed255519, Legacy Ed448 + case PublicKeyAlgorithmTags.EDDSA_LEGACY: { - throw new PGPException("unknown EC algorithm"); + // Legacy Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) + if (pubKey instanceof Ed25519PublicKeyParameters) + { + byte[] pointEnc = new byte[1 + Ed25519PublicKeyParameters.KEY_SIZE]; + pointEnc[0] = 0x40; + ((Ed25519PublicKeyParameters)pubKey).encode(pointEnc, 1); + return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, pointEnc)); + } + // Legacy Ed448 (1.3.101.113) + else if (pubKey instanceof Ed448PublicKeyParameters) + { + byte[] pointEnc = new byte[1 + Ed448PublicKeyParameters.KEY_SIZE]; + pointEnc[0] = 0x40; + ((Ed448PublicKeyParameters)pubKey).encode(pointEnc, 1); + return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, pointEnc)); + } + else + { + throw new PGPException("Unknown LegacyEdDSA key type: " + pubKey.getClass().getName()); + } + } + // Modern Ed22519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) + case PublicKeyAlgorithmTags.Ed25519: + { + byte[] pointEnc = new byte[Ed25519PublicKeyParameters.KEY_SIZE]; + ((Ed25519PublicKeyParameters)pubKey).encode(pointEnc, 0); + return new Ed25519PublicBCPGKey(pointEnc); + } + // Modern Ed448 (1.3.101.113) + case PublicKeyAlgorithmTags.Ed448: + { + byte[] pointEnc = new byte[Ed448PublicKeyParameters.KEY_SIZE]; + ((Ed448PublicKeyParameters)pubKey).encode(pointEnc, 0); + return new Ed448PublicBCPGKey(pointEnc); + } + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) + case PublicKeyAlgorithmTags.X25519: + { + byte[] pointEnc = new byte[X25519PublicKeyParameters.KEY_SIZE]; + ((X25519PublicKeyParameters)pubKey).encode(pointEnc, 0); + return new X25519PublicBCPGKey(pointEnc); + } + // Modern X448 (1.3.101.111) + case PublicKeyAlgorithmTags.X448: + { + byte[] pointEnc = new byte[X448PublicKeyParameters.KEY_SIZE]; + ((X448PublicKeyParameters)pubKey).encode(pointEnc, 0); + return new X448PublicBCPGKey(pointEnc); } - } - else if (algorithm == PublicKeyAlgorithmTags.Ed25519) - { - byte[] pointEnc = new byte[Ed25519PublicKeyParameters.KEY_SIZE]; - ((Ed25519PublicKeyParameters)pubKey).encode(pointEnc, 0); - return new Ed25519PublicBCPGKey(pointEnc); - } - else if (pubKey instanceof Ed25519PublicKeyParameters) - { - byte[] pointEnc = new byte[1 + Ed25519PublicKeyParameters.KEY_SIZE]; - pointEnc[0] = 0x40; - ((Ed25519PublicKeyParameters)pubKey).encode(pointEnc, 1); - return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, pointEnc)); - } - else if (pubKey instanceof Ed448PublicKeyParameters) - { - byte[] pointEnc = new byte[Ed448PublicKeyParameters.KEY_SIZE]; - ((Ed448PublicKeyParameters)pubKey).encode(pointEnc, 0); - return new Ed448PublicBCPGKey(pointEnc); - } - else if (algorithm == PublicKeyAlgorithmTags.X25519) - { - byte[] pointEnc = new byte[X25519PublicKeyParameters.KEY_SIZE]; - ((X25519PublicKeyParameters)pubKey).encode(pointEnc, 0); - return new X25519PublicBCPGKey(pointEnc); - } - else if (pubKey instanceof X25519PublicKeyParameters) - { - byte[] pointEnc = new byte[1 + X25519PublicKeyParameters.KEY_SIZE]; - pointEnc[0] = 0x40; - ((X25519PublicKeyParameters)pubKey).encode(pointEnc, 1); - - PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters); - return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, pointEnc), - kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); - } - else if (pubKey instanceof X448PublicKeyParameters) - { - byte[] pointEnc = new byte[X448PublicKeyParameters.KEY_SIZE]; - ((X448PublicKeyParameters)pubKey).encode(pointEnc, 0); - return new X448PublicBCPGKey(pointEnc); - } - else - { - throw new PGPException("unknown key class"); + default: + { + throw new PGPException("unknown public key algorithm encountered: " + algorithm); + } } } diff --git a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java index 66e0179a34..64779da731 100644 --- a/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java +++ b/pg/src/main/java/org/bouncycastle/openpgp/operator/jcajce/JcaPGPKeyConverter.java @@ -14,7 +14,6 @@ import java.security.interfaces.DSAPrivateKey; import java.security.interfaces.DSAPublicKey; import java.security.interfaces.ECPrivateKey; -import java.security.interfaces.ECPublicKey; import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.DSAPrivateKeySpec; @@ -76,10 +75,13 @@ import org.bouncycastle.jcajce.util.DefaultJcaJceHelper; import org.bouncycastle.jcajce.util.NamedJcaJceHelper; import org.bouncycastle.jcajce.util.ProviderJcaJceHelper; +import org.bouncycastle.jce.interfaces.ElGamalPublicKey; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.math.ec.rfc7748.X25519; +import org.bouncycastle.math.ec.rfc7748.X448; import org.bouncycastle.math.ec.rfc8032.Ed25519; +import org.bouncycastle.math.ec.rfc8032.Ed448; import org.bouncycastle.openpgp.PGPAlgorithmParameters; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKdfParameters; @@ -194,41 +196,66 @@ public PrivateKey getPrivateKey(PGPPrivateKey privKey) ECDHPublicBCPGKey ecdhPub = (ECDHPublicBCPGKey)pubPk.getKey(); ECSecretBCPGKey ecdhK = (ECSecretBCPGKey)privPk; - if (CryptlibObjectIdentifiers.curvey25519.equals(ecdhPub.getCurveOID())) + // Legacy XDH on Curve25519 (legacy X25519) + // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 + if (CryptlibObjectIdentifiers.curvey25519.equals(ecdhPub.getCurveOID()) || + EdECObjectIdentifiers.id_X25519.equals(ecdhPub.getCurveOID())) { // 'reverse' because the native format for X25519 private keys is little-endian return implGeneratePrivate("XDH", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX())))); } + // Legacy X448 (1.3.101.111) + else if (EdECObjectIdentifiers.id_X448.equals(ecdhPub.getCurveOID())) + { + // 'reverse' because the native format for X448 private keys is little-endian (?) + return implGeneratePrivate("XDH", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X448, + Arrays.reverseInPlace(BigIntegers.asUnsignedByteArray(((ECSecretBCPGKey)privPk).getX())))); + } + // Brainpool, NIST etc. else { return implGetPrivateKeyEC("ECDH", ecdhPub, ecdhK); } } + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return implGeneratePrivate("XDH", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X25519, - X25519SecretBCPGKey.LENGTH, Arrays.reverseInPlace(privPk.getEncoded()))); + X25519SecretBCPGKey.LENGTH, privPk.getEncoded())); } + // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return implGeneratePrivate("XDH", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_X448, - X448SecretBCPGKey.LENGTH, Arrays.reverseInPlace(privPk.getEncoded()))); + X448SecretBCPGKey.LENGTH, privPk.getEncoded())); } case PublicKeyAlgorithmTags.ECDSA: { return implGetPrivateKeyEC("ECDSA", (ECDSAPublicBCPGKey)pubPk.getKey(), (ECSecretBCPGKey)privPk); } + // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { + EdDSAPublicBCPGKey eddsaPub = (EdDSAPublicBCPGKey) pubPk.getKey(); + // Legacy Ed448 (1.3.101.113) + if (EdECObjectIdentifiers.id_Ed448.equals(eddsaPub.getCurveOID())) + { + return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448, + BigIntegers.asUnsignedByteArray(Ed448.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX()))); + } + // Legacy Ed25519 + // 1.3.6.1.4.1.11591.15.1 & 1.3.101.112 return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519, BigIntegers.asUnsignedByteArray(Ed25519.SECRET_KEY_SIZE, ((EdSecretBCPGKey)privPk).getX()))); } + // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed25519, Ed25519SecretBCPGKey.LENGTH, privPk.getEncoded())); } + // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return implGeneratePrivate("EdDSA", () -> getPrivateKeyInfo(EdECObjectIdentifiers.id_Ed448, @@ -289,30 +316,54 @@ public PublicKey getPublicKey(PGPPublicKey publicKey) { ECDHPublicBCPGKey ecdhK = (ECDHPublicBCPGKey)publicPk.getKey(); + // Legacy XDH on Curve25519 (legacy X25519) + // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 if (ecdhK.getCurveOID().equals(CryptlibObjectIdentifiers.curvey25519)) { return get25519PublicKey(ecdhK.getEncodedPoint(), EdECObjectIdentifiers.id_X25519, "XDH", "Curve"); } + // Legacy X448 (1.3.101.111) + else if (ecdhK.getCurveOID().equals(EdECObjectIdentifiers.id_X448)) + { + return get448PublicKey(ecdhK.getEncodedPoint(), EdECObjectIdentifiers.id_X448, "XDH", "Curve"); + } + // Brainpool, NIST etc. else { return implGetPublicKeyEC("ECDH", ecdhK); } } + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X25519, "XDH"); } + // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { return implGetPublicKeyX509(publicPk.getKey().getEncoded(), 0, EdECObjectIdentifiers.id_X448, "XDH"); } case PublicKeyAlgorithmTags.ECDSA: - return implGetPublicKeyEC("ECDSA", (ECDSAPublicBCPGKey)publicPk.getKey()); - + { + return implGetPublicKeyEC("ECDSA", (ECDSAPublicBCPGKey) publicPk.getKey()); + } + // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { - return get25519PublicKey(((EdDSAPublicBCPGKey)publicPk.getKey()).getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed"); + EdDSAPublicBCPGKey eddsaKey = (EdDSAPublicBCPGKey) publicPk.getKey(); + // Legacy Ed448 (1.3.101.113) + if (EdECObjectIdentifiers.id_Ed448.equals(eddsaKey.getCurveOID())) + { + return get448PublicKey(eddsaKey.getEncodedPoint(), EdECObjectIdentifiers.id_Ed448, "EdDSA", "Ed"); + } + // Legacy Ed25519 + // 1.3.6.1.4.1.11591.15.1 & 1.3.101.112 + else + { + return get25519PublicKey(eddsaKey.getEncodedPoint(), EdECObjectIdentifiers.id_Ed25519, "EdDSA", "Ed"); + } } + // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { BCPGKey key = publicPk.getKey(); @@ -327,6 +378,7 @@ public PublicKey getPublicKey(PGPPublicKey publicKey) 0, EdECObjectIdentifiers.id_Ed25519, "EdDSA"); } } + // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return implGetPublicKeyX509(BigIntegers.asUnsignedByteArray(new BigInteger(1, publicPk.getKey().getEncoded())), @@ -380,7 +432,6 @@ private BCPGKey getPrivateBCPGKey(PrivateKey privKey, BCPGKeyOperation operation try { - // 'reverse' because the native format for X25519 private keys is little-endian return operation.getBCPGKey(ASN1OctetString.getInstance(pInfo.parsePrivateKey()).getOctets()); } catch (IOException e) @@ -409,32 +460,35 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey) } else { - // 'reverse' because the native format for X25519 private keys is little-endian + // 'reverse' because the native format for X25519,X448 private keys is little-endian return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new ECSecretBCPGKey(new BigInteger(1, Arrays.reverse(pInfoEncoded)))); } } + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) case PublicKeyAlgorithmTags.X25519: { - // 'reverse' because the native format for X25519 private keys is little-endian - return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X25519SecretBCPGKey(Arrays.reverse(pInfoEncoded))); + return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X25519SecretBCPGKey(pInfoEncoded)); } + // Modern X448 (1.3.101.111) case PublicKeyAlgorithmTags.X448: { - // 'reverse' because the native format for X448 private keys is little-endian - return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X448SecretBCPGKey(Arrays.reverse(pInfoEncoded))); + return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new X448SecretBCPGKey(pInfoEncoded)); } case PublicKeyAlgorithmTags.ECDSA: { return new ECSecretBCPGKey(((ECPrivateKey)privKey).getS()); } + // Legacy EdDSA (legacy Ed448, legacy Ed25519) case PublicKeyAlgorithmTags.EDDSA_LEGACY: { return getPrivateBCPGKey(privKey, (pInfoEncoded) -> new EdSecretBCPGKey(new BigInteger(1, pInfoEncoded))); } + // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) case PublicKeyAlgorithmTags.Ed25519: { return getPrivateBCPGKey(privKey, Ed25519SecretBCPGKey::new); } + // Modern Ed448 (1.3.101.113) case PublicKeyAlgorithmTags.Ed448: { return getPrivateBCPGKey(privKey, Ed448SecretBCPGKey::new); @@ -453,88 +507,166 @@ private BCPGKey getPrivateBCPGKey(PGPPublicKey pub, PrivateKey privKey) return new RSASecretBCPGKey(rsK.getPrivateExponent(), rsK.getPrimeP(), rsK.getPrimeQ()); } default: - throw new PGPException("unknown key class"); + throw new PGPException("unknown public key algorithm encountered: " + pub.getAlgorithm()); } } private BCPGKey getPublicBCPGKey(int algorithm, PGPAlgorithmParameters algorithmParameters, PublicKey pubKey) throws PGPException { - if (pubKey instanceof RSAPublicKey) - { - RSAPublicKey rK = (RSAPublicKey)pubKey; - return new RSAPublicBCPGKey(rK.getModulus(), rK.getPublicExponent()); - } - else if (pubKey instanceof DSAPublicKey) - { - DSAPublicKey dK = (DSAPublicKey)pubKey; - DSAParams dP = dK.getParams(); - return new DSAPublicBCPGKey(dP.getP(), dP.getQ(), dP.getG(), dK.getY()); - } - else if (pubKey instanceof DHPublicKey) + switch (algorithm) { - DHPublicKey eK = (DHPublicKey)pubKey; - DHParameterSpec eS = eK.getParams(); - return new ElGamalPublicBCPGKey(eS.getP(), eS.getG(), eK.getY()); - } - else if (pubKey instanceof ECPublicKey) - { - SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()); + case PublicKeyAlgorithmTags.RSA_GENERAL: + case PublicKeyAlgorithmTags.RSA_ENCRYPT: + case PublicKeyAlgorithmTags.RSA_SIGN: + { + RSAPublicKey rK = (RSAPublicKey) pubKey; + return new RSAPublicBCPGKey(rK.getModulus(), rK.getPublicExponent()); + } + case PublicKeyAlgorithmTags.ELGAMAL_ENCRYPT: + case PublicKeyAlgorithmTags.ELGAMAL_GENERAL: + { + ElGamalPublicKey egK = (ElGamalPublicKey) pubKey; + return new ElGamalPublicBCPGKey(egK.getParameters().getP(), egK.getParameters().getG(), egK.getY()); + } + case PublicKeyAlgorithmTags.DSA: + { + DSAPublicKey dK = (DSAPublicKey) pubKey; + DSAParams dP = dK.getParams(); + return new DSAPublicBCPGKey(dP.getP(), dP.getQ(), dP.getG(), dK.getY()); + } - // TODO: should probably match curve by comparison as well - ASN1ObjectIdentifier curveOid = ASN1ObjectIdentifier.getInstance(keyInfo.getAlgorithm().getParameters()); + case PublicKeyAlgorithmTags.DIFFIE_HELLMAN: + { + DHPublicKey eK = (DHPublicKey) pubKey; + DHParameterSpec eS = eK.getParams(); + return new ElGamalPublicBCPGKey(eS.getP(), eS.getG(), eK.getY()); + } - X9ECParametersHolder params = ECNamedCurveTable.getByOIDLazy(curveOid); + case PublicKeyAlgorithmTags.ECDH: + case PublicKeyAlgorithmTags.ECDSA: + { + SubjectPublicKeyInfo keyInfo = SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()); + + // TODO: should probably match curve by comparison as well + ASN1ObjectIdentifier curveOid = ASN1ObjectIdentifier.getInstance(keyInfo.getAlgorithm().getParameters()); + if (curveOid == null) + { + // Legacy XDH on Curve25519 (legacy X25519) + // 1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110 + if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2)) + { + PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters); + + return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)), + kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); + } + // Legacy X448 (1.3.101.111) + if (pubKey.getAlgorithm().regionMatches(true, 0, "X4", 0, 2)) + { + + PGPKdfParameters kdfParams = implGetKdfParameters(EdECObjectIdentifiers.id_X448, algorithmParameters); + + return new ECDHPublicBCPGKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, getPointEncUncompressed(pubKey, X448.SCALAR_SIZE)), + kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); + } + // sun.security.ec.XDHPublicKeyImpl returns "XDH" for getAlgorithm() + // In this case we need to determine the curve by looking at the length of the encoding :/ + else + { + // Legacy X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) + if (X25519.SCALAR_SIZE + 12 == pubKey.getEncoded().length) // + 12 for some reason + { + PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters); + + return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)), + kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); + } + // Legacy X448 (1.3.101.111) + else + { + PGPKdfParameters kdfParams = implGetKdfParameters(EdECObjectIdentifiers.id_X448, algorithmParameters); + + return new ECDHPublicBCPGKey(EdECObjectIdentifiers.id_X448, new BigInteger(1, getPointEncUncompressed(pubKey, X448.SCALAR_SIZE)), + kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); + } + } + } + + X9ECParametersHolder params = ECNamedCurveTable.getByOIDLazy(curveOid); + + ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes()); + X9ECPoint derQ = new X9ECPoint(params.getCurve(), key); + + if (algorithm == PGPPublicKey.ECDH) + { + + PGPKdfParameters kdfParams = implGetKdfParameters(curveOid, algorithmParameters); + + return new ECDHPublicBCPGKey(curveOid, derQ.getPoint(), kdfParams.getHashAlgorithm(), + kdfParams.getSymmetricWrapAlgorithm()); + } + else + { + return new ECDSAPublicBCPGKey(curveOid, derQ.getPoint()); + } + } - ASN1OctetString key = new DEROctetString(keyInfo.getPublicKeyData().getBytes()); - X9ECPoint derQ = new X9ECPoint(params.getCurve(), key); + case PublicKeyAlgorithmTags.EDDSA_LEGACY: + { + // Legacy Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) + if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3)) + { + return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE))); + } + // Legacy Ed448 (1.3.101.113) + if (pubKey.getAlgorithm().regionMatches(true, 0, "ED4", 0, 3)) + { + return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, getPointEncUncompressed(pubKey, Ed448.PUBLIC_KEY_SIZE))); + } + // Manual matching on curve encoding length + else + { + // sun.security.ec.ed.EdDSAPublicKeyImpl returns "EdDSA" for getAlgorithm() + // if algorithm is just EdDSA, we need to detect the curve based on encoding length :/ + if (pubKey.getEncoded().length == 12 + Ed25519.PUBLIC_KEY_SIZE) // +12 for some reason + { + // Legacy Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) + return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE))); + } + else + { + // Legacy Ed448 (1.3.101.113) + return new EdDSAPublicBCPGKey(EdECObjectIdentifiers.id_Ed448, new BigInteger(1, getPointEncUncompressed(pubKey, Ed448.PUBLIC_KEY_SIZE))); + } + } + } - if (algorithm == PGPPublicKey.ECDH) + // Modern Ed25519 (1.3.6.1.4.1.11591.15.1 & 1.3.101.112) + case PublicKeyAlgorithmTags.Ed25519: { - PGPKdfParameters kdfParams = implGetKdfParameters(curveOid, algorithmParameters); + return getPublicBCPGKey(pubKey, Ed25519PublicBCPGKey.LENGTH, Ed25519PublicBCPGKey::new); + } - return new ECDHPublicBCPGKey(curveOid, derQ.getPoint(), kdfParams.getHashAlgorithm(), - kdfParams.getSymmetricWrapAlgorithm()); + // Modern Ed448 (1.3.101.113) + case PublicKeyAlgorithmTags.Ed448: + { + return getPublicBCPGKey(pubKey, Ed448PublicBCPGKey.LENGTH, Ed448PublicBCPGKey::new); } - else if (algorithm == PGPPublicKey.ECDSA) + + // Modern X25519 (1.3.6.1.4.1.3029.1.5.1 & 1.3.101.110) + case PublicKeyAlgorithmTags.X25519: { - return new ECDSAPublicBCPGKey(curveOid, derQ.getPoint()); + return getPublicBCPGKey(pubKey, X25519PublicBCPGKey.LENGTH, X25519PublicBCPGKey::new); } - else + // Modern X448 (1.3.101.111) + case PublicKeyAlgorithmTags.X448: { - throw new PGPException("unknown EC algorithm"); + return getPublicBCPGKey(pubKey, X448PublicBCPGKey.LENGTH, X448PublicBCPGKey::new); } - } - else if (algorithm == PGPPublicKey.Ed25519) - { - return getPublicBCPGKey(pubKey, Ed25519PublicBCPGKey.LENGTH, Ed25519PublicBCPGKey::new); - } - else if (pubKey.getAlgorithm().regionMatches(true, 0, "ED2", 0, 3)) - { - return new EdDSAPublicBCPGKey(GNUObjectIdentifiers.Ed25519, new BigInteger(1, getPointEncUncompressed(pubKey, Ed25519.PUBLIC_KEY_SIZE))); - } - else if (algorithm == PGPPublicKey.X25519) - { - return getPublicBCPGKey(pubKey, X25519PublicBCPGKey.LENGTH, X25519PublicBCPGKey::new); - } - else if (pubKey.getAlgorithm().regionMatches(true, 0, "X2", 0, 2)) - { - PGPKdfParameters kdfParams = implGetKdfParameters(CryptlibObjectIdentifiers.curvey25519, algorithmParameters); - return new ECDHPublicBCPGKey(CryptlibObjectIdentifiers.curvey25519, new BigInteger(1, getPointEncUncompressed(pubKey, X25519.SCALAR_SIZE)), - kdfParams.getHashAlgorithm(), kdfParams.getSymmetricWrapAlgorithm()); - } - else if (algorithm == PGPPublicKey.Ed448) - { - return getPublicBCPGKey(pubKey, Ed448PublicBCPGKey.LENGTH, Ed448PublicBCPGKey::new); - } - else if (algorithm == PGPPublicKey.X448) - { - return getPublicBCPGKey(pubKey, X448PublicBCPGKey.LENGTH, X448PublicBCPGKey::new); - } - else - { - throw new PGPException("unknown key class"); + default: + throw new PGPException("unknown public key algorithm encountered: " + algorithm); } } @@ -633,4 +765,17 @@ private PublicKey get25519PublicKey(BigInteger x, ASN1ObjectIdentifier algorithm } return implGetPublicKeyX509(pEnc, 1, algorithm, keyAlgorithm); } + + private PublicKey get448PublicKey(BigInteger x, ASN1ObjectIdentifier algorithm, String keyAlgorithm, String name) + throws PGPException, GeneralSecurityException, IOException + { + byte[] pEnc = BigIntegers.asUnsignedByteArray(x); + + // skip the 0x40 header byte. + if (pEnc.length < 1 || 0x40 != pEnc[0]) + { + throw new IllegalArgumentException("Invalid " + name + "448 public key"); + } + return implGetPublicKeyX509(pEnc, 1, algorithm, keyAlgorithm); + } } diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/AbstractPgpKeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/AbstractPgpKeyPairTest.java new file mode 100644 index 0000000000..507c85c153 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/AbstractPgpKeyPairTest.java @@ -0,0 +1,45 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.test.AbstractPacketTest; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.security.KeyPair; +import java.util.Date; + +public abstract class AbstractPgpKeyPairTest + extends AbstractPacketTest +{ + + public Date currentTimeRounded() + { + Date now = new Date(); + return new Date((now.getTime() / 1000) * 1000); // rounded to seconds + } + + public BcPGPKeyPair toBcKeyPair(JcaPGPKeyPair keyPair) + throws PGPException + { + BcPGPKeyConverter c = new BcPGPKeyConverter(); + return new BcPGPKeyPair(keyPair.getPublicKey().getAlgorithm(), + new AsymmetricCipherKeyPair( + c.getPublicKey(keyPair.getPublicKey()), + c.getPrivateKey(keyPair.getPrivateKey())), + keyPair.getPublicKey().getCreationTime()); + } + + public JcaPGPKeyPair toJcaKeyPair(BcPGPKeyPair keyPair) + throws PGPException + { + JcaPGPKeyConverter c = new JcaPGPKeyConverter(); + return new JcaPGPKeyPair(keyPair.getPublicKey().getAlgorithm(), + new KeyPair( + c.getPublicKey(keyPair.getPublicKey()), + c.getPrivateKey(keyPair.getPrivateKey())), + keyPair.getPublicKey().getCreationTime()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/Curve25519PrivateKeyEncodingTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/Curve25519PrivateKeyEncodingTest.java new file mode 100644 index 0000000000..96ecc77a44 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/Curve25519PrivateKeyEncodingTest.java @@ -0,0 +1,195 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.asn1.ASN1OctetString; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.bcpg.*; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; +import org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import org.bouncycastle.jcajce.spec.XDHParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.*; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.bouncycastle.util.Arrays; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +/** + * Curve25519Legacy ECDH Secret Key Material uses big-endian MPI form, + * while X25519 keys use little-endian native encoding. + * This test verifies that legacy X25519 keys using ECDH are reverse-encoded, + * while X25519 keys are natively encoded. + */ +public class Curve25519PrivateKeyEncodingTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "Curve25519PrivateKeyEncodingTest"; + } + + @Override + public void performTest() + throws Exception + { + containsTest(); + verifySecretKeyReverseEncoding(); + } + + private void verifySecretKeyReverseEncoding() + throws PGPException, IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException + { + bc_verifySecretKeyReverseEncoding(); + jca_verifySecretKeyReverseEncoding(); + } + + /** + * Verify that legacy ECDH keys over curve25519 encode the private key in reversed encoding, + * while dedicated X25519 keys use native encoding for the private key material. + * Test the JcaJce implementation. + * + * @throws NoSuchAlgorithmException + * @throws InvalidAlgorithmParameterException + * @throws PGPException + * @throws IOException + */ + private void jca_verifySecretKeyReverseEncoding() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException, IOException + { + JcaPGPKeyConverter c = new JcaPGPKeyConverter(); + + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("XDH", new BouncyCastleProvider()); + gen.initialize(new XDHParameterSpec("X25519")); + KeyPair kp = gen.generateKeyPair(); + + byte[] rawPrivateKey = jcaNativePrivateKey(kp.getPrivate()); + + // Legacy key uses reversed encoding + PGPKeyPair pgpECDHKeyPair = new JcaPGPKeyPair(PublicKeyAlgorithmTags.ECDH, kp, date); + byte[] encodedECDHPrivateKey = pgpECDHKeyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("ECDH Curve25519Legacy (X25519) key MUST encode secret key in 'reverse' (big-endian MPI encoding) (JCE implementation)", + containsSubsequence(encodedECDHPrivateKey, Arrays.reverse(rawPrivateKey))); + + byte[] decodedECDHPrivateKey = jcaNativePrivateKey(c.getPrivateKey(pgpECDHKeyPair.getPrivateKey())); + isEncodingEqual("Decoded ECDH Curve25519Legacy (X25519) key MUST match original raw key (JCE implementation)", + decodedECDHPrivateKey, rawPrivateKey); + + // X25519 key uses native encoding + PGPKeyPair pgpX25519KeyPair = new JcaPGPKeyPair(PublicKeyAlgorithmTags.X25519, kp, date); + byte[] encodedX25519PrivateKey = pgpX25519KeyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("X25519 key MUST use native encoding (little-endian) to encode the secret key material (JCE implementation)", + containsSubsequence(encodedX25519PrivateKey, rawPrivateKey)); + + byte[] decodedX25519PrivateKey = jcaNativePrivateKey(c.getPrivateKey(pgpX25519KeyPair.getPrivateKey())); + isEncodingEqual("Decoded X25519 key MUST match original raw key (JCE implementation)", + rawPrivateKey, decodedX25519PrivateKey); + } + + /** + * Return the native encoding of the given private key. + * @param privateKey private key + * @return native encoding + * @throws IOException + */ + private byte[] jcaNativePrivateKey(PrivateKey privateKey) + throws IOException + { + PrivateKeyInfo kInfo = PrivateKeyInfo.getInstance(privateKey.getEncoded()); + return ASN1OctetString.getInstance(kInfo.parsePrivateKey()).getOctets(); + } + + /** + * Verify that legacy ECDH keys over curve25519 encode the private key in reversed encoding, + * while dedicated X25519 keys use native encoding for the private key material. + * Test the BC implementation. + */ + private void bc_verifySecretKeyReverseEncoding() + throws PGPException + { + BcPGPKeyConverter c = new BcPGPKeyConverter(); + + Date date = currentTimeRounded(); + X25519KeyPairGenerator gen = new X25519KeyPairGenerator(); + gen.init(new X25519KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + byte[] rawPrivateKey = ((X25519PrivateKeyParameters) kp.getPrivate()).getEncoded(); + + // Legacy key uses reversed encoding + PGPKeyPair pgpECDHKeyPair = new BcPGPKeyPair(PublicKeyAlgorithmTags.ECDH, kp, date); + byte[] encodedECDHPrivateKey = pgpECDHKeyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("ECDH Curve25519Legacy (X25519) key MUST encode secret key in 'reverse' (big-endian MPI encoding) (BC implementation)", + containsSubsequence(encodedECDHPrivateKey, Arrays.reverse(rawPrivateKey))); + + byte[] decodedECDHPrivateKey = ((X25519PrivateKeyParameters) c.getPrivateKey(pgpECDHKeyPair.getPrivateKey())).getEncoded(); + isEncodingEqual("Decoded ECDH Curve25519Legacy (X25519) key MUST match original raw key (BC implementation)", + decodedECDHPrivateKey, rawPrivateKey); + + // X25519 key uses native encoding + PGPKeyPair pgpX25519KeyPair = new BcPGPKeyPair(PublicKeyAlgorithmTags.X25519, kp, date); + byte[] encodedX25519PrivateKey = pgpX25519KeyPair.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("X25519 key MUST use native encoding (little-endian) to encode the secret key material (BC implementation)", + containsSubsequence(encodedX25519PrivateKey, rawPrivateKey)); + + byte[] decodedX25519PrivateKey = ((X25519PrivateKeyParameters) c.getPrivateKey(pgpX25519KeyPair.getPrivateKey())).getEncoded(); + isEncodingEqual("Decoded X25519 key MUST match original raw key (BC implementation)", + rawPrivateKey, decodedX25519PrivateKey); + } + + /** + * Return true, if the given sequence contains the given subsequence entirely. + * @param sequence sequence + * @param subsequence subsequence + * @return true if subsequence is a subsequence of sequence + */ + public boolean containsSubsequence(byte[] sequence, byte[] subsequence) + { + outer: for (int i = 0; i < sequence.length - subsequence.length + 1; i++) + { + for (int j = 0; j < subsequence.length; j++) + { + if (sequence[i + j] != subsequence[j]) + { + continue outer; + } + } + return true; + } + return false; + } + + /** + * Test proper functionality of the {@link #containsSubsequence(byte[], byte[])} method. + */ + private void containsTest() { + // Make sure our containsSubsequence method functions correctly + byte[] s = new byte[] {0x00, 0x01, 0x02, 0x03}; + isTrue(containsSubsequence(s, new byte[] {0x00, 0x01})); + isTrue(containsSubsequence(s, new byte[] {0x01, 0x02})); + isTrue(containsSubsequence(s, new byte[] {0x02, 0x03})); + isTrue(containsSubsequence(s, new byte[] {0x00})); + isTrue(containsSubsequence(s, new byte[] {0x03})); + isTrue(containsSubsequence(s, new byte[] {0x00, 0x01, 0x02, 0x03})); + isTrue(containsSubsequence(s, new byte[0])); + isTrue(containsSubsequence(new byte[0], new byte[0])); + + isFalse(containsSubsequence(s, new byte[] {0x00, 0x02})); + isFalse(containsSubsequence(s, new byte[] {0x00, 0x00})); + isFalse(containsSubsequence(s, new byte[] {0x00, 0x01, 0x02, 0x03, 0x04})); + isFalse(containsSubsequence(s, new byte[] {0x04})); + isFalse(containsSubsequence(new byte[0], new byte[] {0x00})); + } + + public static void main(String[] args) + { + runTest(new Curve25519PrivateKeyEncodingTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedEd25519KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedEd25519KeyPairTest.java new file mode 100644 index 0000000000..7a2cf69b25 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedEd25519KeyPairTest.java @@ -0,0 +1,158 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.*; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; +import org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.EdDSAParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.PGPPublicKey; +import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyConverter; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyConverter; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; +import org.bouncycastle.util.Pack; +import org.bouncycastle.util.encoders.Hex; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class DedicatedEd25519KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "DedicatedEd25519KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + + testConversionOfTestVectorKey(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider()); + gen.initialize(new EdDSAParameterSpec("Ed25519")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.Ed25519, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + Ed25519KeyPairGenerator gen = new Ed25519KeyPairGenerator(); + gen.init(new Ed25519KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.Ed25519, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed25519 public key MUST be instanceof Ed25519PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed25519PublicBCPGKey); + isTrue("Dedicated Ed25519 secret key MUST be instanceof Ed25519SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed25519SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfTestVectorKey() throws PGPException, IOException { + JcaPGPKeyConverter jc = new JcaPGPKeyConverter().setProvider(new BouncyCastleProvider()); + BcPGPKeyConverter bc = new BcPGPKeyConverter(); + // ed25519 public key from https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-13.html#name-hashed-data-stream-for-sign + // just adapted to be a version 4 key. + Date creationTime = new Date(Pack.bigEndianToInt(Hex.decode("63877fe3"), 0) * 1000L); + byte[] k = Hex.decode("f94da7bb48d60a61e567706a6587d0331999bb9d891a08242ead84543df895a3"); + PGPPublicKey v4k = new PGPPublicKey( + new PublicKeyPacket(PublicKeyAlgorithmTags.Ed25519, creationTime, new Ed25519PublicBCPGKey(k)), + new BcKeyFingerprintCalculator() + ); + + // convert parsed key to Jca public key + PublicKey jcpk = jc.getPublicKey(v4k); + PGPPublicKey jck = jc.getPGPPublicKey(PublicKeyAlgorithmTags.Ed25519, jcpk, creationTime); + isEncodingEqual(v4k.getEncoded(), jck.getEncoded()); + + // convert parsed key to Bc public key + AsymmetricKeyParameter bcpk = bc.getPublicKey(v4k); + PGPPublicKey bck = bc.getPGPPublicKey(PublicKeyAlgorithmTags.Ed25519, null, bcpk, creationTime); + isEncodingEqual(v4k.getEncoded(), bck.getEncoded()); + } + + public static void main(String[] args) + { + runTest(new DedicatedEd25519KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedEd448KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedEd448KeyPairTest.java new file mode 100644 index 0000000000..e353bc9922 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedEd448KeyPairTest.java @@ -0,0 +1,128 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.Ed448PublicBCPGKey; +import org.bouncycastle.bcpg.Ed448SecretBCPGKey; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.Ed448KeyPairGenerator; +import org.bouncycastle.crypto.params.Ed448KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.EdDSAParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class DedicatedEd448KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "DedicatedEd448KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider()); + gen.initialize(new EdDSAParameterSpec("Ed448")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.Ed448, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + Ed448KeyPairGenerator gen = new Ed448KeyPairGenerator(); + gen.init(new Ed448KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.Ed448, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated Ed448 public key MUST be instanceof Ed448PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof Ed448PublicBCPGKey); + isTrue("Dedicated Ed448 secret key MUST be instanceof Ed448SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof Ed448SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + public static void main(String[] args) + { + runTest(new DedicatedEd448KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedX25519KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedX25519KeyPairTest.java new file mode 100644 index 0000000000..6de196eb47 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedX25519KeyPairTest.java @@ -0,0 +1,128 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.bcpg.X25519PublicBCPGKey; +import org.bouncycastle.bcpg.X25519SecretBCPGKey; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; +import org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.XDHParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class DedicatedX25519KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "DedicatedX25519KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("XDH", new BouncyCastleProvider()); + gen.initialize(new XDHParameterSpec("X25519")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.X25519, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + X25519KeyPairGenerator gen = new X25519KeyPairGenerator(); + gen.init(new X25519KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.X25519, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X25519 public key MUST be instanceof X25519PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof X25519PublicBCPGKey); + isTrue("Dedicated X25519 secret key MUST be instanceof X25519SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof X25519SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + public static void main(String[] args) + { + runTest(new DedicatedX25519KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedX448KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedX448KeyPairTest.java new file mode 100644 index 0000000000..42e19a3170 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/DedicatedX448KeyPairTest.java @@ -0,0 +1,128 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.X448PublicBCPGKey; +import org.bouncycastle.bcpg.X448SecretBCPGKey; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.X448KeyPairGenerator; +import org.bouncycastle.crypto.params.X448KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.XDHParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class DedicatedX448KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "DedicatedX448KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, PGPException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("XDH", new BouncyCastleProvider()); + gen.initialize(new XDHParameterSpec("X448")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.X448, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + X448KeyPairGenerator gen = new X448KeyPairGenerator(); + gen.init(new X448KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.X448, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Dedicated X448 public key MUST be instanceof X448PublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof X448PublicBCPGKey); + isTrue("Dedicated X448 secret key MUST be instanceof X448SecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof X448SecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + public static void main(String[] args) + { + runTest(new DedicatedX448KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyEd25519KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyEd25519KeyPairTest.java new file mode 100644 index 0000000000..fda4d0d7d2 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyEd25519KeyPairTest.java @@ -0,0 +1,128 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.EdDSAPublicBCPGKey; +import org.bouncycastle.bcpg.EdSecretBCPGKey; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; +import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.EdDSAParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class LegacyEd25519KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "LegacyEd25519KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider()); + gen.initialize(new EdDSAParameterSpec("Ed25519")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + Ed25519KeyPairGenerator gen = new Ed25519KeyPairGenerator(); + gen.init(new Ed25519KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed25519 public key MUST be instanceof EdDSAPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed25519 secret key MUST be instanceof EdSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + public static void main(String[] args) + { + runTest(new LegacyEd25519KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyEd448KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyEd448KeyPairTest.java new file mode 100644 index 0000000000..07f320df3d --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyEd448KeyPairTest.java @@ -0,0 +1,126 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.*; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.Ed448KeyPairGenerator; +import org.bouncycastle.crypto.params.Ed448KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.EdDSAParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.*; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class LegacyEd448KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "LegacyEd448KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("EDDSA", new BouncyCastleProvider()); + gen.initialize(new EdDSAParameterSpec("Ed448")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + Ed448KeyPairGenerator gen = new Ed448KeyPairGenerator(); + gen.init(new Ed448KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.EDDSA_LEGACY, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy Ed448 public key MUST be instanceof EdDSAPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof EdDSAPublicBCPGKey); + isTrue("Legacy Ed448 secret key MUST be instanceof EdSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof EdSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + public static void main(String[] args) + { + runTest(new LegacyEd448KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyX25519KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyX25519KeyPairTest.java new file mode 100644 index 0000000000..55a008875b --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyX25519KeyPairTest.java @@ -0,0 +1,128 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.ECDHPublicBCPGKey; +import org.bouncycastle.bcpg.ECSecretBCPGKey; +import org.bouncycastle.bcpg.PublicKeyAlgorithmTags; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.X25519KeyPairGenerator; +import org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.XDHParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class LegacyX25519KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "LegacyX25519KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("XDH", new BouncyCastleProvider()); + gen.initialize(new XDHParameterSpec("X25519")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.ECDH, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + X25519KeyPairGenerator gen = new X25519KeyPairGenerator(); + gen.init(new X25519KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.ECDH, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X25519 public key MUST be instanceof ECDHPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X25519 secret key MUST be instanceof ECSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + public static void main(String[] args) + { + runTest(new LegacyX25519KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyX448KeyPairTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyX448KeyPairTest.java new file mode 100644 index 0000000000..61c04c5f54 --- /dev/null +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/LegacyX448KeyPairTest.java @@ -0,0 +1,126 @@ +package org.bouncycastle.openpgp.test; + +import org.bouncycastle.bcpg.*; +import org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import org.bouncycastle.crypto.generators.X448KeyPairGenerator; +import org.bouncycastle.crypto.params.X448KeyGenerationParameters; +import org.bouncycastle.jcajce.spec.XDHParameterSpec; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openpgp.PGPException; +import org.bouncycastle.openpgp.operator.bc.BcPGPKeyPair; +import org.bouncycastle.openpgp.operator.jcajce.JcaPGPKeyPair; + +import java.io.IOException; +import java.security.*; +import java.util.Date; + +public class LegacyX448KeyPairTest + extends AbstractPgpKeyPairTest +{ + @Override + public String getName() + { + return "LegacyX448KeyPairTest"; + } + + @Override + public void performTest() + throws Exception + { + testConversionOfJcaKeyPair(); + testConversionOfBcKeyPair(); + } + + private void testConversionOfJcaKeyPair() + throws NoSuchAlgorithmException, PGPException, InvalidAlgorithmParameterException, IOException + { + Date date = currentTimeRounded(); + KeyPairGenerator gen = KeyPairGenerator.getInstance("XDH", new BouncyCastleProvider()); + gen.initialize(new XDHParameterSpec("X448")); + KeyPair kp = gen.generateKeyPair(); + + JcaPGPKeyPair j1 = new JcaPGPKeyPair(PublicKeyAlgorithmTags.ECDH, kp, date); + byte[] pubEnc = j1.getPublicKey().getEncoded(); + byte[] privEnc = j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + BcPGPKeyPair b1 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j2); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), b2.getPublicKey().getCreationTime().getTime()); + } + + private void testConversionOfBcKeyPair() + throws PGPException, IOException + { + Date date = currentTimeRounded(); + X448KeyPairGenerator gen = new X448KeyPairGenerator(); + gen.init(new X448KeyGenerationParameters(new SecureRandom())); + AsymmetricCipherKeyPair kp = gen.generateKeyPair(); + + BcPGPKeyPair b1 = new BcPGPKeyPair(PublicKeyAlgorithmTags.ECDH, kp, date); + byte[] pubEnc = b1.getPublicKey().getEncoded(); + byte[] privEnc = b1.getPrivateKey().getPrivateKeyDataPacket().getEncoded(); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + b1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + b1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + JcaPGPKeyPair j1 = toJcaKeyPair(b1); + isEncodingEqual(pubEnc, j1.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j1.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + j1.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + j1.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + BcPGPKeyPair b2 = toBcKeyPair(j1); + isEncodingEqual(pubEnc, b2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, b2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + b2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + b2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + JcaPGPKeyPair j2 = toJcaKeyPair(b2); + isEncodingEqual(pubEnc, j2.getPublicKey().getEncoded()); + isEncodingEqual(privEnc, j2.getPrivateKey().getPrivateKeyDataPacket().getEncoded()); + isTrue("Legacy X448 public key MUST be instanceof ECDHPublicBCPGKey", + j2.getPublicKey().getPublicKeyPacket().getKey() instanceof ECDHPublicBCPGKey); + isTrue("Legacy X448 secret key MUST be instanceof ECSecretBCPGKey", + j2.getPrivateKey().getPrivateKeyDataPacket() instanceof ECSecretBCPGKey); + + isEquals("Creation time is preserved", + date.getTime(), j2.getPublicKey().getCreationTime().getTime()); + } + + public static void main(String[] args) + { + runTest(new LegacyX448KeyPairTest()); + } +} diff --git a/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java b/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java index 2cf6ad463c..e9a4c11e3c 100644 --- a/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java +++ b/pg/src/test/java/org/bouncycastle/openpgp/test/RegressionTest.java @@ -62,7 +62,19 @@ public class RegressionTest new BcImplProviderTest(), new OperatorJcajceTest(), new OpenPGPTest(), - new OperatorBcTest() + new OperatorBcTest(), + + new DedicatedEd25519KeyPairTest(), + new DedicatedEd448KeyPairTest(), + new DedicatedX25519KeyPairTest(), + new DedicatedX448KeyPairTest(), + + new LegacyEd25519KeyPairTest(), + new LegacyEd448KeyPairTest(), + new LegacyX25519KeyPairTest(), + new LegacyX448KeyPairTest(), + + new Curve25519PrivateKeyEncodingTest() }; public static void main(String[] args)