2

I wrote a test program to read a users cert from the cert store, and encrypt some text. However, I realize that the encryption algorithm used is 3DES. I need to change this to AES-256. I read a similar post on here, but for me, i think my situation is slightly different...So, I'll get straight to the point.

Using the suggested method:

var recipient = new CmsRecipient("MyCert.cer");
        recipient.EncryptionAlgorithms = new EncryptionAlgorithm[] {
            EncryptionAlgorithm.Aes256
        };           
        var CmsCollection = new CmsRecipientCollection();
        CmsCollection.Add(recipient);
// Followed by calling ApplicationPkcs7Mime.Encrypt(CmsCollection, p7m);

I'm able to change the encryption algorithm... However my key-encryption algorithm, is not the same if I were to do it using my original method of simply using the MailboxAddress to encrypt. E.g.:

MimeMessage mm = new MimeMessage();
        mm.From.Add(new MailboxAddress(from));
        mm.To.Add(new MailboxAddress(to));
ApplicationPkcs7Mime.Encrypt(mm.To.Mailboxes, p7m);

Using the CmsRecipientCollection method, this is the result of my pkcs7m file:

CmsRecipientCollection method

You can see, that the key-encryption algorithm has changed to rsaOAEP,and the email client that I'm sending this message to cannot recognize this algorithm.

Whereas, using the Mailbox method to encrypt:

Mailbox Metho

I'm stuck with 3DES, while the key encryption algorithm is correct...

So I guess, end of day, what I'm asking is, is there a way to get both key-encryption algorithm to be rsaEncryption, and the block cipher to be AES-256?

I saw an method UpdateSecureMimeCapabilities in the API reference, would this be able to do the job?

Also, I guess a more fundamental question is, why would the key-encryption algorithm change if both methods are essentially using the same cert?

Thanks!

Update: So I created a custom class to override the GetPreferredEncryptionAlgorithm function, however it's still falling back to 3DES.

public class CustomWindowsSecureMimeContext : WindowsSecureMimeContext
    {
        public CustomWindowsSecureMimeContext () : base ()
        {

        }
        protected override EncryptionAlgorithm GetPreferredEncryptionAlgorithm(CmsRecipientCollection recipients)
        {
            return EncryptionAlgorithm.Aes256;
        }
    }

Did I override it correctly?

Kelvin L
  • 65
  • 1
  • 10

1 Answers1

2

The UpdateSecureMimeCapabilities method isn't going to help in your case. It's not used when enveloping data, it's only used when decoding signed messages (it's a way for you to update your database of S/MIME capabilities of the email clients used by your correspondents).

There is no way to specify a key encryption algorithm in MimeKit because I haven't been able to figure out how to specify it in BouncyCastle (used by any of the BouncyCastleSecureMimeContext subclasses) nor in Microsoft's CMS API (used by WindowsSecureMimeContext). It seems to make that decision on its own.

Whichever SecureMimeContext class you use, you can override the GetPreferredEncryptionAlgorithm() method(s) to provide your own algorithm for choosing an encryption algorithm that would be suitable to use to encrypt the message to all of the specified recipients -or- you could override the GetCmsRecipient() method which takes a MailboxAddress and creates a new CmsRecipient for that recipient.

The other option is to use the MimeKit.Cryptography.CmsRecipient[Collection] API's in order to set the CmsRecipient.EncryptionAlgorithms property which represents the encryption algorithms supported by that recipient's email client. If you set an array of EncryptionAlgorithms that includes Aes256 for each recipient, then that algorithm will be chosen.

jstedfast
  • 35,744
  • 5
  • 97
  • 110
  • Any ideas why it's choosing different key encryption algo for basically the same cert? – Kelvin L Dec 27 '18 at 00:48
  • Nope. No clue. I haven’t dived into the BouncyCastle code all that much. – jstedfast Dec 27 '18 at 00:50
  • You mentioned that when I use the encrypt() function with a Mailbox object, it's essentially creating a CmsRecipient object internally. Could I copy that chunk of code, and then add in a part to force it to use Aes-256? – Kelvin L Dec 27 '18 at 00:57
  • It would probably be easiest if you just subclass DefaultSecureMimeContext (or whatever context class you are using) and override `GetCmsRecipient()` and just call into base and then just override the EncryptionAlgorithms property. – jstedfast Dec 27 '18 at 01:32
  • Or, possibly even simpler yet, override the GetPreferredEncryptionAlgorithm() on DefaultSecureMimeContext and just return EncryptionAlgorithm.Aes256. – jstedfast Dec 27 '18 at 01:34
  • Also, the base GetCmsRecipient() returns a System.Security.Cryptography.Pkcs.CmsRecipient object. – Kelvin L Dec 27 '18 at 05:42
  • Right, because you are using WindowsSecureMimeContext which is completely different from DefaultSecureMimeContext. WindowsSecureMimeContext doesn't use BouncyCastle, it uses System.Security's crypto API (hence the different CmsRecipient type). Overriding GetPreferredEncryptionAlgorithm() should still work, though. Try stepping thru the code in a debugger, perhaps, and seeing where things are going wrong? – jstedfast Dec 27 '18 at 15:25
  • Yeah, so for whatever reason, GetPreferredEncryptionAlgorithm() just wasn't getting called (I did a console.writeline() in the function and it never appeared). So, I had to go the long route and override encrypt() and a whole bunch of other stuff. Where I forced it to Aes256 was in Envelope() with var algorithm = EncryptionAlgorithm.Aes256; I also discovered that there indeed is a way of forcing the key encryption algo to RSA (albeit a dirty hack) from here: https://www.limilabs.com/qa/2442/using-rsa-encryption. Where I implemented this hack was in the other Envelope function... – Kelvin L Dec 27 '18 at 16:03
  • Did you use the SubjectKeyIdentifier option? – jstedfast Dec 27 '18 at 16:07
  • If the GetPreferredEncryptionAlgorithm() method is not getting called, did you register your CustomSecureMimeContext with `CryptographyContext.Register()` and/or explicitly pass your custom ctx as an argument to the encrypt method? If not, that's probably why. – jstedfast Dec 27 '18 at 16:10
  • So, using the SubjectKeyIdentifier would have worked, however the smime client that I was sending to couldn't decrypt it correctly. I needed to use the IssuerAndSerialNumber option (which I implemented in GetCmsRecipient. However, that brought me back to square one, where the EnvelopedCms was selecting RsaOaep for key encryption. Hence, I had to use UnprotectedAttributes option. So, I basically needed a combination of both in order to get my smime client to recognize and decrypt the p7m file. And also yes, the smime (outlook plugin) is very poorly written and we are looking to replace it. – Kelvin L Dec 27 '18 at 16:58
  • Regarding the GetPreferredEncryptionAlgorithm() not getting called, I did both Register() and also pass ctx into encrypt(). Every other one of the override-ed functions was getting called, except that one... very strange. – Kelvin L Dec 27 '18 at 17:01
  • Oh, I bet I understand the problem. There are 2 different GetPreferredEncryptionAlgorithm() methods for WindowsSecureMimeContext. One takes a System.Security CmsRecipientCollection and one takes a MimeKit.Cryptography.CmsRecipientCollection. You probably overrode the wrong one. – jstedfast Dec 27 '18 at 17:29
  • Yup, you are right. In my haste to hammer out the code I let the Intellisense auto complete the function parameter for me, and I never looked back. Thanks! – Kelvin L Dec 28 '18 at 01:11