Sunday, February 19, 2012

Connection String Encryption for SQL Server Mobile

I'm seeking suggestions on how to go about encrypting a database connection string in the compact framework. It's something that I thought would be relatively straight forward as I've accomplished it without much difficulty in the full framework, but I'm stuggling to find a solution.

I've been trying to implement a solution using public/private key asymmetric encryption using the RSA provider. I've essentially been trying to encrypt the connection string once on my development machine so that I can include both the encrypted connection string value and public key in either code or an external file. I'd then keep the private key out of harms reach. The problem I've encountered in doing this is that that RSA provider seemingly only allows new "in session" keys to be generated and I can't figure out a way of importing a public key from a file or other similar means.

I found the following code which is meant to allow a key to be retrieved from a signed assembly or an SNK file, which I've converted to VB but haven't been able to get working:

http://www.topxml.com/-NET-XML-System-XML/re-2963_Get-RSA-Public-key-from-Assembly-or-SNK-File.aspx

After the code seems to successfully prepare the CspParameters from an SNK files, I get an unspecified error when executing ImportParameters on the RSA provider.

I'd imagine this to be a common requirement, but haven't been able to find much information specific to the compact framework on the web. Any guidance would be much appreciated.

Thanks,
Steve

What's the argument for encrypting with public/private keys? The last major corporation I worked at, we had a class for encryption/decryption utilizing Triple-DES, a hardcoded password, and I believe the IV was an MD5 hash of the data to be encoded. No keys needed.|||

Doesn't the hard coded password defeat the point of the encryption? It does avoid the need to store a plain text connection string in code but, unless I'm missing something, it'd be quite straight forward to decompile the application, obtain the hard coded password and reverse engineer the encryption.

This is the reason behind my thinking with the public/private keys. I could use the key pair to perform the encyption, but only deploy the application with the public key making the reverse engineering impossible. If only I could get it working that is.

Steve

|||

denning_s wrote:

Doesn't the hard coded password defeat the point of the encryption? It does avoid the need to store a plain text connection string in code but, unless I'm missing something, it'd be quite straight forward to decompile the application, obtain the hard coded password and reverse engineer the encryption.

This is the reason behind my thinking with the public/private keys. I could use the key pair to perform the encyption, but only deploy the application with the public key making the reverse engineering impossible. If only I could get it working that is.

Steve

Possible, sure. With obfuscation, and a decently buried class, would I say it's probable? Probably not. But not impossible.

|||also, if someone is intent on obtaining this info, it would be pretty simple to sniff it out of outgoing packets -- I believe it's passed in cleartext, an unfortunate but unavoidable situation, if I recall. WiFi or Ethernet, no problem ... if you're using GPRS connections, it might be better protected, but I'm not certain.|||

I am still of the opinion that hard coding an encryption password offers lilttle more protection than hard coding the database password itself. If the application does ever happen to be maliciously decompiled, then it is likely to be in the hands of someone that is clued up and soon able to figure out the database connection string. I don't beleive I'm being overly cautious here, as by the nature of mobile devices there is a very real likelihood that some will get lost or stolen and it is important to protect corporate data.

I'm not sure what you refer to with regards to Wifi, Ethernet and GPRS. I am simplying referring to connection being established between an application and local SQL Server Mobile database (can that be sniffed?). Any data being transferred to HQ is done so via SSL.

Steve

|||

denning_s wrote:

I'm not sure what you refer to with regards to Wifi, Ethernet and GPRS. I am simplying referring to connection being established between an application and local SQL Server Mobile database (can that be sniffed?). Any data being transferred to HQ is done so via SSL.

Steve

yeah, sql server mobile didn't click with me until after I'd posted. I'm not sure about a local connection like that ... does it utilize named pipes, or tcp/ip? if it's tcp/ip, I suspect it can still be sniffed.

that being said, there aren't a lot of places to hide a database on a mobile device ... are you encrypting the DB? if not, you're wide open as it is ...

|||

AndrewBadera wrote:

does it utilize named pipes, or tcp/ip

