RSA Crypto Service Container Private Key goes out of sync - c#

In a client/server model
We have a RSACryptoServiceProvider key created using a well known "container name" at the startup code, and set a rule on it to Allow Generic Read, and persist the public key into a database. The clients connecting to the server, send sensitive information encrypted with the public key and the server decrypts it using the private key.
However, over time, we are observing that the public key in the crypto store (it's a machine level crypto store at %ProgramData%\Microsoft\Crypto\RSA\Machine Keys goes out of sync with the stored public key in the database) and our clients stop communicating with the server.
Are there any possible reasons as to how this happens ? Is there a way we can detect it when this happens ?

Related

read ssl private key from smartcard with c#

I have a smartcard with a card reader and I decide to implement a client certificate in the latter.
The private key being stored in the card and the public key is stored in the server.
The application scenario is something like this:
application send frames to the Linux server
Linux server answer with a ramdom number
application read private key from (smartcard or pem file) and encrypt received random number and send the result to the server.
server try to decrypt the sent encrypted string via public key (pem file stored in the server) => if succeed access is granted else access is denied.
In my application, there is a mode of certificate authentication (static file .pem) and also uses the private key (also static .pem). I used openssl-net functions such as FromPrivateKey(string pem, string password) and PrivateEncrypt(byte[] msg, RSA.Padding padding) for read private key and encrypt data to send to the server.
The problem that is needed, is that I have no a priori way to export my private key in my smartcard since my pem file.
So after much research I understood that I should use instead of these functions type functions: "ENGINE_load_private_key" with engine "pkcs11."
So I have seen several examples of openssl configuration (eg http://openssl.6102.n7.nabble.com/Private-Key-from-Windows-Cert-Store-td20720.html) with pkcs11 (opensc, engine_pkcs11. so etc. ..) the trouble is that these configurations are for Linux.
Indeed, my need is to develop a client application windows WPF (written in C #) that can read the private key from the smartcard or from a PEM file.

RSA (client side encryption/ server decryption)

This is a continuation of the project in this question, but without the Bouncy Castle.
So I decided to scrap Bouncy Castle (pity, I loved the name)
ANYWAY
I have a server and a client. the client needs to send a serialized object to the server, the server will then process this object.
It does this, however I'd like to add encryption to the process. But without storing a file or anything like that. the process needs to be session based(in a sense)
So, the client will request a key from the server, the server will generate a key pair and send a key to the client.
Client then uses this key to encrypt the object
string key = ASCIIEncoding.ASCII.GetString(RequestKey(tcpclnt));
var RsaClient =new RSACryptoServiceProvider(2048);
while (key.Length > 0) {
RsaClient.FromXmlString(key);
var transmit = ASCIIEncoding.ASCII.GetBytes(stringtosend);
var encrypted = RsaClient.Encrypt(transmit,false);
the server then receives these encrypted bytes and tries to decrypt them
raw = Receive(clientSocket);
byte[] r = TrimBytes(ASCIIEncoding.ASCII.GetBytes(raw),256);
var sdecrypted = ASCIIEncoding.ASCII.GetString(RsaServer.Decrypt(r, false));
But alas, the server can't do this. On Decryption it throws an error
Key does not exist.
So, my question is, what am I doing wrong?
Many thanks in advance for any help you can offer.
UPDATE
Altered the code in the server
var RSAKeyInfo = new RSACryptoServiceProvider(2048, new CspParameters(1)).ExportParameters(true);
New error
The parameter is incorrect
Whilst fine as an exercise in the use of cryptography, the use of basic cryptographic algorithms to build your own system for secure communication is a recipe for insecurity. For every weakness you address in your own system, there are likely 10 (or more!) that you won't even have thought of.
My strong suggestion therefore is to use SSL/TLS to secure your communications. This should provide all the security you need whilst also being straightforward to integrate as the .NET Framework's SslStream has the necessary functionality to operate as either the server or client side of the connection.
Doing this will also allow you to optionally use additional security mechanisms in the future, e.g. certificate based client authentication, with minimal additional effort.

How to Encrypt a file for transport in C#?

I am trying to encrypt a file when I save it to disk and I have looked at the Crypto namespace in C#, but am unsure how I should do it. Basically I need the ability for my program to be able to both encrypt and decrypt a file. The file is just an xml file that is serialized by my program, but it can contain sensitive data like connection strings for SQL servers. My clients want the ability to email these profiles to others and open them in our application to apply the settings to their system.
I tried the AES classes in the Crypto namespace, but I don't know where to store the IV and the key so that my program on another machine will be able to decrypt it.
In a typical scenario, the flow for handling something like this would go:
The IV is static and known to the client
The end machine generates an RSA keypair, and gives the public key only to the party sending the data (the XML file)
Your AES key is generated, and encrypted using the RSA public key and sent to the client, now only the client is able to obtain that AES key using the private key it generated previously.
You encrypt the data using the AES key you securely sent to the client earlier
This means that even if someone captured the complete data stream, they wouldn't be able to decrypt your data because they don't have the private key required to obtain the AES key.

Where should I put the public key in a standalone application

I wrote an C# WPF application that signs a license xml file using the standard .Net SignedXml class. I am able to extract the public and private key as xml strings. I can safely tuck away my private key locally for the signing application, but what about the public key needed in the remote sign check application (library)? Options considered:
KeyContainer: no good, because signing and checking happens in 2 separate environments
Hardcoded: hardcode the public key as xml string in my checking library. I know the public key is not secret, but how can I prevent hackers from replacing the key with their own? I can sign the library, but then they could tamper with the application using the library....
Put the public key in a standard digital certificate that you distribute with your app. The integrity of the certificate will then be guaranteed by Windows, and you can tell if it's been changed.
Of course both the hardware and Windows itself is under the control of any potential attacker, so you can't really prevent a compromise of a specific machine.
Here's an example from a program that I used to distribute. When the program was activated from a licence perspective, it sent a hardware hash to a web service. This returned a self-signed certificate containing the hardware hash, which my program then checked whenever it was started. If the certificate had been changed in any way, the program would stop.
I put the public key in a directory outside of the inetpub directory, and if you move the private key off of the computer, then the worst someone could do is to replace the public key and it no longer can decrypt, but you could be informed when it can't decrypt to know something happened.
But, if someone was able to change your file you will have bigger problems that just having this one file changed.
UPDATE:
Oops, I missed that this is a WPF program. Unfortunately the best you can do is to have the private key separate from the public key, so, you can decrypt, but if the hacker changes the public key the application won't function properly.
That is one of the advantages of using the public/private key, to verify that only you can do the encryption.
The other option is to fetch the public key from a webserver, but then you have the same problem in that it is possible for someone to trick the application to go to the wrong server, so it isn't full-proof, and it will require that the user had an Internet connection, and for you to uniquely identify them.

SQL column encryption

I personally think SQL column encryption is a huge waste ;-), but must implement it due to a customer push. So my questions are:
What actually does it do -- Will an admin see encrypted data, but the application will see cleartext data?
What happens to the data when it gets backed up? I assume that backups remain encrypted, in which case are they usable if we need to recover onto a different server?
Where does the encryption key actually come from?
Can I specify a fixed encryption key, so that at least the database recovery will easily work on an server I move to. I really don't want some magical key algorithm, which shoots me in the foot in the future when the key suddenly is not available.
If the customer is pushing for column encryption but you don't know where the the key will actually come from, your customer is wasting his money and you are wasting his time. Even more so if you are even thinking about fixed keys.
There is an exhaustive explanation on MSDN explaining the key encryption hierarchy. All the schemes have the key chain rooted either in the DPAPI for the case where the service itself must access the encrypted storage w/o any key provided by the user, either in a password explicitly provided by the user.
Encryption is a measure put in place to mitigate specific security threats. Depending on what those threats are (they are nowhere specified in your post) column level encryption may be the right answer, but almost always deploying Transparent Database Encryption is a much better solution.
There is no encryption scheme that can hide the content from an administrator that desires to see the content. Period. Every solution that claims the contrary is snake oil.
http://msdn.microsoft.com/en-us/library/ms179331.aspx
You can create a symmetric key to encrypt the data and can use a string to create it (with the KEY_SOURCE option) that will enable you to recreate it later (this isn't in the linked sample bit is in the docs). This has to be opened to access the actual data. This is protected by a certificate which is in turn protected by the database master key. DO NOT lose the password for your database master key. The Database master key is protected by a server key, so if you restore to another server you must open your database master key with the password and reencrypt with the new server's service master key.
If you created the symmetric key with a static string (KEY_SOURCE option), then you can recreate it with a different certificate and database master key and still access your encrypted data.
-- backup service master key tied to computer (used to decrypt database master password,
-- if this is the same on two servers you can move the database between them)
BACKUP SERVICE MASTER KEY TO FILE = 'C:\ServiceMasterKey.smk'
ENCRYPTION BY PASSWORD = 'topsecret'
go
-- create database master key
CREATE MASTER KEY ENCRYPTION BY PASSWORD = 'dbpassword'
go
-- create certificate to use to encrypt symmetric key
CREATE CERTIFICATE TestCertificate WITH SUBJECT = 'Test Certificate',
EXPIRY_DATE = '01/01/2016'
go
-- create symmetric key to encrypt data
CREATE SYMMETRIC KEY TestKey WITH ALGORITHM = TRIPLE_DES,
KEY_SOURCE ='pass_phrase' ENCRYPTION BY CERTIFICATE TestCertificate
go
create table CCInfo (ID int, Plain varchar(16), Encrypted varbinary(128))
go
insert into CCInfo (ID, Plain) values (1, '1234567890ABCDEF')
insert into CCInfo (ID, Plain) values (2, '1234123412341234')
insert into CCInfo (ID, Plain) values (3, '1234567890ABCDEF')
insert into CCInfo (ID, Plain) values (4, '1111111123456789')
go
-- encrypt credit card data
OPEN SYMMETRIC KEY TestKey DECRYPTION BY CERTIFICATE TestCertificate
update CCInfo set Encrypted = EncryptByKey(Key_GUID('TestKey'), Plain)
CLOSE SYMMETRIC KEY TestKey
go
-- check that data is the same
OPEN SYMMETRIC KEY TestKey DECRYPTION BY CERTIFICATE TestCertificate
select ID, Plain, Encrypted, convert(varchar(16), DecryptByKey(Encrypted)) as Decrypted
from CCInfo
CLOSE SYMMETRIC KEY TestKey
A couple things to note:
This is called "Cell-level" encryption, and it is a manual process - you can't just mark a column as "encrypted"
It may require access to Certificate Services, which carries its own set of challenges and overhead (I'm not positive about this, it may depend on whether you use AD)
To answer your specific questions:
Nobody sees unencrypted data directly in the database - you must use a stored procedure to encrypt and decrypt the data. The column itself must be converted to a varbinary column. I believe access can be controlled based on both the key and the stored procedures.
The data is backed up as a varbinary column.
The encryption key is generated in the database by someone with appropriate permissions
I think so? The latter part of this encryption tutorial should give you an idea of what's entailed.
More information can be found in the MSDN Database Encryption documentation.

Categories