locked
Safe way to store password in registry(encrypt & decrypt) RRS feed

  • Question

  • Hello,

    I would like to save an admin password in the registry because my application uses it for active directory logon.

    But i want it to be saved in a safe way so that nobody can read the actual password.

    I figured the best way would me encryption.

    I've looked at some encryption MD5/SHA1 but they are only 1-way encryption. My application must decrypt the password every time it logs on the active directory.

    Is there an easy/safe way to accomplish this?

    I prefer that the encryption/decryption has a "salt" function in it.

    Thanks!



    Student
    Tuesday, March 3, 2009 10:48 PM

Answers

  •  or is it better to embed it un my program in a safe string?)

    Safety of the safe string is relative, not absolute and recently MS's repudiated its claim that it is so safe. What it does is it prevents the string from multiplying in your RAM. Therefore there is no uncontrollable loss of sensitive information but if it is not encrypted then it is like any other information open to compromise. I cannot provide a link now to support what I said, perhaps later in the day I will. The most acceptable way to store encoded strings is in app.config file which is an xml file.

    AlexB
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:18 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 2:23 PM
  • OMEGA_ReD said:

    I must check if the Rijnedael encryption has the same problem as RSA.
     

    Rijnedael (AES) is a symetic cypher and uses a single key to do both the encryption and decryption, since they client application has to have access to the decryption key anyhow it doesn't really matter if you use an asymetric cypher (RSA) or symetric (AES) security wise they are equally vulnerable in this scenario.

     
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:19 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 2:23 PM
  • I don't know how Symantec does it, Microsoft must have a special area for it that no one can access. Basically all you'll be doing is hiding it as well as you can, but a user might not like it if their account is compromised because of your application (not saying it's likely, but you are putting the password somewhere less safe than Microsoft stores it).

    Edit: Antivirus programs may register themselves with windows. I know XP sees whether you have antivirus installed and tells you if it's out of date, so it may register with windows when it's installed so windows knows to let it search everywhere when it runs.
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:21 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 5:35 PM
  • OMEGA_ReD said:
    Maybe it's better to use a hash with a salt?
     

    I tried explaining before hashes are one way, its like throwing a something in a blender looking at what it grinds down to and going yeah that was a apple, you can never put it back together though.. Whats usually being done is having a supporting service run at the required authentication and having the client application delegate work to the service for processing.
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:22 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 5:52 PM
  • Hi OMEGA_ReD,

    You can use the SecureStringToCoTaskMemUnicode method of the Marshal class to convert a SecureString to a character array, then convert the character array to a normal string.
    Code Snippet:
                    //using System.Runtime.InteropServices;  
                    private string StringFromSecureString(SecureString secureString)  
                    {  
                        IntPtr memory = new IntPtr();  
                        string sPassword = "";  
                          
                        try 
                        {  
                            //Convert a SecureString to a character array  
                            char[] cPassword = new char[secureString.Length];  
                            memory = Marshal.SecureStringToCoTaskMemUnicode(secureString);  
                            Marshal.Copy(memory, cPassword, 0, secureString.Length);  
     
                            //Covert a character array to a string  
                            sPassword = new string(cPassword);  
     
                            return sPassword;  
                        }  
                        finally 
                        {  
                            Marshal.ZeroFreeCoTaskMemUnicode(memory);  
                        }  
                    } 


    Best regards,
    Guo
    • Edited by Guo Surfer Tuesday, March 10, 2009 3:13 AM add a link
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:22 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Tuesday, March 10, 2009 3:11 AM

All replies

  • Have you looked at Rijnedael?

    http://msdn.microsoft.com/en-us/library/system.security.cryptography.rijndael.aspx

    of course the example uses a file to encrypt/decrypt but with small modifications, you can make it work with a string.
    Need 2 be back @ MS - MS All the way! Follower since 1995 MS Super Evangelist| MSDN Forums Moderator
    Tuesday, March 3, 2009 11:45 PM
  •  It is not a good idea. That code is for symmetric algorithm (large texts like files). He needs asymmetric algorithm to encrypt passwords. There is plenty of code around for that also.
    AlexB
    • Proposed as answer by JChirite Tuesday, July 9, 2013 12:54 PM
    Wednesday, March 4, 2009 2:14 AM
  • Hi Both,

    Thanks for your reply's!

    I've searched the net for asymmetric algorithm and found some code and i written two functions based on that code: Encrypt and Decrypt.

    Shuld i also store the myRSA.ToXmlString(true) to the registry?

    Can you explain me more about this string? I'm guessing that "myAsymmetricKey" is a salt option.
    Is the RSA algorithm object stored in the computer in a safe place?

    Thanks for helping!

            private byte[] Encrypt(string Password) 
            { 
                // Csp: Crytographic Service Provider 
                // Create a CspParameters object to store our keys permanently in this machine 
                CspParameters persistantCsp = new CspParameters(); 
                persistantCsp.KeyContainerName = "myAsymmetricKey"
     
                // Create an instance of the RSA algorithm object 
                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider(persistantCsp); 
     
                // Specify that the private key should be stored in the CSP 
                myRSA.PersistKeyInCsp = true
     
                // Create a new RSAParameters object with the private key 
                RSAParameters privateKey = myRSA.ExportParameters(true); 
     
                // Showing keys 
                //MessageBox.Show(myRSA.ToXmlString(true)); 
     
                // Now, encrypting some test data 
                string data = txtAdminPassword.Text; 
                byte[] encBytes = Encoding.Unicode.GetBytes(data); 
     
                // Encrypt 
                byte[] encData = myRSA.Encrypt(encBytes, false); 
     
                return encData; 
            } 
     
            private string Decrypt(byte[] EncryptedData) 
            { 
                // Csp: Crytographic Service Provider 
                // Create a CspParameters object to store our keys permanently in this machine 
                CspParameters persistantCsp = new CspParameters(); 
                persistantCsp.KeyContainerName = "myAsymmetricKey"
     
                // Create an instance of the RSA algorithm object 
                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider(persistantCsp); 
     
                // Specify that the private key should be stored in the CSP 
                myRSA.PersistKeyInCsp = true
     
                // Create a new RSAParameters object with the private key 
                RSAParameters privateKey = myRSA.ExportParameters(true); 
     
                // Showing keys 
                MessageBox.Show(myRSA.ToXmlString(true)); 
     
                // Decrypt 
                byte[] decBytes = myRSA.Decrypt(EncryptedData, false); 
     
                // Showing results 
                return Encoding.Unicode.GetString(decBytes); 
            } 


    Student
    Wednesday, March 4, 2009 10:38 AM
  •  Storing the key is your responsibility. It is better to use SecureString to manipulate it in code. Once you encoded the text and stored it you are safe. You store your encoded text anywhere (Registry, app.config, xml file, etc). It is gibberish and unintelligible to anyone without possessing your key. You can keep your key on a memory flash in your pocket if you wish or you can ask for it every time as a password. The algorithm itself is well known and does not have to be stored in a safe place. It is just code. You store the encoded result (text) or whatnot. You can and should store passwords for matching as well.
    AlexB
    Wednesday, March 4, 2009 3:00 PM
  • Salts are only applicable in hasing functions. by adding a salt to your hash you prevent precomputed dictionary attacks by adding some 'random' data to the data you are hashing.  You can't do this for encryption and you don't need to do this. A hashing function like MD5 (without salt) will alway give the same value for the word 'Password' (so really handy for a precomputed dictionary attack) however as soon as you are no longer hashing but encrypting the results are based on the combination of the the data you are encrypting and the key you use for it. So the result of encrypting 'Password' with EAS or DES will never result in the same result unless you use the exact same key and therefore are not vulnerable for precomputed dictionary attacks.
     
    Now the  claim that asymetric encryption is more secure then symetric encryption only applies if the encrpytor and decryptor are two different entities (people or locations if that helps you visualize) since data encrypted with the public key of A can only be decrypted with the private key of A, A can send his public key to B without worring his data will be compromised since he is the only one that has the private key that matches the public key he send to B.

    Now for your application which does both the encryption and decryption from a single executable does it really matter if you use a public/private key or a single symetric key? Since you are A & B at the same time you need to have both keys in your application somewhere (and therefore vulnerable for people finding your keys) it doesn't really matter if people find your single symetric key or your private key you are just as compromised.

    So now that your password is safe how are you going to keep your keys safe? Yup its a never ending loop :)



     


     

    Wednesday, March 4, 2009 3:01 PM
  • Hi Ray,

    Thanks for your reply!

    Your explanation most certainly clears everything out.

    My application sores the encrypted password in the Local Machine registry.

    And i have 2 applications reading the password: the Admin console and a User application.

    The problem with the RSA-Encryption is that if i set the password under the windows Administrator account, a user account can't read the password because it doesn't know the public key.

    I must check if the Rijnedael encryption has the same problem as RSA.


    Thanks!

    Student
    Thursday, March 5, 2009 10:20 AM
  •         private byte[] Encrypt(string Password, out string PrivateKey) 
            { 
                // Csp: Crytographic Service Provider 
                // Create a CspParameters object to store our keys permanently in this machine 
                CspParameters persistantCsp = new CspParameters(); 
                persistantCsp.KeyContainerName = "myAsymmetricKey"
     
                // Create an instance of the RSA algorithm object 
                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider(persistantCsp); 
     
                // Specify that the private key should be stored in the CSP 
                myRSA.PersistKeyInCsp = true
     
                // Create a new RSAParameters object with the private key 
                RSAParameters privateKey = myRSA.ExportParameters(false); 
     
                // Showing keys 
                PrivateKey = myRSA.ToXmlString(true); 
     
                // Now, encrypting some test data 
                string data = Password; 
                byte[] encBytes = Encoding.Unicode.GetBytes(data); 
     
                // Encrypt 
                byte[] encData = myRSA.Encrypt(encBytes, true); 
     
                return encData; 
            } 
     
            private string Decrypt(byte[] EncryptedData, string PrivateKey) 
            { 
                // Csp: Crytographic Service Provider 
                // Create a CspParameters object to store our keys permanently in this machine 
                CspParameters persistantCsp = new CspParameters(); 
                persistantCsp.KeyContainerName = "myAsymmetricKey"
     
                // Create an instance of the RSA algorithm object 
                RSACryptoServiceProvider myRSA = new RSACryptoServiceProvider(persistantCsp); 
                myRSA.FromXmlString(PrivateKey); 
     
                // Specify that the private key should be stored in the CSP 
                myRSA.PersistKeyInCsp = false
     
                // Create a new RSAParameters object with the private key 
                RSAParameters privateKey = myRSA.ExportParameters(false); 
     
                // Decrypt 
                byte[] decBytes = myRSA.Decrypt(EncryptedData, true); 
     
                // Showing results 
                return Encoding.Unicode.GetString(decBytes); 
            } 
    I've altered my code so i can provide the private key.
    Wich i can store in a XML file or the registry. (I'm storing it in the registry, or is it better to embed it un my program in a safe string?)

    Please correct me if im wrong: You can only decrypt the password if you have both the Private key and the KeyContainerkey "MyAssemetricalKey".

    Please advise me if you see anything i can improve.

    Thanks!


    Student
    Thursday, March 5, 2009 11:44 AM
  •  or is it better to embed it un my program in a safe string?)

    Safety of the safe string is relative, not absolute and recently MS's repudiated its claim that it is so safe. What it does is it prevents the string from multiplying in your RAM. Therefore there is no uncontrollable loss of sensitive information but if it is not encrypted then it is like any other information open to compromise. I cannot provide a link now to support what I said, perhaps later in the day I will. The most acceptable way to store encoded strings is in app.config file which is an xml file.

    AlexB
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:18 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 2:23 PM
  • OMEGA_ReD said:

    I must check if the Rijnedael encryption has the same problem as RSA.
     

    Rijnedael (AES) is a symetic cypher and uses a single key to do both the encryption and decryption, since they client application has to have access to the decryption key anyhow it doesn't really matter if you use an asymetric cypher (RSA) or symetric (AES) security wise they are equally vulnerable in this scenario.

     
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:19 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 2:23 PM
  •  You should also keep your app.config in a folder where access can be gained with elevated priviedges only.
    AlexB
    Thursday, March 5, 2009 2:24 PM
  • OMEGA, what exactly are you trying to accomplish with this? I fear that what you're trying to do is impossible. If you want to store the user password on the computer so that your program can use it anytime it wants you cannot do so safely. Ray mentioned it:

    "So now your password is safe how are you going to keep your keys safe? Yup its a never ending loop :)"

    One of the pieces of data always has to rest in the users mind and not on the computer, and this is already done by having a password in the first place. If you encrypt the password with a key to keep it safe the user then has to input the key, which is the exact same as them inputting the password. Otherwise you have to store the unencrypted key somewhere on the computer, because if you want to encrypt that you'll end up with another key. As ray said, never ending loop.
    Thursday, March 5, 2009 2:25 PM
  • What i'm trying to accomplish:
    1. Admin Application to save the Admin credentials in the register.
    2. User Application (run's in a user environment with user permissions) run's some code (impersonation) witch require admin rights.

    I'm wondering how other applications from for example Symantec,Microsoft etc. saves the credentials in the register.

    Maybe it's better to use a hash with a salt?
    Or i can embed the key in the application in a safe string (i guess it's better to hide the key then safe it in the registry/xml).

    I don't know any safer options, and hearing your suggestions and comments there seems to be no better options.

    Thx!

    Student
    Thursday, March 5, 2009 4:21 PM
  • I don't know how Symantec does it, Microsoft must have a special area for it that no one can access. Basically all you'll be doing is hiding it as well as you can, but a user might not like it if their account is compromised because of your application (not saying it's likely, but you are putting the password somewhere less safe than Microsoft stores it).

    Edit: Antivirus programs may register themselves with windows. I know XP sees whether you have antivirus installed and tells you if it's out of date, so it may register with windows when it's installed so windows knows to let it search everywhere when it runs.
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:21 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 5:35 PM
  • OMEGA_ReD said:
    Maybe it's better to use a hash with a salt?
     

    I tried explaining before hashes are one way, its like throwing a something in a blender looking at what it grinds down to and going yeah that was a apple, you can never put it back together though.. Whats usually being done is having a supporting service run at the required authentication and having the client application delegate work to the service for processing.
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:22 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Thursday, March 5, 2009 5:52 PM
  • Owh im sorry i knew that but it slipped my mind.
    Student
    Thursday, March 5, 2009 5:55 PM
  •                     SecureString password = new SecureString(); 
                        foreach (char c in "RSA Key etc...."
                            password.AppendChar(c); 
    Hello,

    I've decided that i want to save the RSA key in a secure string embedded in my application.
    The only problem is that the decryption function expects a string and doesn't accept a secure string.

    Is it possible/safe to convert the securestring to a normal string in runtime? So that the function(as posted above) accept the string.

    Thanks.

    Student
    Thursday, March 5, 2009 6:44 PM
  • Hi OMEGA_ReD,

    You can use the SecureStringToCoTaskMemUnicode method of the Marshal class to convert a SecureString to a character array, then convert the character array to a normal string.
    Code Snippet:
                    //using System.Runtime.InteropServices;  
                    private string StringFromSecureString(SecureString secureString)  
                    {  
                        IntPtr memory = new IntPtr();  
                        string sPassword = "";  
                          
                        try 
                        {  
                            //Convert a SecureString to a character array  
                            char[] cPassword = new char[secureString.Length];  
                            memory = Marshal.SecureStringToCoTaskMemUnicode(secureString);  
                            Marshal.Copy(memory, cPassword, 0, secureString.Length);  
     
                            //Covert a character array to a string  
                            sPassword = new string(cPassword);  
     
                            return sPassword;  
                        }  
                        finally 
                        {  
                            Marshal.ZeroFreeCoTaskMemUnicode(memory);  
                        }  
                    } 


    Best regards,
    Guo
    • Edited by Guo Surfer Tuesday, March 10, 2009 3:13 AM add a link
    • Proposed as answer by Guo Surfer Wednesday, March 11, 2009 2:22 AM
    • Marked as answer by Guo Surfer Wednesday, March 11, 2009 3:29 AM
    Tuesday, March 10, 2009 3:11 AM