locked
How to store RSA private data RRS feed

  • Question

  • Hey all

    A quick one hopefully! :)

    I have a .NET application that uses modified code to do RSA encryption on various data from the following: http://www.obviex.com/samples/Encryption.aspx.

    My one and only question is where can I securely store the pass phrase, salt value and initialization vector? Storing these directly in the source code is obviously a no go, and using Dotfuscator or something similar is out of the question...

    Any suggestions welcome!

    Thanks in advance.


    • Edited by tompsonn Thursday, December 15, 2011 7:00 AM
    Thursday, December 15, 2011 7:00 AM

Answers

  • I'm still a little bit confused about how one client is supposed to be able to unwrap the symmetric key... wouldn't it have been wrapped using a totally different key pair than the client?

    Each client has to have the symmetric key wrapped by the client's public key.  The client uses its private key to unwrap the symmetric key.

    There is no "server" other than the SQL server, so there is no "on the server side". Initial set up of the database (tables, schemas, initial data, etc) is done by a client instance with sysadmin rights on the SQL server.

    Treat 'server side' as stuff the server admin has to do, ie. not performed by the client application.  (The admin tool will be an SQL client, or course, but it's not the same SQL client as the users have.)

    Something tells me that there must be an easier way to implement this so that all clients can encrypt/decrypt data to and from the database without too much hassle...

    Of course, if you're willing to deal with the issues involved the secure distribution of symmetric keys (which is why asymmetric keys are so useful).  Alternatively you can declare 'there is only one key' and build it into the clients - but I thought you didn't want to do that, hence your original post.

    (BTW, have you noticed how your 'quick question hopefully' has turned out?  This is typical of security - it's much harder than you think.)


    Answering policy: see profile.
    • Marked as answer by tompsonn Friday, December 23, 2011 2:31 PM
    Wednesday, December 21, 2011 4:02 PM

All replies

  • I have a .NET application that uses modified code to do RSA encryption on various data from the following: http://www.obviex.com/samples/Encryption.aspx.

    My one and only question is where can I securely store the pass phrase, salt value and initialization vector? Storing these directly in the source code is obviously a no go, and using Dotfuscator or something similar is out of the question...

    There's a terminology issue I want to raise first.  The link you quote does not perform RSA encryption, but the symmetric Rijndael algorithm.  Symmetric algorithms don't have private keys, they have keys (or secret keys) which must be kept secret. This is an important distinction.  AES is a form of Rijndael with specific parameters.

    Salts and IVs don't need to be kept secret provided they change unpredictably with every encryption.

    The passphrase does need to be kept secret, however.

    If your goal is to completely automate the process with no human intervention, then the short answer is that it is impossible to make this secure, the reason being that any such automation must necessarily encode all the information needed to access the passphrase (and therefore the secret key).  Anyone with access to the application (and the skill) can reverse engineer this information and recover the passphrase (and secret key).  Only by introducing external information at run time from outside of the program (e.g. a passphrase or PIN entered securely by a human on request) can this be prevented.

    Some systems attempt to minimise the amount of human interaction by asking for passphrase/PIN once and then caching it for the remainder of the system up-time.  This can be acceptable if done correctly, but it always represents a compromise of security requirements.

    Incidentally, you are correct to reject Dotfuscator as a means of protecting a passphrase.

    Edit: I've just realised the significance of the words 'modified code' in your post.  I hope this means that you are using Rijndael for the data encryption using a secret key, and then wrapping the secret key using RSA.  The same argument applies; what you have to protect is the means of unlocking the RSA private key (a PIN or a passphrase).


    Answering policy: see profile.
    Thursday, December 15, 2011 12:29 PM
  • Thanks for your reply!

    I'm very new to cryptography, so thanks for the explanation and correction!

    First up, I meant modified in that I'd just modified the code... it actually has no significance at all... so no I'm not wrapping the secret key using RSA...

    Perhaps if I outline my specific requirement, it would better! This is a distributed application that has to be machine independent because this data is stored in a central SQL database, and some of it needs to use some form of reversible encryption so that it can be used (and then quickly released from memory!) on the client.

    Perhaps Rijndael is not the right method to use for this scenario? If not... what would you suggest? The application is still in development, so there's plenty of head room to work with!

    Thanks!


    • Edited by tompsonn Friday, December 16, 2011 12:48 AM
    Friday, December 16, 2011 12:43 AM
  • Rijndael is very appropriate for this scenario - although I'd suggest using AES-128 (which, as I said before, is Rijndael with specific parameters).  Choose an appropriate encryption mode (CBC is commonly used; avoid ECB).

    The data can be transmitted by the server in its encrypted form to and from the client, which keeps it from being revealed over the network.  The client (assuming it has the secret key) can decrypt data it receives.

    The question then becomes: how does the client obtain the secret key in a secure manner?  It's unsafe to distribute the secret key embedded in your client software, as this will (a) make the key accessible in the manner described in my previous reply, and (b) prevent you changing the key without replacing the software if the key is compromised.

    The technique I mentioned before, 'key wrapping' involves encrypting a secret key with a different key (secret or public).  This might not seem to make much difference - you have protected the original key but now need another key - but in fact it's a big step forward to achieving your goal.

    Each user can be assigned a separate key-wrapping key such that when they connect to the server and authenticate themselves, the server can wrap the database secret key with the user's wrapping key and return the result to the user.  The user then unwraps the database key using his wrapping key and the database key becomes available for his use for the duration of the connection.

    This is where RSA comes in.  RSA is an algorithm which involves two distinct but mathematically-related keys: a private key which is ket secret by user, and a public key for others to use. Normally the public key is made available as a public-key certificate.

    Key wrapping can be performed using the user's public key on the server, and passed back to the client where the user can unwrap the database key using his private key.

    This is a broad outline of one approach you can use for this.  There's a lot of details I'm omitting because I suspect they would be too much at this stage.  Unfortunately it's the details which make the difference between a design which is properly secure and a design which only looks secure. You should seek advice from someone properly qualified.

     

     


    Answering policy: see profile.
    Friday, December 16, 2011 3:28 PM
  • Thanks for your help so far!

    The only server in the scenario is the SQL server. There is no "server" that users connect to, so there would be no concept of a per-user "key wrapping key", mainly because there isn't a concept of a user either. The only time authentication is involved is when the connection to the SQL database is made (and of course the SQL server knows nothing about such high level concepts like encrypted data that clients receive).

    I'm not too sure how the private/public key system in RSA actually works, but I did have an idea, but I'll need to ask how it works... Could each user have their own private key encrypted using DPAPI in the user.config file, and then in the database, we can store a public key?

    Thanks! :)

    Saturday, December 17, 2011 2:21 AM
  • Could each user have their own private key encrypted using DPAPI in the user.config file, and then in the database, we can store a public key?

    Yes, but there's a better way which makes use of the standard Certificate Stores.

    As before, each user is assigned an RSA private key for this purpose with a corresponding public-key certificate. 

    The private key is stored in the user's personal certificate store which is always part of his profile and already protected by the login credentials.

    The public-key certificate can be stored in the database in a table describing users, together with a wrapped copy of the database secret key.

    When the client application has connected to the database, it must first retrieve the wrapped secret key from the user's entry and then use the private key (in the user's 'My' certificate store) to unwrap it.  The secret key is then available for use in reading and writing the encrypted part of the database.

    Denying that user access then becomes simply a matter of removing the wrapped key for that user.  Granting him access means preparing a wrapped key for him.

    Under this particular arrangement, replacing the DB secret key would require offline processing of the database; a new secret key is chosen, and each encrypted field re-encrypted using the new key, and the public key in the user's certificate used to wrap the new secret key for each user.  Don't forget to validate the certificate before using it in this way.

    With more information in the user records and encrypted fields, you can remove this 'offline' requirement.


    Answering policy: see profile.
    Tuesday, December 20, 2011 4:59 PM
  • TLDR:

    I simply need to protect global data in a database and stop it from being looked at over a network (possibly the internet) in a way that can be easily implemented without having to store encryption keys inside the application itself.

    --

    Thanks again for your reply.... that seems like a great solution, however...

    I should make it clear that encrypted data is not per-user in the database. Access to the objects that contain this data is controlled at a different level and is only encrypted to prevent prying eyes over a network. (Internal application - if internal users try anything malicious, they are basically going to be jobless).

    So in theory there should need to be a public key and a private key for each client that connects and the essence is that basically I need a way to encrypt this data without storing keys etc by embedding them into the application binaries itself.

    If we do it this way Rijndael can be skipped entirely (and so too can the key wrapping) and RSA can just be used to encrypt/decrypt the data?

    Consider this: When the DB is set up for the first time, we get the first public/private key pair and store the public key in the DB. Then when the first client connects we give them their own private key (either stored using DPAPI [easier for me], or cert store).

    Is this possible?

    Thanks!


    • Edited by tompsonn Wednesday, December 21, 2011 8:49 AM
    Wednesday, December 21, 2011 8:48 AM
  • TLDR:

    I simply need to protect global data in a database and stop it from being looked at over a network (possibly the internet) in a way that can be easily implemented without having to store encryption keys inside the application itself.

    --

    Thanks again for your reply.... that seems like a great solution, however...

    I should make it clear that encrypted data is not per-user in the database.

    That's why there must be a single key used to encrypt the database.

    (Internal application - if internal users try anything malicious, they are basically going to be jobless).

    And that's why you need to plan for changing that key.

    So in theory there should need to be a public key and a private key for each client that connects and the essence is that basically I need a way to encrypt this data without storing keys etc by embedding them into the application binaries itself.

    This is what RSA gives you.

    If we do it this way Rijndael can be skipped entirely (and so too can the key wrapping) and RSA can just be used to encrypt/decrypt the data?

    BUT .. RSA is much too slow to use for all encryption, and the 'single database key' requirement means that all users would have to have the same RSA keypair, which makes it pointless.  This is why you need to use (something similar to) the combined Rijndael/RSA scheme I outlined previously.

    Consider this: When the DB is set up for the first time, we get the first public/private key pair and store the public key in the DB. Then when the first client connects we give them their own private key (either stored using DPAPI [easier for me], or cert store).

    This enters into an area called 'key management', and to some extent, this is a separate (albeit important) topic - one of those details I skipped over earlier.

    It's important because if you're not careful, you can end up allowing uncontrolled access to your database because anyone with a copy of the application (however obtained) could gain access to your database - all they need to do is run it.  This may not be what you want!

    Normally, you should manage the creation of RSA keys separately in a controlled manner, so that only those user who are permitted access to the database are provided with a key-pair.

    Is this possible?

    Possible, yes, but as indicated above, not safe.


    Answering policy: see profile.
    Wednesday, December 21, 2011 9:34 AM
  • I simply need to protect global data in a database and stop it from being looked at over a network (possibly the internet) in a way that can be easily implemented without having to store encryption keys inside the application itself.

    I should make it clear that encrypted data is not per-user in the database. Access to the objects that contain this data is controlled at a different level and is only encrypted to prevent prying eyes over a network.

    I've realised that it's not quite clear whether the fundamental concern is that the data needs to be encrypted 'at rest' within the database (as I've been assuming), or simply in transit over the network.

    If the latter, then the whole problem is much easier to solve - use an encrypted tunnel for your network connection (you'll still be faced with the key management problem, though).


    Answering policy: see profile.
    Wednesday, December 21, 2011 9:47 AM
  • Thanks for explaining everything.

    There cannot be unauthorized access to the database simply because the SQL server will refuse authentication for any user not given permission to connect.

    The data must be encrypted "at rest" within the database, yes... Sorry now that you've mentioned it like that, it seems that would be my higher concern.

    So in simple terms then, how would I go about implementing Rijndael key-wrapping mechanism with RSA? I understand the concept now, but I am unsure on how to implement it.

    For example, how/when do I generate private keys for RSA, where and how do I store them on the client? Do I create private keys using some method that takes a public key that I created? How do I create the public key?

    Then, how do I generate the Rijndael passphrase and where do I store that (I'm assuming encrypted using RSA public key in the database)?

     

    Thanks so much for your help with all this!

    Wednesday, December 21, 2011 10:07 AM
  • (Several times IE has mysteriously crashed while trying to answer your questions; I'm not sure of the cause, but I suspect the forum software itself. This forum looks different to the one I normally use (VC++ General).)

    You will need to become familiar with the concepts behind public key infrastructure and how that is represented in Windows.

    From a developer's point, the principal Cryptographic API involved is CryptoAPI or its successor CNG ("CryptoAPI Next Generation"), and there are .NET versions of these.  Avoid CAPICOM for new development.

    The steps you need to take on the client are:

    1. Generate an RSA keypair suitable for Key Exchange;
    2. Construct a PKCS#10 certificate request;
    3. Send the request to a CA or certificate server and receive the PKCS#7 response containing the certificate.
    4. Unpack the PKCS#7 response and place the certificate and the corresponding private key in the user's personal ('My') Certificate Store.
    5. Place the Certificate (but not the private key) in the database for use in wrapping keys. You can use CryptExportKey with PUBLICKEYBLOB to get the certificate in a suitable form to save.

    On the server side, you need to:

    1. create an AES key for the database encryption;
    2. create another RSA keypair and certificate (as above) for use by server maintenance tools that you will need;
    3. wrap the AES key using the server's certificate from 2) and store it in the DB somewhere for use by the server tools;
    4. create multiple wrapped instances of the AES key (one for each client) using the client certificates and place them in the DB for the clients to use.

    At run time, the client application needs to find its wrapped key in the database and use its private key to unwrap it.  It can then use that key for Decrypting and Encrypting.

    I've tried to provide helpful links in the above, although it won't always be obvious why the link is useful.

    It's possible that the .NET functionality is easier to use than the native C++ functionality referenced above.  The basic plan is the same, though.

    Beware: this is not complete.  There's still a lot of important detail to be filled in.


    Answering policy: see profile.
    Wednesday, December 21, 2011 2:11 PM
  • Thanks, that is really helpful and should be enough to get me started, but...

    I'm still a little bit confused about how one client is supposed to be able to unwrap the symmetric key... wouldn't it have been wrapped using a totally different key pair than the client?

    There is no "server" other than the SQL server, so there is no "on the server side". Initial set up of the database (tables, schemas, initial data, etc) is done by a client instance with sysadmin rights on the SQL server. 

    Something tells me that there must be an easier way to implement this so that all clients can encrypt/decrypt data to and from the database without too much hassle...
    • Edited by tompsonn Wednesday, December 21, 2011 2:48 PM
    Wednesday, December 21, 2011 2:17 PM
  • I'm still a little bit confused about how one client is supposed to be able to unwrap the symmetric key... wouldn't it have been wrapped using a totally different key pair than the client?

    Each client has to have the symmetric key wrapped by the client's public key.  The client uses its private key to unwrap the symmetric key.

    There is no "server" other than the SQL server, so there is no "on the server side". Initial set up of the database (tables, schemas, initial data, etc) is done by a client instance with sysadmin rights on the SQL server.

    Treat 'server side' as stuff the server admin has to do, ie. not performed by the client application.  (The admin tool will be an SQL client, or course, but it's not the same SQL client as the users have.)

    Something tells me that there must be an easier way to implement this so that all clients can encrypt/decrypt data to and from the database without too much hassle...

    Of course, if you're willing to deal with the issues involved the secure distribution of symmetric keys (which is why asymmetric keys are so useful).  Alternatively you can declare 'there is only one key' and build it into the clients - but I thought you didn't want to do that, hence your original post.

    (BTW, have you noticed how your 'quick question hopefully' has turned out?  This is typical of security - it's much harder than you think.)


    Answering policy: see profile.
    • Marked as answer by tompsonn Friday, December 23, 2011 2:31 PM
    Wednesday, December 21, 2011 4:02 PM
  • Thanks so much, I think I can go ahead and actually get something working with all the information you've given me!

    Thanks again!

    I marked your last post as the answer, but I think many of them are... :)
    • Edited by tompsonn Friday, December 23, 2011 2:31 PM
    Friday, December 23, 2011 2:31 PM