Security with RijndaelManaged and ServicePointManager - ssl

I have a security question about RijndaelManaged and
ServicePointManager.
I have implemented a system where C# application is encrypting data, such as user credentials and some XML data. Then I use WebClient to send encrypted user credentials with some encrypted XML document containing instructions - to my Tomcat Java Web application. The job of the Java Application: is to decrypt user credentials and XML instructions – perform instructions and respond back to C# with an encrypted XML result.
All connections from my C# application to Tomcat server are with SSL enabled (Self signed certificate for now).
First Question: Given the fact that my C# application by default always connecting to my Server (only) with SSL enabled. Can I simply implement the call back function as:
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
As I understand that the call back function is used to Identify and validate certificate used by the Server I’m connecting to. If I were to give that application to – say one of my clients to connect to my Server (with SSL enabled) – is the code above satisfactory? If client uses my application to connect to another server that is not known and I have no Idea about its SSL certificate status – the code above should be replaced with an actual certificate validation function. Does my question make sense?
Second Question: I have encryption/decryption implemented using RijndaelManaged in my C# application. But the key I’m using is part of the C# application – the application is obfuscated. As I understand this is not a secure way.
Is there a reliable way for the C# application to receive the encryption/decryption key from my Web application. Or is there a way for the key to be generated in C# application that can be used by Web application to decrypt the data – if so: how do I generate that key and most important how do I send it to the server in a reliable secure way. Since the connection is SSL – can the key simply be a part of the encrypted stream?
Here is code that I’m using for encryption in my C# app.
private const string KEY = "samplekey";
private const int KEY_SIZE = 128;
private const int KEY_BITS = 16;
private string Encrypt(string textToEncrypt)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
rijndaelCipher.KeySize = KEY_SIZE;
rijndaelCipher.BlockSize = KEY_SIZE;
byte[] pwdBytes = Encoding.UTF8.GetBytes(KEY);
byte[] keyBytes = new byte[KEY_BITS];
int len = pwdBytes.Length;
if (len > keyBytes.Length)
{
len = keyBytes.Length;
}
Array.Copy(pwdBytes, 0, keyBytes, 0, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = keyBytes;
ICryptoTransform transform = rijndaelCipher.CreateEncryptor();
byte[] plainText = Encoding.UTF8.GetBytes(textToEncrypt);
return System.Convert.ToBase64String(transform.TransformFinalBlock(plainText, 0, plainText.Length));
}

Related

Why is SignHash from RSACng (dotNetCore) different from BoncyCastle (running in Mono)?

I'm trying summarize: I have a self-signed certificate (created by OpenSSL) being used in a aspnetCore API to verify hash (or message digest, if you prefer) signature. I can run tests to sign the hash and run in the API and everything goes well.
Now, I'm trying do my client sign such hashs and consume the API. It's an application running on Mono. I'm tried do exactly the same thing as my tests, but Mono has a bug in X509Certificate2, when pfx certificate is protected by password. So, I replaced it the by the famous BouncyCastle. However, the results are different... Checking the pk algorithm, I can see some differences, but nothing so remarkable (at least to me).
Can you give me advices? I gonna put the codes:
Good code running on tests (dotNet Core):
Console.WriteLine("Entry text:");
var text = Console.ReadLine();
X509Certificate2 certificate = new X509Certificate2((byte[])Resource1._2dbb1721_281d_4990_836c_7e46909b8767, "1509a96c-d56b-4e17-af5b-c11f5f214c74");
SHA1Managed sha1Hasher = new SHA1Managed();
UnicodeEncoding encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(text);
byte[] hash = sha1Hasher.ComputeHash(data);
RSA provider = (RSA)certificate.PrivateKey;
var signatureData = provider.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
var signature = Convert.ToBase64String(signatureData);
Bad code, running on Mono and BouncyCastle:
SHA1Managed sha1Hasher = new SHA1Managed();
var encoding = new UnicodeEncoding();
byte[] data = encoding.GetBytes(uuid);
byte[] hash = sha1Hasher.ComputeHash(data);
var rsaParameters = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)privateKeyParam);
var provider = RSA.Create();
provider.ImportParameters(rsaParameters);
var signatureData = provider.SignHash(hash, HashAlgorithmName.SHA1, RSASignaturePadding.Pkcs1);
var signature = Convert.ToBase64String(signatureData);
Both certificates are the same. Debugging, I could see the dotNet instantiates on provider as RSACng. The SignatureAlgorithm property is "RSA" as the KeyExchangeAlgorithm so.
In the BoncyCastle over Mono, the provider is RSACrytoServiceProvider. According some articles that I read, this shouldn't make any difference. However, SignatureAlgorithm is "http://www.w3.org/2000/09/xmldsig#rsa-sha1", while KeyExchangeAlgorithm is "RSA-PKCS1-KeyEx".
Thanks in advance
My bad: I've just realized my program wasn't using the string it is supposed might use to calculate the hash...
The Mono's version using BouncyCastle is working perfect fine.

