OpenSSL.NET How to implement PKCS7? - c#

I am writing an application where I need to encrypt, sign and wrap some content into a PKCS7/CMS structure. I am using OpenSSL.NET for the task (Wrapper for .NET).
I don't have much yet, I have successfully encrypted some data but
RSA toServer = cert.Certificate.PublicKey.GetRSA();
RSA fromClient = cert.Certificate.PublicKey.GetRSA();
byte[] cipherText = toServer.PublicEncrypt(Encoding.UTF8.GetBytes("Hello World!"), RSA.Padding.PKCS1);
byte[] plainText = fromClient.PrivateDecrypt(cipherText, RSA.Padding.PKCS1);
This works, it successfully encrypts and decrypts the data, but now I want to move further and implement PKCS7/CMS so that I have a standard format for my messages. I have found the below object that seem to point in the right direction but I fail to find some documentation on how to use it:
OpenSSL.X509.PKCS7 p7 = new OpenSSL.X509.PKCS7( ? );
Any suggestions or references to documentation are welcome.

Related

How to decrypt an OpenPGP RSA Encrypted text file in C#?

I am hoping that this question can be met with some guidance for someone who is beginning to work with encryption/decryption in C#. There are existing examples on the web regarding this, but I am truthfully struggling to put it all into practice for my given situation.
If given a text file that has been encrypted using OpenPGP with RSA, what is the best method to decrypt this in C#?
This is what I am attempting:
Using Kleopatra OpenPGP, I am generating a key pair using 2048bit RSA. This generates a private and public key.
I am then encrypting/signing a text file with a few word in it as a test.
In C#, I want to decrypt this text file.
Current code:
byte[] encryptedData = File.ReadAllBytes("C:\\PGP Encryption\\test.txt.gpg"); // The encrypted text file generated by Kleopatra.
using (RSACryptoServiceProvider RSA = new RSACryptoServiceProvider())
{
//Import the RSA Key information. This needs
//to include the private key information.
RSA.ImportParameters(RSAKeyInfo);
//Decrypt the passed byte array and specify OAEP padding.
decryptedData = RSA.Decrypt(DataToDecrypt, DoOAEPPadding);
}
return decryptedData;
Unfortunately, the RSA.Decrypt() call throws an exception that reads "The data to be decrypted exceeds the maximum for this modulus of 128 bytes."
I also do not believe that my private key is actually being loaded, as I'm not explicitly stating where the key is. But I don't see how the RSAParameters object is supposed to get populated otherwise.
If anyone can point me in the right direction to decrypt a file in this way, thank you in advance for your time and information.
It's looks like you need this library (see Decrypt section) https://github.com/mattosaurus/PgpCore

input too large for RSA cipher with BouncyCastle

