2

I'm using BouncyCastle (BC) API for C#.

After Hours going through this API hell i figured out how to sign/verify and encrypt/decrypt using CMS with BC. I have to encrypt the symmetric key for the CMSEnvelope with RSA-OAEP (SHA256 + MGF1 with SHA256) as key encryption algorithm. On default BC obviously uses RSA.

In RecipientInfo structure of the CMS envelope I have to use KeyTransRecipientInfo.

I can't figure out how to set the RSA-OAEP-algorithm to the recipientInfo:

    //Create Encrypted cms envelope
      X509Certificate otherscert = new X509CertificateParser().ReadCertificate(myCertBytes)
      CmsEnvelopedDataGenerator envDataGen = new CmsEnvelopedDataGenerator();
      envDataGen.AddKeyTransRecipient(othersCert); //setting Cert, but how the key encr. algorithm?
      CmsProcessableByteArray sData = new CmsProcessableByteArray(signedData.GetEncoded());
      var envData =  envDataGen.Generate(sData, CmsEnvelopedDataGenerator.Aes256Cbc); //generate the envelope

Now in the recipientInfo KeyEncryptionAlgOid is 1.2.840.113549.1.1.1 (RSA)

I need it to be 1.2.840.113549.1.1.7 (RSA-OAEP) with the mentioned key encryption parameters.

Any idea how to do that in BC's C#-API?


EDIT:

Now I got the Source from Git and did the following edits. The problem was not just setting the keyEncryptionAlgorithm to the recipient. BC's logic takes the certificates SubjectPublicKeyInfo-algorithm for key encryption.

in CMSEnvelopedGenerator.cs I added

public void AddKeyTransRecipientRsaOaep(
            X509Certificate cert, DerObjectIdentifier digest, DerObjectIdentifier mgf1digest, AlgorithmIdentifier pSource = null)
        {
            if (pSource == null)
            {
                pSource = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdPSpecified, new DerOctetString(new byte[0]));
            }
            AlgorithmIdentifier hash = new AlgorithmIdentifier(digest, DerNull.Instance);
            AlgorithmIdentifier mask = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, mgf1digest);
            var rsaOaepParams = new RsaesOaepParameters(hash, mask, pSource);

            KeyTransRecipientInfoGenerator ktrig = new KeyTransRecipientInfoGenerator();
            ktrig.RecipientCert = cert;
            ktrig.AlgorithmId = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdRsaesOaep, rsaOaepParams);

            recipientInfoGenerators.Add(ktrig);
        }

In KeyTransrecipientInfoGenerator.cs I added

private AlgorithmIdentifier keyEncryptionAlg;
    ...
 internal AlgorithmIdentifier AlgorithmId
        {
            set
            {
                keyEncryptionAlg = value;
            }
        }

...
protected virtual AlgorithmIdentifier AlgorithmDetails
        {
            get
            {
                if (keyEncryptionAlg == null)
                {
                    return info.AlgorithmID;
                }
                else
                {
                    return keyEncryptionAlg;
                }
            }
        }
//In the Generate() method I changed 
  keyEncryptionAlgorithm = AlgorithmDetails;
//to
  AlgorithmIdentifier keyEncryptionAlgorithm;
  if (this.keyEncryptionAlg != null)
  {
    keyEncryptionAlgorithm = this.keyEncryptionAlg;
  }
  else
  {
    keyEncryptionAlgorithm = AlgorithmDetails;
  }

Now the keyEncryption algorithm and parameters are set correctly and it encrypts without exception:

CmsEnvelopedDataGenerator envDataGen = new CmsEnvelopedDataGenerator();
envDataGen.AddKeyTransRecipientRsaOaep(othersCert, NistObjectIdentifiers.IdSha256, NistObjectIdentifiers.IdSha256);
CmsProcessableByteArray sData = new CmsProcessableByteArray(signedData.GetEncoded());
            var envData =  envDataGen.Generate(sData, CmsEnvelopedDataGenerator.Aes256Cbc);

Reading the Envelope with BC or NetCore3 works fine. The RecipientInfos are set as intended (keyEncryptionAlgorithm, params).

But Decryption fails on both... :(

Jorg busch
  • 21
  • 3
  • 1
    GitHub issue for the same problem [here](https://github.com/bcgit/bc-csharp/issues/106). As the API & runtime of the C# and Java code base are usually mirrored, a similar issue for Java [here](https://stackoverflow.com/questions/43590554/decrypttion-fails-on-s-mime-enveloped-message-with-oaep-key-encryption) (unanswered as of now). And yeah, probably also requires code changes for decryption, of course. Both CMS and PGP functionality tend to get stuck in the past, unfortunately. – Maarten Bodewes Dec 10 '19 at 14:21
  • 1
    For what it’s worth, the EnvelopedCms class that comes with .NET supports OAEP. – bartonjs Dec 10 '19 at 15:44
  • @bartonjs So there is a part where the .NET crypto API has *more* support than a competing library? That's rare, but credit where it is due, I suppose :) – Maarten Bodewes Dec 10 '19 at 18:50
  • @bartonjs: for .NetCore only since 3.0. A least BC is able to decrypt the RSA-OAEP key after I encrypted it in netcore3.0... ;). Unfortunately it's a mess reading PEM-Files in Net. I will try the suggested code adjustment in [github](https://github.com/bcgit/bc-csharp/issues/106) – Jorg busch Dec 11 '19 at 17:09
  • In Netcore 3.0/3.1 encrypt the private key with rsaes-oaep-Sha256 works fine, but decryption isn't implemented.Only rsaes-oaep-Sha1 is implemented. So now I can only encrypt with netCore 3.0 and decrypt only with BouncyCastle... what the heck. – Jorg busch Dec 14 '19 at 00:46
  • You can perform the PEM parsing itself using bouncy castle. I'm *pretty sure* that there is a proposal for a PEM library for .NET on GitHub. Very very sure actually. – Maarten Bodewes Dec 14 '19 at 22:45

0 Answers0