EnvelopedCMS with AES and rsaEncryption (PKCS#1 v1

2019-02-13 21:01发布

I've been using .NET for cryptographic purposes a bit. Up to now, I used 3DES (Oid 1.2.840.113549.3.7) in combination with rsaEncryption (Oid 1.2.840.113549.1.1.1, RSAES-PKCS1-v1_5). While the first one has now to be replaced by AES (Oid 2.16.840.1.101.3.4.1.42), I still have to use rsaEncryption / RSAES-PKCS1-v1_5, not RSAES-OAEP.

If I just pass an additional argument to the EnvelopedCMS constructor that I'm calling, I can switch from 3DES to AES:

    ContentInfo plainContent = new ContentInfo(new Oid("1.2.840.113549.1.7.1"), data);

    EnvelopedCms encryptedMessage = new EnvelopedCms(plainContent); // using 3DES
    // EnvelopedCms encryptedMessage = new EnvelopedCms(plainContent, new AlgorithmIdentifier(new Oid("2.16.840.1.101.3.4.1.42")));  // for AES (id-aes256-CBC)

    CmsRecipient recipient = new CmsRecipient(cert);
    encryptedMessage.Encrypt(recipient);

    byte[] encryptedBytes = encryptedMessage.Encode();

That's fine so far. Unfortunately, some recipients cannot decrypt my messages, althought they are able to decrypt AES. Looking at the ASN.1 structure tells me that not only 3DES changed to AES, but also rsaEncryption (1.2.840.113549.1.1.1) was replaced by RSAES-OAEP (1.2.840.113549.1.1.7). Can I somehow force to still use RSAES-PKCS1-v1_5 with EnvelopedCMS? Or do you see another problem in switching 3DES->AES?

Edit: In case I cannot change the padding that easily to v1.5, what other options do I have? Manually calling the CryptoServiceProviders and build up the PKCS#7 envelope on my own? Are there more elegant ways?

1条回答
The star\"
2楼-- · 2019-02-13 21:24

The .NET Framework EnvelopedCms is built on top of Windows CAPI CryptMsg* functions. CryptMsgOpenToEncode supports two ways of encoding recipients, one of which is conditionally compiled (though I haven't been able to identify when it is not available; I suspect it's a Win9x vs NT4/WinXP compat problem).

On a whim I looked to see what could flip it to use the other codepath, and if that would change your result here. It turns out, yes, making it internally "useCms" results in the recipient encryption algorithm being 1.2.840.113549.1.1.1.

Option 1) Use SubjectKeyIdentifier identification

If you're interoperating with another system, as is the case here, make sure that the certificate has an explicit SubjectKeyIdentifier extension before using this identification form. .NET/Windows will make up an implicit value if there isn't an explicit one, and not all CMS implementations will match the recipient certificate in that case (e.g. OpenSSL).

You accomplish this by changing your CmsRecipient to

CmsRecipient recipient = new CmsRecipient(SubjectIdentifierType.SubjectKeyIdentifier, cert);

Option 2) Add an UnprotectedAttribute

EnvelopedCms allows for other metadata to be added onto the message unencrypted. Specifying any of these values makes the encryptor/encoder use the alternate codepath.

Before calling Encrypt add

// Pkcs9DocumentName requires a non-empty string.
// You can use any AsnEncodedData value, though.
encryptedMessage.UnprotectedAttributes.Add(new Pkcs9DocumentName("a"));

Each of those worked in local testing.

查看更多
登录 后发表回答