MartijnKooij / PolymorphicPseudonymisation

.Net Standard C# implementation of Polymorphic Pseudonymisation Decryption
MIT License
6 stars 5 forks source link

Add support for converting p7 and p8 files to PEM #2

Open MartijnKooij opened 6 years ago

MartijnKooij commented 6 years ago

The BSNk register provides the p7 and p8 files to decrypt the encrypted identity and pseudonyms. The client currently has to convert these to PEM using openssl. It would be better if we could take this work away from the clients and do that conversion ourselves inside the library, but I got stuck on the conversion: https://stackoverflow.com/questions/52460001/get-pem-from-p7p8-files-using-c-sharp

cveld commented 6 years ago

I think I was able to provide a Microsoft implementation to indirectly decrypt the transported key from the PKCS#7 CMS structure, and interestingly we get the same or at least very much alike exception: System.Security.Cryptography.CryptographicException: 'Error occurred while decoding OAEP padding.'

I looked into the meaning of OAEP a bit, and it appears to stand for Optimal Asymmetric Encryption Padding. It seems to be version 2 of PKCS#1. PKCS#1 nowadays comes in two flavors:

Hypothesis I seems to me that both BouncyCastle as the Microsoft Cryptography libraries are assuming our PKCS#8 private key is in OAEP padding format. I would like to find out if we can enforce v1.5 behavior. On the other hand, I suppose the PKCS#8 private key is following ASN.1 syntax, and surely encodes the padding format as well? Edit: Tried out var keyDeformatter = new RSAPKCS1KeyExchangeDeformatter(); but this results in System.Security.Cryptography.CryptographicException: 'The parameter is incorrect.'

Reading the PCKS#8 private key One thing I don't know yet is how to obtain the private key from the PKCS#8 file. One workaround is to create a PKCS#12 (PFX) file; read it with the Microsoft API and take the PrivateKey property.

  1. Create the PKCS#12 (PFX) file with openssl: Although serial and object identifiers are not really relevant for the private key part, it was part of a test to create a certificate that corresponds to the recipient within the PKCS#7 CMS structure; albeit not yet succesful; I still get the exception System.Security.Cryptography.CryptographicException: 'The enveloped-data message does not contain the specified recipient.' openssl pkcs8 -inform der -outform pem -in private.p8 -out private-p8.pem -topk8 -nocrypt openssl req -new -x509 -key private-p8.pem -out mycert-pem.crt -outform PEM -set_serial 0x00D17021F6B4322D9D -config cert.conf openssl pkcs12 -in mycert-pem.crt -inkey private-p8.pem -export -out mycert.pfx

Contents of cert.conf:

[ req ]
distinguished_name = dn
prompt = no

[ dn ]
emailAddress = digid@example.com
CN=digid.logius.nl
OU=DigiD
O=Logius
L=Den Haag
stateOrProvinceName=ZH
C=NL

Decrypt the transported private key

  1. Run the following C# code:
// PKSC#8 private key processing:
var myCertificate = new X509Certificate2(@"resources\mycert.pfx");
var keyDeformatter = new RSAOAEPKeyExchangeDeformatter();
keyDeformatter.SetKey(myCertificate.PrivateKey);            
            // ideally we should read the PKCS#8 private key directly from the private.p8 file on disk

// PKCS#7 CMS structure with transported encrypted private key processing:
var p7Data = File.ReadAllBytes(@"resources\ID-4.p7");
var envelopedCms = new System.Security.Cryptography.Pkcs.EnvelopedCms();
envelopedCms.Decode(p7Data);
var recipientsMS = envelopedCms.RecipientInfos;
var firstRecipient = recipientsMS[0];

// Decrypt the encrypted transported key:
var decryptedprivatekey = keyDeformatter.DecryptKeyExchange(firstRecipient.EncryptedKey);
            // currently throws the exception System.Security.Cryptography.CryptographicException: 'Error occurred while decoding OAEP padding.'

The decryptedprivatekey variable in the end should contain the transported decrypted private key.

Decrypting enveloped data Ad 1. I use the following Microsoft API code to try out decrypting on the CMS structure level; very much the same as the current BouncyCastle implementation:

var coll = new System.Security.Cryptography.X509Certificates.X509Certificate2Collection();
coll.Add(myCertificate);
envelopedCms.Decrypt(firstRecipient, coll);
var decryptedprivatekey = envelopedCms.ContentInfo.Content;

Unfortunately, this currently results in the exception `System.Security.Cryptography.CryptographicException: 'The enveloped-data message does not contain the specified recipient.'.

MartijnKooij commented 6 years ago

Thanks for the research Carl! I really feel that we are close... But not yet there... There must certainly be another piece of this puzzle lying around somewhere. I will continue searching for clues using your new found valuable input.