Geeks With Blogs

Alex's Blog-o-monium

I've been doing a bit of external API integration work lately. Sounds mundane (and it is for the most part) - but there was one notable "gem" I had to tackle. To make long story short, there's this external source written in PHP and exposed as a web service. The operations are simple and there isn't much to it, except one little detail - this service uses PHP's encryption to pass data securely between peers using SSL certificates: the operations are "openssl_seal" and "openssl_open".

Now, I'm coding in .NET and I figure: surely, there must be some sort of equivalent to support for all this and after quickly reading up on what PHP does behind the scenes, off to MSDN I go.

First alarming sign: .NET does not have native (Cryptography namespace) support for RC4 ciphers (this is used in one of the steps - and there are multiple steps, more on this later) nor is there such thing as a "pem" file reader ("pem" file is where the certificate key data is stored). This is going to be more challenging than I expected.

Alright, let's apply some google-fu and see what pops up. Searches like ".NET equivalent of PHP 'openssl_seal'" and such turned up absolutely nothing (hopefully, this will change once I'm done typing this up) but I do find an OpenSSL library implementation in .NET (well, it's more of a managed wrapper around C/C++: - it doesn't seem to have been updated for about a year but it's worth a try.

The documentation wasn't the most detailed (argh!):


..and few hours of looking, the site turned up some useful bits but not a quick-'n-easy equivalent for "openssl_seal" command. This whole thing appears to be PHP only feature (as far as I can tell) which uses some of the OpenSSL functionality.

So, what does this command do exactly? The official PHP site ( doesn't share too much in terms of reverse-engineering, this is about all it states:


But there are user comments I found more useful, one gave some good pseudo flow:


And there's a link to a Java example (aha!) - Though, this mostly deals with decrypting data - helpful, but still no luck with the 'encryptor' "openssl_seal" implementation. Another hint - it does use Bouncy Castle libraries for Java (the .NET C# version can be found at so I go ahead in that direction.

As expected, Bouncy Castle does not provide straightforward "openssl_seal"/"openssl_open" implementation. But it seems to have everything I'd need (or at least, I think I need) - oh, and by the way there's no easy documentation there neither. You'll need to search through trunks on Google and such to figure out finer details (for example,

After whole bunch of trial and error, I got very close. I was able to generate a RC4 random 128-bit key, encrypt data using RC4 cipher and bring it back (decrypt it). However, there was one last step still missing - encrypting the above-mentioned 128-bit key using RSA cipher. It looked like I was doing it as prescribed, what could it be?!

It wasn't until I found PHP security library interop documentation for OpenSSL (  and click on PHP Bindings: openssl_seal() / openssl_open() -> phpseclib) and one detail caught my eye - PHP line "$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1); " line.

The key must be encrypted with RSA (I knew that) AND padded using PKCS1!!! Well, of course, isn't that obvious to everyone (*sarcastic argh!). 

So here's my take on all this - go ahead and grab a Visual Studio NuGet Package for "Bouncy Castle". And use following code:

For encryption, the "OPENSSL_SEAL" equivalent:

.NET "open_seal"
  2. var randomPassword = Guid.NewGuid().ToString("n").ToCharArray();
  4. var salt = new byte[16];
  5. for (int i = 0; i != salt.Length; i++)
  6.     salt[i] = (byte)i;
  8. var pGen = new OpenSslPbeParametersGenerator();
  9. pGen.Init(PbeParametersGenerator.Pkcs5PasswordToBytes(randomPassword), salt);
  10. var rc4Parameters = (KeyParameter)pGen.GenerateDerivedParameters("RC4", 128); /* generate random 128 bit key */
  12. var rc4Cipher = CipherUtilities.GetCipher("RC4");
  13. rc4Cipher.Init(true, rc4Parameters);
  14. var rc4DataBytes = rc4Cipher.DoFinal(Encoding.ASCII.GetBytes("YOUR_DATA_STRING_TO_ENCYPT")); /* encrypt data symmetrically with RC4 using the random key */
  16. var rsaCipher = CipherUtilities.GetCipher("RSA//PKCS1PADDING"); /* that pesky padding flag */
  17. var remReader = new PemReader(new StringReader("YOUR_STRING_OF_PUBLIC_KEY_CONTENTS_FROM_PEM_FILE"));
  18. var rsaParameters = (RsaKeyParameters)remReader.ReadObject();
  19. rsaCipher.Init(true, rsaParameters);
  20. var rsaDataBytes = rsaCipher.DoFinal(rc4Parameters.GetKey()); /* encrypt the random key itself using RSA */
  22. .


As for decrypting: first, you'll need a way to parse the private key from the PEM file and generate RsaPrivateCrtKeyParameters:

PEM Private Key Reader
  1. public static RsaPrivateCrtKeyParameters GetPrivateKey(String pemFile)
  2. {
  3.     if (string.IsNullOrEmpty(pemFile))
  4.         throw new ArgumentNullException("pemFile");
  6.     string privateKey = File.Exists(pemFile) ? File.ReadAllText(pemFile) : pemFile;
  8.     var reader = new PemReader(new StringReader(privateKey));
  9.     RsaPrivateCrtKeyParameters privkey = null;
  10.     Object obj = reader.ReadObject();
  11.     if (obj is AsymmetricCipherKeyPair)
  12.     {
  13.         privkey = (RsaPrivateCrtKeyParameters)((AsymmetricCipherKeyPair)obj).Private;
  14.     }
  15.     return privkey;
  16. }


..and basically reverse the process but use the private key:

.NET "openssl_open"
  2. var privateKeyParameters = GetPrivateKey("YOUR_STRING_OF_PRIVATE_KEY_CONTENTS_FROM_PEM_FILE");
  4. var rsaCipher = CipherUtilities.GetCipher("RSA//PKCS1PADDING");
  5. rsaCipher.Init(false, privateKeyParameters);
  6. var keyBytes = rsaCipher.DoFinal(Convert.FromBase64String("ENCRYPTED_KEY_STRING"));                    /* decrypt key using RSA */
  8. var rc4CipherDecrypt = CipherUtilities.GetCipher("RC4");
  9. var decryptParameter = new KeyParameter(keyBytes);
  10. rc4CipherDecrypt.Init(false, decryptParameter);
  11. var rc4DataBytesDecrypt = rc4CipherDecrypt.DoFinal(Convert.FromBase64String("ENCRYPTED_DATA_STRING")); /* decrypt data using RC4 */
  12. var dataString = Encoding.ASCII.GetString(rc4DataBytesDecrypt);
  14.             .


I hope you find this useful and save yourself much headache. Cheers!

Posted on Sunday, January 27, 2013 6:19 PM | Back to top

Copyright © Strenium | Powered by: