0

I need help on how to correctly generate PGPKeyring that contains 3 keys each for signing, encryption, and authentication. These keys to be uploaded to a smartcard with SmartPGP applet. I have successfully put the keys into the card, and tested it with the OpenKeyChain. But it only works when I am using RSA type of keys.

My code to generate the keys is as follows:

private PgpKeyRingGenerator CreatePgpKeyRingGenerator(string email, string signatureKeyAlg, string encryptionKeyAlg, string authenticationKeyAlg)
{
        PgpKeyPair signatureKeyPair = CreatePgpKeyPair(signatureKeyAlg, false); 
        int certificationLevel = PgpSignature.DefaultCertification;
        string id = email;
        SymmetricKeyAlgorithmTag encAlgorithm = SymmetricKeyAlgorithmTag.Null;
        HashAlgorithmTag hashAlgorithm = HashAlgorithmTag.Sha256;
        char[] rawPassPhrase = null;
        bool useSha1 = true; 
        PgpSignatureSubpacketGenerator masterHashGen = new PgpSignatureSubpacketGenerator();
        masterHashGen.SetKeyFlags(false, PgpKeyFlags.CanSign | PgpKeyFlags.CanCertify);
        
        PgpSignatureSubpacketVector masterHashedPackets = masterHashGen.Generate();
        PgpSignatureSubpacketVector unhashedPackets = null;
        PgpKeyRingGenerator pgpKeyRingGenerator = new PgpKeyRingGenerator(certificationLevel, signatureKeyPair, id, encAlgorithm, hashAlgorithm, rawPassPhrase, useSha1, masterHashedPackets, unhashedPackets, new Org.BouncyCastle.Security.SecureRandom());

        PgpKeyPair encSubKeyPair = CreatePgpKeyPair(encryptionKeyAlg, true); 
        PgpSignatureSubpacketGenerator encHashGen = new PgpSignatureSubpacketGenerator();
        encHashGen.SetKeyFlags(false, PgpKeyFlags.CanEncryptStorage | PgpKeyFlags.CanEncryptStorage);
        PgpSignatureSubpacketVector encHashedPackets = encHashGen.Generate();
        pgpKeyRingGenerator.AddSubKey(encSubKeyPair, encHashedPackets, null);

        PgpKeyPair authSubKeyPair = CreatePgpKeyPair(authenticationKeyAlg, true);
        PgpSignatureSubpacketGenerator authHashGen = new PgpSignatureSubpacketGenerator();
        authHashGen.SetKeyFlags(false, 0x20);       // CanAuth
        PgpSignatureSubpacketVector authHashedPackets = authHashGen.Generate();
        pgpKeyRingGenerator.AddSubKey(authSubKeyPair, authHashedPackets, null);

        return pgpKeyRingGenerator;
}

private PgpKeyPair CreatePgpKeyPair(string algorithm, bool subKey)
{
        switch (algorithm)
        {
                case "RSA-2048":
                    return CreateRsaKeyPair(2048, PublicKeyAlgorithmTag.RsaGeneral);
                case "RSA-3072":
                    return CreateRsaKeyPair(3072, PublicKeyAlgorithmTag.RsaGeneral);
                case "RSA-4096":
                    return CreateRsaKeyPair(4096, PublicKeyAlgorithmTag.RsaGeneral);
                case "EC-256 (nistP256r1)":
                    return CreateEcKeyPair(EcObjectIdentifiers.NIST_P_256, (subKey ? PublicKeyAlgorithmTag.ECDH : PublicKeyAlgorithmTag.ECDsa));
                case "EC-256 (brainpoolP256r1)":
                    return CreateEcKeyPair(EcObjectIdentifiers.BRAINPOOL_P256_R1, (subKey ? PublicKeyAlgorithmTag.ECDH : PublicKeyAlgorithmTag.ECDsa));
                case "EC-384 (nistP384r1)":
                    return CreateEcKeyPair(EcObjectIdentifiers.NIST_P_384, (subKey ? PublicKeyAlgorithmTag.ECDH : PublicKeyAlgorithmTag.ECDsa));
                case "EC-384 (brainpoolP384r1)":
                    return CreateEcKeyPair(EcObjectIdentifiers.BRAINPOOL_P384_R1, (subKey ? PublicKeyAlgorithmTag.ECDH : PublicKeyAlgorithmTag.ECDsa));
                case "EC-512 (nistP521r1)":
                    return CreateEcKeyPair(EcObjectIdentifiers.NIST_P_521, (subKey ? PublicKeyAlgorithmTag.ECDH : PublicKeyAlgorithmTag.ECDsa));
                case "EC-512 (brainpoolP512r1)":
                    return CreateEcKeyPair(EcObjectIdentifiers.BRAINPOOL_P512_R1, (subKey ? PublicKeyAlgorithmTag.ECDH : PublicKeyAlgorithmTag.ECDsa));
                default:
                    throw new Exception("invalid algorithm: " + algorithm);
        }
}

private PgpKeyPair CreateRsaKeyPair(int length, PublicKeyAlgorithmTag tag)
{
         DateTime currentUtcDt = DateTime.UtcNow;

         var rsaKeyGen = GeneratorUtilities.GetKeyPairGenerator("RSA");
         KeyGenerationParameters keyGenerationParameters = new KeyGenerationParameters(new SecureRandom(), length);
         rsaKeyGen.Init(keyGenerationParameters);
            
         PgpKeyPair pgpKeyPair = new PgpKeyPair(tag, rsaKeyGen.GenerateKeyPair(), currentUtcDt);
         return pgpKeyPair;
}

private PgpKeyPair CreateEcKeyPair(DerObjectIdentifier oid, PublicKeyAlgorithmTag tag)
{
         DateTime currentUtcDt = DateTime.UtcNow;

         ECDomainParameters eCDomainParameters = new ECDomainParameters(ECNamedCurveTable.GetByOid(oid));
         var ecdhKeyGen = GeneratorUtilities.GetKeyPairGenerator("ECDH");
         ecdhKeyGen.Init(new ECKeyGenerationParameters(eCDomainParameters, new SecureRandom()));
         var masterKeyPair = ecdhKeyGen.GenerateKeyPair();
         ECPublicKeyParameters masterPk = (ECPublicKeyParameters)masterKeyPair.Public;

         masterPk = new ECPublicKeyParameters("ECDH", masterPk.Q, oid);   // need to be remake, so we can add the curveOid parameter, otherwise it will cause null error during public key packet encoding
         PgpKeyPair masterPgpKeyPair = new PgpKeyPair(tag, masterPk, masterKeyPair.Private, currentUtcDt);  // need to use ECDsa otherwise if using ECDH it will cause Signature generation error at PgpKeyRingGenerator

         return masterPgpKeyPair;
}

Example calling the program:

// rsa 
CreatePgpKeyRingGenerator("linrsa@mail.com", "RSA-2048", "RSA-2048", "RSA-2048");

// ec
CreatePgpKeyRingGenerator("lin@mail.com", "EC-256 (brainpoolP256r1)", "EC-256 (brainpoolP256r1)", "EC-256 (brainpoolP256r1)");

With the code above when using RSA type of keys, it can be successfully imported in Kleopatra, see the screenshot below: enter image description here

But when creating EC type of keys, e.g: using brainpoolP256r1 the import show hash warning, and i dont know which part to edit in the above code, also only the master key is imported in Kleopatra and the subkeys is not. See the screenshots below: enter image description here enter image description here

Any suggestion is appreciated.

of32 inc
  • 105
  • 1
  • 7

0 Answers0