C#.NET Encrypt XML on one machine and Decrypt on other machine - encryption

I need to do a GET/PUT/DELETE/POST message on httpwebrequest.
my request body contains XML.
I need to encrypt the content in body XML and decrypt back on the client/receiver side.
I see there are multiple ways to encrypt the XML.
one of it is here http://msdn.microsoft.com/en-us/library/sb7w85t6.aspx
But my concern is, receiver should be able to decrypt it. and receiver shoul dbe on different platform might not be on .NET framework.
Can any one suggest a best approach for this.
What i have tried so far:
// Create a new Rijndael key.
key = new RijndaelManaged();
// Load an XML document.
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.PreserveWhitespace = true;
xmlDoc.Load("test.xml");
// Encrypt the "creditcard" element.
Encrypt(xmlDoc, "creditcard", key);
Console.WriteLine("The element was encrypted");
Console.WriteLine(xmlDoc.InnerXml);
Decrypt(xmlDoc, key);
Console.WriteLine("The element was decrypted");
Console.WriteLine(xmlDoc.InnerXml);
This looks to be doing the job. But I have concerns about the key
key = new RijndaelManaged();
Decrypt(xmlDoc, key);
What is this Key, will client on different machine and different framework and different technology be able to decrypt this message?
Update
After my research on few encryption methods, I found X509Certificate2 is best encryption option and client can also able to decrypt it, if the same X509 cert is installed on their machine.
I could find a script to encrypt
public static void Encrypt(XmlDocument Doc, string ElementToEncrypt, X509Certificate2 Cert)
{
// Check the arguments.
if (Doc == null)
throw new ArgumentNullException("Doc");
if (ElementToEncrypt == null)
throw new ArgumentNullException("ElementToEncrypt");
if (Cert == null)
throw new ArgumentNullException("Cert");
XmlElement elementToEncrypt = Doc.GetElementsByTagName(ElementToEncrypt)[0] as XmlElement;
// Throw an XmlException if the element was not found.
if (elementToEncrypt == null)
{
throw new XmlException("The specified element was not found");
}
EncryptedXml eXml = new EncryptedXml();
// Encrypt the element.
EncryptedData edElement = eXml.Encrypt(elementToEncrypt, Cert);
EncryptedXml.ReplaceElement(elementToEncrypt, edElement, false);
}
If found this code to decrypt
public static void Decrypt(XmlDocument Doc)
{
// Check the arguments.
if (Doc == null)
throw new ArgumentNullException("Doc");
// Create a new EncryptedXml object.
EncryptedXml exml = new EncryptedXml(Doc);
// Decrypt the XML document.
exml.DecryptDocument();
}
My question is this decrypt method is not asking for and X509 key. So how is it decrypting, doesn't it need and key to decrypt. Will this decryption works on other machines as well.