No it doesn't. It's actually a non-issue anyway, as if it got into the hands of a malicious person it'd only be their connection attempts that'd get sniffed.

AndrewBadera wrote:

are you encrypting the DB? if not, you're wide open as it is ...

That's exactly what I'm doing - encrypting the SQL Server Mobile DB with a password. It's supplying the password that's causing the problem as I don't want to store it plain text within code.

Has anyone done something similar before?

|||You can use the RSACryptoServiceProvider.ToXmlString() and .FromXmlString() methods to retrieve and assign the keys. Keep in mind that the amount of the data that you can encrypt using the asymmetric cryptography providers is usually limited (even though there are ways around these limitations), so you may run into problems if your connection string gets too long.I would recommend to use secret-key (symmetric) encryption to encrypt the connection string, and use public-key (asymmetric) encryption to encrypt the key.

HTH,

Gerrit

-

Friend Class RSA

' to generate the keys:
'Dim rsa As New RSACryptoServiceProvider()
'Dim publicKey As String = RSA.ToXmlString(False)
'Dim privateKey As String = RSA.ToXmlString(True)

Friend Shared Function EncryptToBase64String(ByVal text As String, ByVal keyXml As String) As String

Dim rsa As New RSACryptoServiceProvider
rsa.FromXmlString(keyXml)
Dim s As String
s = System.Convert.ToBase64String(rsa.Encrypt(UTF8.GetBytes(text), False), Base64FormattingOptions.InsertLineBreaks)
rsa.Clear()
rsa = Nothing
Return s

End Function

Friend Shared Function DecryptFromBase64String(ByVal base64String As String, ByVal keyXml As String) As String

Dim rsa As New RSACryptoServiceProvider
rsa.FromXmlString(keyXml)
Dim s As String
s = UTF8.GetString(rsa.Decrypt(System.Convert.FromBase64String(base64String), False))
rsa.Clear()
rsa = Nothing
Return s

End Function

End Class

|||

Hi Gerrit

Thanks for the response. This is useful code that is along the lines of what I've been trying to do, but there is one fundamental problem in that the compact framework does not support the methods .ToXmlString() and .FromXmlString().

Steve

|||Sorry, I did not check if these methods were supported by the compact framework. :(

I think you can store the keys in the machine store, if that is an option for you. This way the OS would handle the security of the keys. Check the documentation for the CspParameters class and CspParameters.KeyContainerName.

Alternatively, you should be able to recover/assign all the key information via the RSACryptoServiceProvider.ExportParameters() and RSACryptoServiceProvider.ImportParameters() methods. They seem to represent the exact information that is exported by the .ToXmlString() method (I guess this method just serializes the RSAParameters class returned by the .ExportParameters() method).

Gerrit

|||

There is difficulty in getting the keys into the machine store in the first instance. Containing a public key within an external file would be the preferrable solution as it could be released with the application. Generating new keys at runtime would not work for this scenario.

The only solution I can think of is to obtain the a public key from a web service the first time the application runs and then pass the key into the machine store on the mobile device for subsequent use. However this is not an ideal solution and may not be an option for anyone else attempting to do the same thing.

For a seemingly simple requirement, this has proved far more complex than I would have expected. I'd hope the issue to be more throughly addressed in the next release of the compact framework.

|||so why can't you simply generate your keys during development, store the public key in an xml file, and provide that to the client?|||

AndrewBadera wrote:

so why can't you simply generate your keys during development, store the public key in an xml file, and provide that to the client?

I am unable to import the public key into the RSA provider from a string because .FromXMLString() is not supported in the compact framework. I was thinking that I could pass back parameters in a non-string format from a web service in order to import them into the RSA provider, but I no longer believe this is possible either.

Seems like I'm at a dead end on this one.

|||Have you tried to retrieve/assign the key information via the RSACryptoServiceProvider.ExportParameters() and RSACryptoServiceProvider.ImportParameters() methods as I suggested in my previous post? I have not tried this, but you should be able to serialize the RSAParameters object directly to a XML file.

Gerrit

No comments:

Post a Comment