0

We have passwords to certain external system that we need to use programmatically to login to that system. We have no control over the external system, we can not hash the password and use it like that so we need the plaintext password at some point. The password is stored currently in an xml file in plaintext. It can not be hardcoded in the program because there are multiple difference instances of that external system with different password and more are added/removed/changed often. To at least provide some layer of protection we want to (symmetric) encrypt that password and put it in the xml file encrypted like that, and decrypt it in the program when using it (which is still not complete protection, we know that, but it's at least something). The solution must work without internet at all time, you can't rely on any public/online service.

What would be the best encryption algorithm to do that? I was going to use AES RFC2898 with keygen nb of iterations 100, keysize 128 and PKCS7 padding. The .NET implementation is at the bottom of this post. Is this a sufficiently secure choice for the intended use?

The encryption key would be hardcoded in the program which is of course not good, because if they decompile the program they could see the key or they could see it in RAM. However I don't really see an alternative to that: if you want to store that password somewhere else then you want to encrypt that and then we're back to the above. Or am I wrong and is there an alternative?

Considering that the encryption key will be hardcoded should I use a salt with the encryption? Will the salt add any amount of additional security if it's also hardcoded like the encryption key? If not I might as well leave the salt blank?

        string textToEncrypt= "thepasswordtoencryptwillbeputhere";
        int Rfc2898KeygenIterations = 100;
        int AesKeySizeInBits = 128;
        string EncryptionKey = "encryptionkeywillbehardcodedhere";
        byte[] Salt = new byte[16];
        byte[] rawPlaintext = System.Text.Encoding.UTF8.GetBytes(textToEncrypt);
        byte[] cipherText = null;
        using (Aes aes = new AesManaged())
        {
            aes.Padding = PaddingMode.PKCS7;
            aes.KeySize = AesKeySizeInBits;
            int KeyStrengthInBytes = aes.KeySize / 8;
            System.Security.Cryptography.Rfc2898DeriveBytes rfc2898 =
                new System.Security.Cryptography.Rfc2898DeriveBytes(EncryptionKey, Salt, Rfc2898KeygenIterations);
            aes.Key = rfc2898.GetBytes(KeyStrengthInBytes);
            aes.IV = rfc2898.GetBytes(KeyStrengthInBytes);
            using (MemoryStream ms = new MemoryStream())
            {
                using (CryptoStream cs = new CryptoStream(ms, aes.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(rawPlaintext, 0, rawPlaintext.Length);
                }
                cipherText = ms.ToArray();
            }
            Console.WriteLine("Done, encrypted password:");
            string encryptedPassword = Convert.ToBase64String(cipherText);
            // ...
        }
  • What sort of platform is this being run from? Is it a web application, desktop application, or console app? What is the OS you are planning on deploying this to. Is it hosted in a cloud environment? If so, which one? The reason I ask is may platforms have a pre-existing key storage mechanism. – user52472 Jul 14 '17 at 14:33
  • .Net 3.5 desktop application on Windows 7 embedded. Not cloud. No internet access available. – user968698 Jul 14 '17 at 21:46
  • This isn't adding up. If you don't have an external network connection, you aren't authenticating against a third party system. Why can't you just hash the passwords, and compare that hash against the hash of whatever the user enters? – user52472 Jul 17 '17 at 18:12
  • There is an external network connection to a large lan. It's just that the system on which our software runs has no internet access. We are automatically authenticating with a third party system in that lan. No user types in the password, as stated in the original post it's stored in a file because the authentication with the third party system happens in certain situations and it happens automatically behind the scenes (the actual user of our software does not and should not know the password to that third party system). – user968698 Jul 18 '17 at 19:19
  • If you were to use encryption then there are better ways than hard-coding the key. Such as storing the key in an HSM (hardware security module), or if an HSM is too costly you should at least load the key from separate configuration/environment at run-time so it is not hard-coded into source-code that is committed to version-control... – Sean Burton Oct 12 '17 at 16:42
1

There is very little point in encrypting this password - as you suggest, the encryption algorithm and key and salt will all be available to any attacker in any event. All encrypting will do is slow them down slightly at the expense of complexity and difficulty in rotating the password/key for the external system.

The appropriate mechanisms here are either file system permissions preventing non-authorized people from reading the configuration file (the traditional method) or a key storage mechanism such as a Hardware Storage Module (expensive! possibly overkill), a software equivalent (KeyWhiz, Hashicorp's Vault are examples) or available services (if in AWS, for instance, AWS Key Management System).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.