There exist several approaches to encryption.
Symmetric encryption uses the same key to encrypt and decrypt the data. AES encryption algorithm is an example of such encryption.
Asymmetric (public- and private-key based) encryption uses a pair of keys. In this mode you encrypt the data for someone using his public key. He uses his private key (which you don't have and should not have) to decrypt the data prepared for him. Asymmetric encryption is accomplished using certificate-based PKCS#7 / CMS standard or using OpenPGP.
Now about XML. You can encrypt it as if it were binary data using one of the above methods. Or you can encrypt it using XMLEnc standard.
The way to use depends on who decides or demands encryption format and method. If it's you that makes the decision, then the decision should be based on what capabilities (libraries, code) both sides can use AND how the keys are managed (PKI is a bit harder to manage than symmetric key, but in general PKI is more secure).
Just a note: our SecureBlackbox product supports both symmetric and certificate-based encryption (both binary, XMLEnc and also OpenPGP) on .NET, Java and other platforms.

Related

RSA/ECB/PKCS1 padding Encryption in SAP ABAP

I have a requirement where I need to do Encryption of my Private Key using Public Key(provided by third party) with RSA/ECB/PKCS1 Encryption
The Public Key is already Padded.
I am generating the private key using cl_sec_sxml_writer=>generate_key( cl_sec_sxml_writer=>co_aes256_algorithm_pem ). Is this the correct way to generate a new key or we can have any random string as a private key?
This private key will be used to encrypt a data string using AES/ECB/PKCS7 padding encryption and then convert to BASE64 and send it via API call. For AES/ECB/PKCS7 padding, I am using the classes provided by following https://github.com/Sumu-Ning/AES. pfb implementation below:
CALL METHOD zcl_aes_utility=>encrypt_xstring
EXPORTING
i_key = lv_xstr
i_data = lv_pwd_xstr
* i_initialization_vector =
i_padding_standard = zcl_byte_padding_utility=>MC_PADDING_STANDARD_PKCS_7
i_encryption_mode = zcl_aes_utility=>mc_encryption_mode_ecb
IMPORTING
e_data = lv_encrypt
My query is , how do I encrypt the private key using public key and RSA/ECB/PKCS1 Encryption.
The public key is of length 399 chars and something like this
DfP4hVgyXMSNWJFWakwo44p1PMyRKSmFG+UGq
I have checked other blogs that asks to use standard fm SSF_KRN_ENVELOPE but I am not able to understand how to use it.
Please help. Let me know in case of any further details required.

RSA Asymmetric encryption / decryption - Which key is being used

When I create a public/private key using the following code :
// Create the CspParameters object and set the key container
// name used to store the RSA key pair.
CspParameters cp = new CspParameters();
cp.KeyContainerName = ContainerName;
// Create a new instance of RSACryptoServiceProvider that accesses
// the key container MyKeyContainerName.
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(cp);
If I then call
rsa.Encrypt (....
OR
rsa.Decrypt(..
how do I know which key is being used. Whether the public or private key is used in each case is dependent on the application. How can I determine which is being used ?
Encrypt is done with the public key, and decrypt is done with the private key .. thus only the holder of the private key can decrypt.
You are not meant to decrypt using a public key, and thus the interface don't provide you with a way to do this.
Signatures utilizes encrypting using the private key, and decryption using the public key + some one way hash logic, but in this case the interface only allows this using specific signature methods (SignData(..) & VerifyData(..)).

Replacing System.Web.Security.MachineKey.Encode with System.Web.Security.MachineKey.Protect

I just upgraded a project from .NET 4.0 to .NET 4.5.1 which produced the following warning:
Public Shared Function Encode(data() As Byte, protectionOption As
System.Web.Security.MachineKeyProtection) As String' is obsolete:
'This method is obsolete and is only provided for compatibility with
existing code. It is recommended that new code use the Protect and
Unprotect methods instead.'
I have lots of values floating around in cookies and emails that were encrypted with Encode. If I am going to replace Encode/Decode with Protect/Unprotect, I still need to be able to decrypt those old encrypted values. Is it possible to Unprotect a value that was encrypted with Encode?
In .NET 4.0 you can use MachineKey API to Protect/Unprotect data like this:
string Protect(byte[] data)
{
if (data == null || data.Length == 0) return null;
return MachineKey.Encode(data, MachineKeyProtection.All);
}
byte[] Unprotect(string value)
{
if (String.IsNullOrWhiteSpace(value)) return null;
return MachineKey.Decode(value, MachineKeyProtection.All);
}
MachineKey.Encode accepts a byte[] to protect and returns a string. The second parameter is an enum that indicates if you want encryption, validation or both. I’d typically suggest both (MachineKeyProtection.All). The returned string can then be used to pass back to the client as a cookie value or a query string value without concern for viewing or tampering. MachineKey.Decode simply reverses the process.
And here’s the 4.5 usage:
string Protect(byte[] data)
{
if (data == null || data.Length == 0) return null;
var value = MachineKey.Protect(data, "");
return Convert.ToBase64String(value);
}
byte[] Unprotect(string value)
{
if (String.IsNullOrWhiteSpace(value)) return null;
var bytes = Convert.FromBase64String(value);
return MachineKey.Unprotect(bytes, "");
}
In 4.5 the old APIs are deprecated in favor of these new Protect and Unprotect APIs. The new APIs no longer accept the level of protection (they always encrypt and MAC now [which is good]) and instead now accept a new parameter which is called purpose. This purpose parameter is intended to act somewhat as a validation mechanism. If we use a value that’s specific to the user (as we do above with the GetMachineKeyPurpose helper) we then are verifying that the value can only be unprotected by the same user. This is a nice addition in 4.5.
No - the process is different. Not to mention you'll be trying to Unprotect data that has no additional parameter specified (which won't work) and sometimes decoding data with the additional parameter specified (if you are ideally taking advantage of how protect works)
I'd refactor the code to be able to tell when the old data is present and write a new cookie/etc out using Protect();
On the first case I mentioned - you cannot use a blank parameter in Protect like
var unprotect = MachineKey.Unprotect(Encoding.UTF8.GetBytes(myOldEncryptedStuff), "");
and if you in turn have some other code there like "User 12345" to help protect that data - this is called the purpose string and helps keep that string encrypted in a more unique way tied to that user.
var unprotect = MachineKey.Unprotect(Encoding.UTF8.GetBytes(myOldEncryptedStuff), "User 12345")
If the purpose strings don't match you'll just get a generic exception here like:
System.Security.Cryptography.CryptographicException: Error occurred
during a cryptographic operation.
So it won't work for you - the two methods operate very differently. You'll need to figure out when to use one vs the other. You could always catch the exception and then try to fallback to the old tech - but test that out :)

How to upload public RSA key to HSM (using PKCS#11 library)?

I am quite new to using PKCS#11 library so maybe someone with more experience can clear things up.
I want to do the following:
upload to HSM existing RSA public key (which was generated on PC)
and later use this uploaded key to wrap symmetric key that was generated on HSM.
I know how to generate symmetric key, but how to upload existing RSA public key?
Is this even possible using PKCS#11 library?
There seems to be similar question at Wrap a secret key with a public key using PKCS#11 but it uses RSA key pair that is generated on HSM. I need to upload RSA public key to HSM myself.
We can use C_CreateObject function of PKCS#11 to import a public key to HSM.
This can be found from
RSA PKCS#11
Functions -> Object Management Functions -> C_CreateObject
There is also an example of load public key. But it requires the support of token to load the public key from cryptoki library.
CK_SESSION_HANDLE hSession;
CK_OBJECT_HANDLE hKey;
CK_OBJECT_CLASS keyClass = CKO_PUBLIC_KEY;
CK_KEY_TYPE keyType = CKK_RSA;
CK_BYTE modulus[] = {... };
CK_BYTE exponent[] = {... };
CK_ATTRIBUTE keyTemplate[] = {
{CKA_CLASS, &keyClass, sizeof(keyClass)}
,
{CKA_KEY_TYPE, &keyType, sizeof(keyType)}
,
{CKA_WRAP, &true, sizeof(true)}
,
{CKA_MODULUS, modulus, sizeof(modulus)}
,
{CKA_PUBLIC_EXPONENT, exponent, sizeof(exponent)}
};
CK_RV rv;
/* Create an RSA public key object */
rv = C_CreateObject(hSession, &keyTemplate, 5, &hKey);
if (rv == CKR_OK) {
.
.
}

Asp.net Identity password hashing

The new ASP.net Identity project has brought some useful code and interfaces for website security. To implement a custom system using the interfaces (instead of using the standard Entity Framework implementation included in the MVC 5 template) an IPasswordHasher is required.
IPasswordHasher interface in ASP.net Identity
namespace Microsoft.AspNet.Identity
{
public interface IPasswordHasher
{
string HashPassword(string password);
PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword);
}
}
Is it possible to use password salting for more secure encryption in ASP.net Identity and via this interface?
HEALTH WARNING for the below answer: Know which version of ASP.Net Identity you are using. You should refer to the source code directly if it is one of the newer versions from the github repository.
As I write this, the current version (3.0.0-rc1/.../PasswordHasher.cs) of the password handler is significantly different to the below answer. This newer version supports multiple hash algorithm versions and is documented as (and may change further by the time you read this):
Version 2:
PBKDF2 with HMAC-SHA1, 128-bit salt, 256-bit subkey, 1000 iterations.
(See also: SDL crypto guidelines v5.1, Part III)
Format: { 0x00, salt, subkey }
Version 3:
PBKDF2 with HMAC-SHA256, 128-bit salt, 256-bit subkey, 10000 iterations.
Format: { 0x01, prf (UInt32), iter count (UInt32), salt length (UInt32), salt, subkey }
(All UInt32s are stored big-endian.)
The original answer is still valid for the original version of ASP.Net Identity, and is as follows:
#jd4u is correct, but to shed a little more light which wouldn't fit into a comment for his answer:
Microsoft.AspNet.Identity.PasswordHasher : IPasswordHasher already salts for you,
more importantly it uses Rfc2898DeriveBytes to generate the salt and the hash,
which uses industry standard PBKDF2 (SE discussion here, OWASP recommendation for PBKDF2 here).
The default Microsoft.AspNet.Identity.UserManager<TUser> implementation uses Microsoft.AspNet.Identity.PasswordHasher as a concrete IPasswordHasher
PasswordHasher in turn is a really simple wrapper for (ultimately)System.Security.Cryptography.Rfc2898DeriveBytes
So, if you are going to use Rfc2898DeriveBytes, just use PasswordHasher - all the heavy lifting is already done (hopefully correctly) for you.
Details
The full code that PasswordHasher (currently) ultimately uses does something very close to:
int saltSize = 16;
int bytesRequired = 32;
byte[] array = new byte[1 + saltSize + bytesRequired];
int iterations = SOME; // 1000, afaik, which is the min recommended for Rfc2898DeriveBytes
using (var pbkdf2 = new Rfc2898DeriveBytes(password, saltSize, iterations))
{
byte[] salt = pbkdf2.Salt;
Buffer.BlockCopy(salt, 0, array, 1, saltSize);
byte[] bytes = pbkdf2.GetBytes(bytesRequired);
Buffer.BlockCopy(bytes, 0, array, saltSize+1, bytesRequired);
}
return Convert.ToBase64String(array);
"Is it possible to use password salting for more secure encryption in
ASP.net Identity and via this interface?"
Yes, the interface is provided for the new implementation of PasswordHasher already present in Core framework.
Also note that the default implementation is already using Salt+Bytes.
After creating custom PasswordHasher (say MyPasswordHasher), you can assign it to UserManager instance like userManager.PasswordHasher=new MyPasswordHasher()
See one example of such IPasswordHasher
To implement a custom system using the interfaces (instead of using the standard Entity Framework implementation included in the MVC 5 template) an IPasswordHasher is required.
For implementing alternate system from EF,
- You shall implement all Core interfaces.
- IPasswordHasher implementation is not required. PasswordHasher is already provided in Core framework as it's implementation.
I ran into an issue while updating from Membership to AspNet.Identity. The Rfc2898 hashes are different from those used before. That's for good reason, but changing the hashes would require all users to reset their passwords. As a solution this custom implementation makes it backwards compatible:
public class MyPasswordHasher : PasswordHasher {
public FormsAuthPasswordFormat FormsAuthPasswordFormat { get; set; }
public MyPasswordHasher(FormsAuthPasswordFormat format) {
FormsAuthPasswordFormat = format;
}
public override string HashPassword(string password) {
return FormsAuthentication.HashPasswordForStoringInConfigFile(password, FormsAuthPasswordFormat.ToString());
}
public override PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword) {
var testHash = FormsAuthentication.HashPasswordForStoringInConfigFile(providedPassword, FormsAuthPasswordFormat.ToString());
return hashedPassword.Equals(testHash) ? PasswordVerificationResult.Success : PasswordVerificationResult.Failed;
}
}
Once you create your UserManager instance just set the hasher:
Usermanager.PasswordHasher = new MyPasswordHasher(FormsAuthPasswordFormat.SHA1);
The code complains that the HashPasswordForStoringInConfigFile method is deprecated, but that's fine as we know that the whole exercise is to get rid of the old technology.

Resources