According to MSDN SecureString contents is encrypted for additional safety so that if the program is swapped to disk the string contents can't be sniffed.
How is such encryption possible I wonder? The algorithm would be fixed and therefore either well-known or deductible (say one of seven widely used in industry algorithms) and there must be a key somewhere in the program. So the attacker could fetch the encrypted string, fetch the key and decrypt the data.
How can such encryption be useful?
I'm quoting from an article about the DPAPI which is used to derive the key. This should answer most questions that you have about SecureString.
And yes, SecureString has drawbacks and is not completely secure, there are ways to access to data, for example, injecting Hawkeye into the process is mentioned on MSDN as a way to extract the SecureString. I have not personally verifed this assertation.
DAPI Key Management
DAPI is a symmetric based encryption technique, which means it uses the same key to both encrypt and decrypt data. Before getting to some examples of how to use DAPI it's worth covering how DAPI manages its key. For the most part DAPI key management process is invisble and you generally don't need to worry about it, which is the main reason why DAPI is a good approach.
In the introduction I wrote that the master key is generated from the user's login password. This isn't the complete picture. What actually happens is Windows uses the user's login password to generate a master key. This master key is protected using the user's password and then stored along with the user's profile. This master key then gets used to derive a number of other keys and it's these other keys that are used to protect the data.
The reason why Windows does this is it allows applications to add additional information, called entropy, to the process of generating the individul keys. You see if every application running under the user's login account used the same key then every application could unprotect DAPI protected data. Sometimes you might want applications to be able to share DAPI protected data; however, sometimes you won't. By letting the application contribute entropy to the generation of a key then that key becomes application specific and any data that is protected by that application can only be unprotected again if they know the entropy.
Although generating a master key, and then using that master key to generate other keys to do the actual encryption, might seem like a long winded approach it does have one major advantage. Since there is an additional level of abstraction between the user password protected master key and the actual keys used to protect the data it means that when the user changes their password then only the master key need to be re-protected; none of the protected data needs to be re-protected. Since the master key is much smaller in size than the data then a significant performance saving is made.
When the user's password changes then of course a new master key is generated. This new master key is then used to generate new individual keys. However, since all the previously generated individual keys were derived from the old master key then Windows needs to store all previous master keys, which it does. Windows never forgets a master key and all protected data is marked with a GUID that indicates which master key was used to protect the data. So in terms of adaptability DAPI is able to cope with changes to users' passwords, while ensuring a) that protected data doesn't need to be re-protected, and b) that keys used to previously protect data as still available, and c) it does all this automatically for you.
Unless the computer is a member of a domain DAPI can only unprotected data on the same machine that was used to protect it.
As well as allowing user level protection, in that master keys are based on user passwords and protected data for one user cannot be unprotected by another user, DAPI also provides machine level protection, in that the master keys are based on machine specific information. Machine level master keys allow applications to store protected data so that it can be unprotected by all users of the application. The only difference in the process already described is the master key is generated from machine specific information not user specific information.
I looked at one point into the code for it and it uses Windows's advapi32 to do its dirty work. So the key isn't stored in the application's memory.
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
internal static int SystemFunction040([In, Out] SafeBSTRHandle pDataIn, [In] uint cbDataIn, [In] uint dwFlag)
Which is better known as RtlEncryptMemory.
It decrypts with RtlDecryptMemory (SystemFunction041).
I'm sure the compiler does something with the SecurityCriticalAttribute as well.
edit this was reflected using 4.0. other versions might different.
As others have already answered, the contents of SecureString are encrypted using DPAPI, so the keys aren't stored in your application, they're part of the OS. I'm not 100% positive, but I would assume that SecureString uses a user-specific key, so that even if another process gains access to the block of memory, it would have to be running under the same credentials in order to simply decrypt the content using the DPAPI. Even if not, the machine key (in theory) prevents the string from being readily decrypted if transferred to another system.
More important with SecureString is how & when you use it. It should be used to store string data that needs to be retained in memory for "extended" periods of time, but which are not frequently needed in their decrypted form. At some point, you're going to have to decrypt it into a regular old System.String, or a System.Char[]. This is when it's most vulnerable in memory. If you do this too often, then you have multiple copies of the decrypted string floating around in memory waiting to be collected.
As a general rule, if I'm reading encrypted data (say login credentials) that I need to retain for infrequent use (PayPal or Amazon API interaction, for instance), then I store/cache those credentials as SecureString, then decrypt it as-needed only long enough to make the web service calls, and ensure that the lifespan of any decrypted copy is only a few lines of code.
It's probably also wise to use critical blocks or similar to hint to the CLR that it should not context-switch while the decrypted string is in use, to improve the chances that any decrypted copies are collected before the memory is cached or swapped.
By the magic of DPAPI:
This class stores its data using the Data Protection API (DPAPI) protected memory model. In other words, data is always in its encrypted form while it is stored inside of a SecureString. The encryption key is managed by the local security authority subsystem (LSASS.EXE), and through the DPAPI, the data can be decrypted via interprocess communication.
Related
I'm looking into using Windows' Data Protection API (DPAPI) to encrypt some data. One requirement I have is to use a Dynamic Salt when encrypting values.
I have noticed through testing that if I encrypt the same string multiple times, I get a different result. This is with using the same string, null Entropy value, and same scope.
This makes me FEEL as though there is a dynamic salt involved already. I am not seeing any documentation stating this.
Here is the method I am calling https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.protecteddata.protect?view=netframework-4.7.2
.
Does DPAPI handle dynamic salting already? If not, what is causing the encrypted values to change each time?
The MasterKey, however, is not used explicitly to protect the data.
Instead, a symmetric session key is generated based on the MasterKey,
some random data, and any additional entropy, if an application
chooses to supply it. It is this session key that is used to protect
the data.
[...]
The session key is never stored. Instead, DPAPI stores the random data
it used to generate the key in the opaque data BLOB. When the data
BLOB is passed back in to DPAPI, the random data is used to re-derive
the key and unprotect the data.
https://msdn.microsoft.com/en-us/library/ms995355.aspx
This random data included in the encrypted data acts as a salt.
The intention of the optionalEntropy parameter is to allow individual applications to protect themselves from other applications running under the same user account and is not required to increase the effectiveness of the salting already performed.
We are developing a huge financial, budget and expense management solution and one of the requirements is the user data and postings collected by our app stored in sql server MUST be encrypted by user supplied key.
We are using SQL server 2012,EF 6 and .NET 4.5.
What we have tried:
We created class library with two functions in c# that does the encryption and decryption.The assemblies are complied to sql assembly and that works fine using a single encryption key.
The challenge:
The database contain data from different users who supply different key.the question is
How do we store user supplied keys such that it's secure...e.g If a user lost/forgot the key used to encrypt their data..the app can recover it.. while the DBA who supports this database should NOT have access to the keys..?
if we have 1M users..that means million keys..the tables have relational references so it become tricky to encrypt each row differently per user...What's the industry standard in this scenario..?
First off, I would like to preface this answer by stating that I don't pretend to know the industry standard in this scenario -- I don't. That being said, here's what I would do.
In cryptography, there's an algorithm known as Shamir's Secret Sharing. In summary, it would let you split the key into multiple parts:
User chooses their private key, and splits it into 4 parts (n = 4), where any subset of 2 parts (k = 2) is sufficient to reconstruct their secret. You can vary n and k to suit your needs, where n would be the number of recovery options provided and k is the number that must be correct.
User then encrypts each part of the private key with their recovery options and sends the encrypted parts to the server to store.
When user requests file, server sends encrypted file to client who can then decrypt it with their key.
In the event the user forgets their key, they can request their encrypted key parts from the server, provide recovery answers in an attempt to decrypt at least k of them, and (hopefully) get their data back.
Notes:
Server doesn't store answers to the recovery options. This means it won't be able to decrypt the files without the user's help (unless you were to send the raw splits to the server as well, but that's a potential security risk). In essence, you could help the user get back to their key, but all bets are off if they can't remember any of their recovery options (e.g. amnesia, Alzheimer's, untimely death).
If the user were to change their secret key, every file would need to be decrypted and re-encrypted using the new key. This could be a potentially expensive task.
The sum of recovery options needed to remake the key must not be easy for an attacker to guess. For example, if I have 4 recovery options of which I must provide 2, and my choices are phone number, best friend's first name, and some others, then this would not be secure. There aren't very many possible choices, which would make that example combination very easy to brute force.
So I'm working on a supplemental web-based system required by an HR department to store and search records of former personnel. I fought the requirement, but in the end it was handed down that the system has to both enable searching by full SSN, and retrieval of full SSN. My protestations aside, taking some steps to protect this data will actually be a huge improvement over what they are doing with it right now (you don't want to know).
I have been doing a lot of research, and I think I have come up with a reasonable plan -- but like all things crypto/security related there's an awful lot of complexity, and it's very easy to make a mistake. My rough plan is as follows:
On first time run of the application, generate a large random salt, and a 128bit AES key using RijndaelManaged
Write out both of these into a plaintext file for emergency recovery. This file will be stored offline in a secure physcial location. The application will check for the presence of the file, and scream warnings if it is still sitting there.
Store the salt and key securely somewhere. This is the part I don't have a great answer for. I was planning on using DPAPI -- but I don't know how secure it really is at the end of the day. Would I be better off just leaving it in plaintext and restricting filesystem access to the directory its stored in ?
When writing a record to the database, hash the SSN along with the large salt value above to generate a field that is searchable (but not recoverable without obtaining the salt and brute forcing all possible SSNs), and AES encrypt the raw SSN value with a new IV (stored alongside) to generate a field that is retrievable (with the key/iv) but not searchable (because encrypting the same SSN twice should yield different output).
When searching, just hash the search value with the same salt and look it up in the DB
When retrieving, decrypt the value from the DB using the AES key/iv
Other than needing a way to store the keys in a relatively secure way (number 3 above) it seems solid enough.
Things that won't work for us:
"Don't do any of this" Is not an option. This needs to be done, and if we don't do it they'll a) get mad at us and b) just pass all the numbers around in a plaintext document over email.
This will be internal to our network only, so we have that layer of protection at least on top of whatever is implemented here. And access to the application itself will be controlled by active directory.
Thank you for reading, and for any advice.
Update #1:
I realized from the comments that it makes no sense to keep a private IV for the SSN retrieval field. I updated the plan to properly generate a new IV for each record and store it alongside the encrypted value.
Update #2:
I'm removing the hardware stuff from my list of stuff we can't do. I did a bit of research, and it seems like that stuff is more accessible than I thought. Does making use of one of those USB security token things add meaningful security for key storage?
I've had to solve a similar problem recently and have decided to use an HMAC for the hashing. This would provide more security than a simple hash, especially as you can't salt the value (otherwise it wouldn't be searchable).
Then as you say, use AES with a random salt for the reversible encryption.
It maybe that you don't need to encrypt this data but I had no choice and this seemed like a reasonable solution.
My question on IT Security https://security.stackexchange.com/questions/39017/least-insecure-way-to-encrypt-a-field-in-the-database-so-that-it-can-still-be-in
With respect to key storage there are two methods you can use if you choose to store your AES key in the web.config. First method is to use DPAPI as you mentioned. This will encrypt your web.config application setting for that box. The other method you can use is via RSA key (check out this MSDN tutorial), this will encrypt your web.config just like DPAPI however you can use the RSA key on multiple boxes, so if the application is clustered then RSA key is better (just more complicated to setup).
As far as generating the key before you run your application not on the machine running the app this way there's no chance you're going to leave the text file in the directory. You should generate the key as follows.
Generate a random value using RngCryptoServiceProvider
Generate a random salt value using RngCryptoServiceProvider
Hash the two values with PBKDF2 (Rfc2898DeriveBytes)
The reason you use the key derivation method is it protects you in case RngCryptoServiceProvider was found to be insecure for some reason which happens with random number generators.
Use AES 256 instead of AES 128, reason is these algorithms are extremely fast anyway so get the higher security it's almost free. Also make sure you're using the algorithm in CBC or CTR mode (CTR is available in the BouncyCastle library).
Now this will not give your key absolute protection if someone were able to put up a aspx file in your directory. Because that file will become part of your application it would have access to your decrypted values including your key. The reason I'm mentioning this is your network and server security will have to be top notch, so I would highly recommend you work hand-in-hand with your network security team to ensure that nobody has access to that box except the parties in the HR department that need access (Firewall not Active directory). Do NOT make this application publically accessible from the internet in any way shape or form.
You also cannot trust your HR department, someone could become a victim of a social engineering attack and end up giving away their login thus destroying your security model. So in addition to working with your network team you should integrate a two factor authentication mechanism to get into the system, highly recommend going with an actual RSA key or something similar rather than implementing TOTP. This way even if someone from the dept gives away their password because they thought they were winning a free ipad, the attacker would still need a physical device to get into the application.
Log Everything, any time someone sees a SSN make sure to log it somewhere that will be part of a permanent record that's archived on a regular basis. This will allow you to mitigate quickly. I would also put limits on how many records a person can see in a particular time frame, this way you know if someone is mining data from within your application.
Create a SQL user specifically to access this table, do not let any other user have access to the table. This will ensure that only with a particular user id and password can you view the table data.
Before deploying to a production environment you should hire a penetration testing team to test the application and see what they can get, this will go a long way to harden the application from potential attackers, and they can give you great advice on how to harden the security of the application.
Create a new salt and IV for each record. If you need to dump the data into a report for some reason (hopefully without my SSN in it), you would be able to use the method you describe with the unique salt and IV. If you only need to search on an SSN, you could actually hash it instead of using a reversible encryption (more secure).
I think I read somewhere once that hashing a limited set of inputs gets you absolutely nothing. A quick google turned up this SO post with similar warnings:
Hashing SSNs and other limited-domain information
I must admit that I am also no security expert, but given that the possible number of inputs is much smaller than 10^9 which any decent hacker should be able to breeze through in a matter of hours, hashing a SSN seems like you are adding a small layer of annoyance rather than an actual security/difficulty barrier.
Rather than doing it this way, could you do something else? For example, SSN's only have value to an attacker if they can associate a name to a number (since anyone can enumerate out all numbers easily enough). In that case, could you encrypt the user id that the SSN links to in such a way that would be impractical to attack? I am assuming your employees table has some sort of ID, but maybe instead of that do a hash on their email or some sort of guid? That way, even if they do get your SSN data, they would not be able to tell which employee's it is until they managed to brute force that link.
Then again, that approach is also flawed since your company may not have that many employees total. At that point it would be a relatively simple matter of guessing and checking against a company directory to attain everything. No matter how you slice it, this security flaw is going to exist if SSN's must be stored with other identifying data.
I need some advice on a school project I am working on. I am making an AES app for encrypting data in some files. Now these files can be accessed by many people.
For the AES key, I was thinking of using RFC2898DeriveBytes to get an encryption key from a passphrase. MSDN has some good tutorial on how to use it. Now, my problem is Where and how to store that key?
I wanted to store the key in a file in a flash drive, but if there are many users, then how to write the key to many flash drives at the same time? (A computer can have only a limited number of ports). Also, lets say I have a new user who should have access rights to some file, how do I write the key to his flash drive?
It really depends on the goal of your application.
If the intent is to encrypt the data such that any user of your applicaiton can access it, then it is more appropriate to embed the key (or, even safer, data from which to derive the key) in the application itself.
If access is to be restricted on a per user basis, then the key (or data from which to derive the key) will need to be stored on a per user basis (so that it is only available to authorized users).
A couple tips on using embedded security data:
break the data up into pieces that can be pulled from various places within the application. Use a custom algorithm to assemble the data.
it is much safer to embed data from which to derive your key than to embed the key itself. If a hacker uses a binary editor and finds your key intact in the application, it will be much easier to decrypt the files. If the same hacker finds the data from which to derive the key, he still must determine the algorithm you've used to derive the key from that data before it would be usable.
You cannot store the key; you would have to tell the user what the key is. The RFC2898DeriveBytes is useless if you simply store the output. If you need a random key, use a well seeded random number generator instead.
Normally you would encrypt a random data key with the key that is generated from the users password. Then use the data key to encrypt the data. This way you can encrypt a file for multiple users; just encrypt the same key with those of the users (generated with the PBKDF2 function in RFC2898DeriveBytes) as you do now.
Make sure you use a different salt for each time that a user enters his/her password. It's also strongly recommended to prepend a random IV to the data file, and to use authenticated mode encryption or a (H)MAC.
Personally I wouldn't store the key anywhere - just require them to enter the password and generate the key on-demand.
I've built a CMS system to allow users to create and manage online forms on my client's intranet app.
Of course some of the data handled by the forms may need to be encrypted e.g. if the system is used to build a form that handles salary specifics or whatever. So I'm using the AESManaged class to symmetrically encrypt this sort of data prior to it going into our application db.
All is fine, but now, prior to release, I could do with a steer regarding the shared secret and salt.
My original idea was to make a (dynamic) shared secret by combining the (GUID-based) ID of the Form containing the encrypted field with the (again, GUID-based) id of the Question the field is the answer to:
FormId:QuestionId
My Salt is currently generated the same way, only with the order of Guids reversed ie.
QuestionID:FormID.
I'm new to this stuff so not sure if this a sensible strategy or if I should be doing it some other way?
The salt should be a randomly generated value. Its purpose is to make dictionary/brute force attacks more difficult to execute. Wikipedia has a nice article on cryptographic salts:
http://en.wikipedia.org/wiki/Salt_(cryptography)
For the shared secret ideally it would not be a value that was stored unencrypted with the data that it was encrypting (such as your ids). It's generally a best practice that the key be chosen somehow by the end-user or admin so that they could rotate it periodically or if some sort of security breach occurred. This password key could be owned by each user of the CMS or perhaps by an admin account. If you have very serious security requirements you could pursue a third-party Key Management Server.
If the main goal here is more of obfuscation and the CMS will not be subject to some form of security audit then something along the lines of your initial idea would do. It would prevent the casual access of the data but would probably not pass an audit against formal standards that would require a random salt, a way to rotate the keys, and a way for the "owner" of the system to change the password such that you yourself could not access the data.