Keyset does not exist /r /n

I was tasked to create a integration service between our SharePoint app and one service provider. One requirement of the service provider I'm going to integrate with is to provide them a public key which they will use to verify my request which was signed using our own private key.
Initially I created a console app which reads the certificate store and gets the private key which to use to sign my request and all. The console app works fine so I decided to move it now within our SharePoint application. Unfortunately it fails in this specific part of the code:
key.FromXmlString(privateCert.PrivateKey.ToXmlString(true));
The whole code snippet which gets the certificate and does the signing can be found below:
X509Certificate2 privateCert = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.MaxAllowed);
var certs = store.Certificates.Find(X509FindType.FindByThumbprint, "thumbprinthere", true);
if (certs.Count > 0)
{
privateCert = certs[0];
}
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(privateCert.PrivateKey.ToXmlString(true));
byte[] sig = key.SignData(Encoding.ASCII.GetBytes(data), CryptoConfig.MapNameToOID("SHA256"));
string signature = Convert.ToBase64String(sig);
[UPDATE]
I tried following the steps in this link. I first uninstalled my existing private key in the server. I then imported it back to the Certificate store and confirmed that there was a Thumbprint property. After that, I ran findprivatekey.exe and was able to navigate to the MachineKeys folder. From there I added different users ranging from Network Services, IIS_IUSRS and even local accounts I used to login to the server as well as SPFarm admin but I still keep getting the error.
I also made sure that the key I added was exportable so there should be a way for it the application to extract the private key attached to the certificate.
[UPDATE 2]
I updated the code so that it just returns one certificate prior to assigning it to the variable I was using to extract the private key. Still the same issue even if I can see that the certs variable is returning exactly one record.
After much checking I realized I missed one important part in calling the method code block above. I forgot to wrap it an elevate privilege block. After doing that, the code functioned similarly as my console app.
SPSecurity.RunWithElevatedPrivileges(delegate())
{
...
X509Certificate2 privateCert = null;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.MaxAllowed);
var certs = store.Certificates.Find(X509FindType.FindByThumbprint, "<thumbprinthere>", true);
if (certs.Count > 0)
{
privateCert = certs[0];
}
RSACryptoServiceProvider key = new RSACryptoServiceProvider();
key.FromXmlString(privateCert.PrivateKey.ToXmlString(true));
byte[] sig = key.SignData(Encoding.ASCII.GetBytes(data), CryptoConfig.MapNameToOID("SHA256"));
string signature = Convert.ToBase64String(sig);
...
});

Windows 8 Metro RSA Encryption: AsymmetricKeyAlgorithmProvider ImportPublicKey Fails