I'm trying to write a service to SFTP to a server on a given interval, download all files in a directory, and then decrypt them for processing.
The decrypt method was working at one point, and I have no modified it since. I am still using the same keys as when it did successfully work.
I am using the PGPEncrypt, PGPDecrypt, and PGPEncryptionKeys classes for BouncyCastle found here: https://github.com/sledwith/PGP-Decryption-With-C-Sharp
Additionally, I have modified the code as shown here: Exception on decrypting file using BouncyCastle PGP
If you noticed, I commented on how that fixed my code and the decryption worked.
Now, it isn't.
Does anyone have some insight why this might have happened, or how I could go about fixing it?
I am going to make a guess that you are using a 1024 bit RSA public/private key and trying to encrypt 128 bytes of something with it? If I am right, use a larger RSA key (RSA 4096 will allow you to encrypt up to ~500 bytes).
I note in the linked post you say this is sporadic. Some googling indicates that if you have leading zeros in the to-be-encrypted bytes it may be able to handle a full 128 bytes.
Also - if you are just encrypting "data" with the keypair, you need to be certain it will not overrun these limitations (240 or so bytes for RSA 2048 and 500 or so for RSA 4096 accounting for padding). Good practice and future proofing would be to implement a symmetric key encryption of all your data and just use the RSA key to encrypt / decrypt your keys.
If you're not dead-set on using the PGP process explicitly, you might use my library here:
https://github.com/zenith-nz/ObscurCore
Its "banner feature" is not yet fully active (creating encrypted archives of a kind), but it does everything that you want it for, it appears - it does key derivation with a ECDHC scheme, UM1, and implements a large variety of block and stream ciphers. It's built on top of BouncyCastle.
I think I resolved this problem; please try this code.
public string StringToDecrypt(string text)
{
byte[] toDecrypt = Convert.FromBase64String(text);
AsymmetricCipherKeyPair keyPair;
using (var reader = File.OpenText(#"Private Key File Path"))
{
keyPair = (AsymmetricCipherKeyPair) new PemReader(reader).ReadObject();
}
var engine = new RsaEngine();
engine.Init(false, keyPair.Private);
return Encoding.UTF8.GetString(engine.ProcessBlock(toDecrypt, 0, toDecrypt.Length));
}

Encrypting mdm profile

I have seen question on signing and encrypting final mdm profile here:
iOS MDM profile signing, which certificate to use?
I am using Bouncy Castle library for encryption. Currently I am stuck while encrypting the final profile using the scep identitiy certificate.
I am facing the following issue.
The public key retrieved from with scep response certificate is not 16byte(128 bit) so encryption is failing with a message Key should be 128 bit.
If I can change the public key to 16byte using the following code the device throws invalid profile dailog.
public static string getKeyMessageDigest(string key)
{
byte[] ByteData = Encoding.UTF8.GetBytes(key);
//MD5 creating MD5 object.
MD5 oMd5 = MD5.Create();
byte[] HashData = oMd5.ComputeHash(ByteData);
//convert byte array to hex format
StringBuilder oSb = new StringBuilder();
for (int x = 0; x < HashData.Length; x++)
{
//hexadecimal string value
oSb.Append(HashData[x].ToString("x2"));
}
return Convert.ToString(oSb);
}
Can some one help me with some blog or sample code to encrypt the profile? Appreciate your help.
I had a similar problem. PFB the working code that I'm using to encrypt now. I'm retrieving the signing certificate from the device response, retrieving the public key from it and using the same to encrypt.
byte[] request = StreamToByte(ResponseFromDevice);
var signer = new SignedCms();
signer.Decode(request);
X509Certificate2 certificate = signer.Certificates[0];
string xmlData = "payload string to encrypt";
Byte[] cleartextsbyte = UTF8Encoding.UTF8.GetBytes(xmlData);
ContentInfo contentinfo = new ContentInfo(cleartextsbyte);
EnvelopedCms envelopedCms = new EnvelopedCms(contentinfo);
CmsRecipient recipient = new CmsRecipient(certificate);
envelopedCms.Encrypt(recipient);
string data = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"><plist version=\"1.0\"><dict><key>EncryptedPayloadContent</key><data>[ENCRYPTEDDATA]</data><key>PayloadDescription</key><string>For profile enrollment</string><key>PayloadDisplayName</key><string>ProfileName</string><key>PayloadIdentifier</key><string>YourIdentifier</string><key>PayloadOrganization</key><string>YourOrg</string><key>PayloadRemovalDisallowed</key><false/><key>PayloadType</key><string>Configuration</string><key>PayloadUUID</key><string>YourUDID/string><key>PayloadVersion</key><integer>1</integer></dict></plist>";
data = data.Replace("[ENCRYPTEDDATA]", Convert.ToBase64String(envelopedCms.Encode()));
HttpContext.Current.Response.Write(data);
WebOperationContext.Current.OutgoingResponse.ContentType = "application/x-apple-aspen-config";
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.OK;
I answered in comments on your previous question:
"I would recommend to take a look on OS X Server MDM implementation.
Generally speaking to encrypt profile, as I remember you should use PKCS7 wrapping. So, you should look at this: http://www.cs.berkeley.edu/~jonah/bc/org/bouncycastle/jce/PKCS7SignedData.html
BTW. I would recommend to read up a little bit on cryptography, if you want to get general understanding. Very-very high level overview of your problem: you are trying to use RSA key directly to encrypt the data. However, it should be used to encrypt a symmetric key which in its turn is used to encrypt the data."
You can also take a look here:
PKCS#7 Encryption
Your code won't work, because it's
- not PKCS7
- you are trying to use MD5(public certificate key) which doesn't make any sense
I would really-really recommend to read again MDM documentation and something on cryptopraphy. It's quite easy to make it wrong (both non working or unsecure implementation).
In bouncycastle you have to encrypt it using CMSAlgorithm.DES_EDE3_CBC. Then signed the data as you done in the previous step. Make sure you Base64 encode the encrypted payload before signing.

AES file encryption with .Net Framework and decrypt it with IOS

We encrypt PDFs using AESManaged algorithm implemented in .NET framework. I used the example explained in here to implement C# code to encrypt the file. Now I need to decrypt that file using an iPhone application.(That is the requirement). So I use the this code to do that but decryption failed by returning an error.
'Error Domain=CommonCryptoErrorDomain Code=-4304 "Decode Error"
UserInfo=0x127356c0 {NSLocalizedFailureReason=Input data did not
decode or decrypt correctly, NSLocalizedDescription=Decode Error'
Can some one help me to resolve this issue.
We use 12345678 as encryption key.
Most likely the problem is in the deriving actual key from the password (12345678 cannot be the AES key directly - it is only 8 bytes).
Technically this should work though I've never tested it, both methods uses the same ad-hoc format.
Encrypt using my authenticated encryption example.
//use your secret data you want to encrypt instead.
String secretMessage = "Message";
var rnCryptorHeader = new Byte[]{
2, //RNCryptor Format version 2
0 //RNCryptor Uses password
};
//encryptedString is base64 encoded
var encryptedString = AESThenHMAC.SimpleEncryptWithPassword(secretMessage,
password:"1234567891011",
nonSecretPayload:rnCryptorHeader);
Then Decrypt using RNCryptor and NSData+Base64 for IOS
//This is the encrypted data passed from .net
NSString *encryptedString = #"AgE8C9E7gsfyOAmSotIOgyLQ0O6mdcuMXXjN/iZa3azym4KVWZAkfykIP6mqMt/qkpfftdB3XQhMkoxtQEM+rA0iHxOvZiNlmA2KJtg6BOnmlg==";
NSData *encryptedData = [NSData dataFromBase64String: encryptedString];
NSError *error;
NSData *decryptedData = [RNDecryptor decryptData:encryptedData
withPassword:#"1234567891011"
error:&error];
NSString *secretMessage = [[[NSString alloc] initWithData:decryptedData
encoding:NSUTF8StringEncoding] autorelease];
Since you aren't dealing with strings and are dealing with bytes directly, just remove the Base64 and utf8 encoding/decoding from this objective-c example and the linked c# example, once you are sure this is working.

Digitally sign in PHP using private key, verify in C#

I am working on a feature that needs me to digitally sign a short string in PHP, and verify the string's signature in C#.
I would really like to use openssl_sign in PHP, because of its simplicity, but all the information I can find on Google indicates that this will not work.
There are some external libraries that claim to do this well, however as this is a hobby project I would rather not purchase such a library.
So what are the alternatives here? Full interoperability between C# and PHP is required. Libraries besides OpenSSL can be used.
I've done something very similar using Bouncy Castle Crypto APIs. It appears PHP openssl_sign uses SHA1 by default. If you are using anything other than the default you'll need to change the algorithm parameter for GetSigner.
string base64pubkey = "<!-- BASE64 representation of your pubkey from open ssl -->";
RsaKeyParameters pubKey = PublicKeyFactory.CreateKey(Convert.FromBase64String(base64pubkey)) as RsaKeyParameters;
byte[] signature = Convert.FromBase64String("<!-- BASE64 representation of your sig -->");
byte[] message = Encoding.ASCII.GetBytes("Something that has been signed");
ISigner sig = SignerUtilities.GetSigner("SHA1WithRSAEncryption");
sig.Init(false, pubKey);
sig.BlockUpdate(message, 0, message.Length);
if (sig.VerifySignature(signature))
{
Console.WriteLine("all good!");
}
You may use to check the digital signature smth like this:
string publicKey = "some key";
// Verifying Step 1: Create the digital signature algorithm object
DSACryptoServiceProvider verifier = new DSACryptoServiceProvider();
// Verifying Step 2: Import the signature and public key.
verifier.FromXmlString(publicKey);
// Verifying Step 3: Store the data to be verified in a byte array
FileStream file = new FileStream(args[0], FileMode.Open, FileAccess.Read);
BinaryReader reader = new BinaryReader(file2);
byte[] data = reader.ReadBytes((int)file2.Length);
// Verifying Step 4: Call the VerifyData method
if (verifier.VerifyData(data, signature))
Console.WriteLine("Signature verified");
else
Console.WriteLine("Signature NOT verified");
reader.Close();
file.Close();
Is there a reason you need something as complex as SSL signing? Can't you just use a simple one-way hash like MD5/SHA-1 on the string? If all you're looking for is verification that the string wasn't tampered with, that should be sufficient.
So looking at this - this guy appears to have asymmetric signing and encrypting working between PHP and C#. Signing should not be a problem, SHA* and MD* are standard, and so it's very very unlikely that is going to not be compatible (although you should be looking at SHA256 as MD* and SHA1 are deprecated due to vulnerabilities)
We're missing some context as to why you need to sign it. You may not need to.
The important question is: what guarantees do you need from your data?
If all you need to do is verify the integrity of the data, a hash will do the job. If you need to verify where it's coming from, you need to sign it. If you need both, hash it, concatenate the payload with the hash, and sign the whole thing.
Regarding cross-platform libraries... you really should need to worry about it. A SHA1 is a SHA1 is a SHA1, no matter which library generated it. Same thing with generating and verifying digital signatures. Use what's easiest in PHP and use what's easiest in C#. If they're both set up correctly you shouldn't need to worry about it.

Categories

Resources