I am attempting to pass some encrypted data between a Win 8 Metro app and a RESTful WCF service. Initially the Metro app requests a public key and the WCF service returns it as a raw Stream as to avoid any pesky formatting issues. The Base 64 encoded public key is decoded in the metro app into a byte array. Here is where the problem occurs. When I attempted to call AsymmetricKeyAlgorithmProvider.ImportPublicKey I get the error "ASN1 bad tag value met".
I am using RSA PKCS1 for the encryption. Here is the relevant code:
WCF Service
string keyName = "This is passed in via a parameter";
var key = !CngKey.Exists(keyName) ? CngKey.Create(CngAlgorithm2.Rsa, keyName) : CngKey.Open(keyName);
// Create the RSA container to get keys and then dispose
using (var rsaCng = new RSACng(key) { EncryptionPaddingMode = AsymmetricPaddingMode.Pkcs1, KeySize = 2048 })
{
byte[] publicBlob = rsaCng.Key.Export(CngKeyBlobFormat.GenericPublicBlob);
publicKey = Convert.ToBase64String(publicBlob);
}
Metro App
public static string Encrypt(IBuffer dataBuffer, string publicKeyString)
{
var asymmAlg = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
// The next line fails with ASN1 bad tag value met
var publicKey = asymmAlg.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(publicKeyString), CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey);
var encryptedData = CryptographicEngine.Encrypt(publicKey, dataBuffer, null);
return CryptographicBuffer.EncodeToBase64String(encryptedData);
}
EDIT 1: More information below
Exporting the public key from a 2048bit key pair from the WCF service yields a 283 bit length key blob, while exporting the same type of public key from the Metro app is only 270 bits. When I import the Metro generated public key it succeeds. Any idea why the WCF service has 13 extra bits on its public key? I think those extra 13 bits are causing the failure.
Here is the Metro code that yields the shorter public key blob:
var provider = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
CryptographicKey standardKeyPair = provider.CreateKeyPair(2048);
byte[] standardKey = standardKeyPair.ExportPublicKey(CryptographicPublicKeyBlobType.Pkcs1RsaPublicKey).ToArray();
Quite late, but maybe it will help you or saves someone's time...
Change the type of blob type during import. It's really wierd, but I had success with it, after experimenting.
Your code in WCF may stay as it is.
Change just the Metro code:
public static string Encrypt(IBuffer dataBuffer, string publicKeyString)
{
var asymmAlg = AsymmetricKeyAlgorithmProvider.OpenAlgorithm(AsymmetricAlgorithmNames.RsaPkcs1);
// The next line fails with ASN1 bad tag value met
var publicKey = asymmAlg.ImportPublicKey(CryptographicBuffer.DecodeFromBase64String(publicKeyString), CryptographicPublicKeyBlobType.BCryptPublicKey);
var encryptedData = CryptographicEngine.Encrypt(publicKey, dataBuffer, null);
return CryptographicBuffer.EncodeToBase64String(encryptedData);
}
So the only change here is the BCryptPublicKey during the importing. Then it works. But do not ask me why :-).

Custom X509CertificateValidator Check Requestor Against CN

I have a custom X509CertificateValidator that currently validates a series of rules against a certificate presented for a WCF SOAP message.
There is a requirement to check the CN name on the certificate against the domain the certificate is being presented by, but I'm not aware that I have access to the request from within the X509CertificateValidator.
Is there any way to check that the certificate matches the request domain?
I haven't found any way to do this from within the X509CertificateValidator, but it is possible within the service.
Here is my first cut - I will be refining it to make it more elegant, but this works.
private static void ValidateRequestIsFromCertificateDomain()
{
RemoteEndpointMessageProperty endpointProperty = OperationContext.Current.IncomingMessageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
var claimSet = OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets[0] as X509CertificateClaimSet;
string domain = claimSet.X509Certificate.GetNameInfo(X509NameType.DnsName, false);
var resolvedAddress = System.Net.Dns.GetHostAddresses(domain);
if (resolvedAddress.Count() == 0 || endpointProperty.Address != resolvedAddress[0].ToString())
{
throw new SecurityException("Client address mismatch");
}
}
This isn't really required because the client encrypts data with its private key that can only be decrypted with its public key - so you know the certificate is being presented by the real client.
However, if you are given this as an integration requirement as I have been, this may be useful to you.

How to generate a CMS (cryptographic message syntax) with Mono Framework and BouncyCastle API?

I have a Certificate in PKCS#12 format and I need to generate a CMS signature (Cryptographic Message Syntax). Due that "Mono Framework" does not have a full implemented "System.Security.Cryptography" assembly, I am trying to use "Bouncy Castle API for C#".
So, using "Bouncy Castle", I need to write an alternative code to the one I had wrote on DOTNET.
The code on DOT NET is the following:
X509Certificate2 crt = new X509Certificate2();
byte[] crtBytes = [ certificate in the format PKCS12 (certificate + private key) obtained using FileStream class]
crt.Import(crtBytes, "123456", X509KeyStorageFlags.DefaultKeySet);
Encoding msgCodificado = Encoding.UTF8;
byte[] msgBytes = msgCodificado.GetBytes(xmlTRA.OuterXml); // xmlTRA.OuterXml is the data to sign
ContentInfo pkcsContentInfo = new ContentInfo(msgBytes);
SignedCms cms = new SignedCms(pkcsContentInfo);
CmsSigner firmante = new CmsSigner(crt);
firmante.IncludeOption = X509IncludeOption.EndCertOnly;
cms.ComputeSignature(firmante); // ---> throw an cryptografy exception with MONO
byte[] firma = cms.Encode();
firmaB64 = Convert.ToBase64String(firma);
Anyone knows how to write an alternative code using "Bouncy Castle API for C#"?
Org.BouncyCastle.Pkcs has classes for working with a PKCS#12 store.
Org.BouncyCastle.Cms has classes for working with CMS messages.
There are corresponding test classes in the source code that show the basics of using, e.g. Pkcs12Store(Builder) and CmsSignedData(Generator).