Question

I've got a script that runs in PhantomJS on my server that I need to pass a password to as a command line argument to the script. For those of you unfamiliar with PhantomJS, it's a headless webkit browser that runs server side with no interaction from the client.

In order to load the password into the context of a virtual webpage object in PhantomJS, it needs to be stored in a javascript file that is included on a particular web page object. The password file will only persist long enough to login and will be deleted. I have a fail safe mechanism that deletes the file after the script no longer needs it. I do not want this password to be stored in plain text so I want to use AES encryption.

Passwords will be stored in my database using AES encryption. I know that storing passwords this way isn't the most secure method, but the script needs to know the password so hashing is not an option.

I will be invoking this PhantomJS script from C# in my ASP.NET MVC3 web application and I'd like to pass an encrypted password from C# using either AesManaged or RijndaelManaged. I've got a basic understanding of cryptography and have managed to get some code working in C# and javascript. However, when I encrypt text from C#, I am unable to decrypt it with javascript. Here is some of my C# code for an example:

class Encrypter
{
    public RijndaelManaged rijndael { get; set; }
    public byte[] bytesToDecrypt { get; set; }
    public byte[] bytesToEncrypt { get; set; }

    public Encrypter(string base64key, string base64IV)
    {
        // CBC/128/PKCS7
        rijndael = new RijndaelManaged();
        rijndael.BlockSize = 128;
        rijndael.KeySize = 192;
        rijndael.IV = Convert.FromBase64String(base64IV);
        rijndael.Padding = PaddingMode.PKCS7;
        rijndael.Mode = CipherMode.CBC;
        rijndael.Key = Convert.FromBase64String(base64key);
    }
    public string Encrypt(string strInptData)
    {
        bytesToEncrypt = UTF8Encoding.UTF8.GetBytes(strInptData);

        ICryptoTransform encryptor = rijndael.CreateEncryptor(rijndael.Key, rijndael.IV);
        bytesToDecrypt = encryptor.TransformFinalBlock(bytesToEncrypt, 0, bytesToEncrypt.Length);

        return Convert.ToBase64String(bytesToDecrypt);
    }

    public string Decrypt()
    {
        ICryptoTransform decryptor = rijndael.CreateDecryptor(rijndael.Key, rijndael.IV);

        byte[] decryptBytes = decryptor.TransformFinalBlock(bytesToDecrypt, 0, bytesToDecrypt.Length);
        // return original string
        return UTF8Encoding.UTF8.GetString(decryptBytes);
    }


    public string ByteArrayToString(byte[] array)
    {
        StringBuilder sb = new StringBuilder();

        sb.Append('[');
        foreach (byte b in array)
        {
            sb.Append(b);
            sb.Append(", ");
        }
        sb.Append("] length : " + array.Length);
        return sb.ToString();
    }
}

The javascript code uses the slowAES implementation:

$('#encrypt').click(function () {
                var plainText = $('#plaintext').val();
                var $encrypted = $('#encryptedtext');
                var bytesToEncrypt = cryptoHelpers.convertStringToByteArray(plainText);
                var key = cryptoHelpers.base64.decode("bALREf3IwJhzO8JdUwZ55coMydj2YD8R");
                var iv = cryptoHelpers.base64.decode("v/VCTAlV5+kexBFN16WY5A==");

                var result = slowAES.encrypt(bytesToEncrypt, 
                                           slowAES.modeOfOperation.CBC,
                                           key,
                                           slowAES.aes.keySize.SIZE_192,
                                           iv);
                var base64Result = cryptoHelpers.base64.encode(result);
                var hexKey = cryptoHelpers.toHex(key);
                $encrypted.val(base64Result);
                $('div#results').append('<p>bytes to enrypt: ' + bytesToEncrypt + ' length ' + bytesToEncrypt.length + '</p>');
                $('div#results').append('<p>Key: ' + key + '</p>');
                $('div#results').append('<p>IV: ' + iv + '</p>');
                $('div#results').append('<p>Result: ' + result['cipher'] + '</p>');
                $('div#results').append('<p>Hex Key: ' + hexKey + '</p>');
            });
            $('#decrypt').click(function () {
                var $plain = $('#plaintext');
                var encrypted = $('#encryptedtext').val();
                var bytesToDecrypt = cryptoHelpers.base64.decode(encrypted);
                var key = cryptoHelpers.base64.decode("bALREf3IwJhzO8JdUwZ55coMydj2YD8R");
                var iv = cryptoHelpers.base64.decode("v/VCTAlV5+kexBFN16WY5A==");

                var result = slowAES.decrypt(bytesToDecrypt, 
                                           slowAES.modeOfOperation.CBC,
                                           key,
                                           slowAES.aes.keySize.SIZE_192,
                                           iv);
                var plainresult = cryptoHelpers.convertByteArrayToString(result);
                $plain.val(plainresult);
            });

This code for the javascript was merely setup so I could do quick tests of encryption and decryption. I will be processing the password as a command line argument from PhantomJS after I've got the encryption and decryption working between C# and javascript.

The key and IV are:

string base64key = "bALREf3IwJhzO8JdUwZ55coMydj2YD8R";
string base64iv = "v/VCTAlV5+kexBFN16WY5A==";

After running the encryption of the text 'test', Here's the output for the C# code:

BytesToEncrypt: [116, 101, 115, 116, ] length : 4
Base64 Encrypted String: RxNZztdUgbx3KPdvVvMmBg== 
Key: [108, 2, 209, 17, 253, 200, 192, 152, 115, 59, 194, 93, 83, 6, 121, 229, 202, 12, 201, 216, 246, 96, 63, 17 ] length : 24 
IV: [191, 245, 66, 76, 9, 85, 231, 233, 30, 196, 17, 77, 215, 165, 152, 228 ] length : 16 
Result: [71, 19, 89, 206, 215, 84, 129, 188, 119, 40, 247, 111, 86, 243, 38, 6 ] length : 16 
Decrypted: test

Here's the output from the javascript:

Bytes to Encrypt: 116,101,115,116,12,12,12,12,12,12,12,12,12,12,12,12 length 16

Base64 Encrypted String: VRPeZsEJpP7OURwg3FdI8g==

Key: 108,2,209,17,253,200,192,152,115,59,194,93,83,6,121,229,202,12,201,216,246,96,63,17 length 24

IV: 191,245,66,76,9,85,231,233,30,196,17,77,215,165,152,228 length 16

Result: 85,19,222,102,193,9,164,254,206,81,28,32,220,87,72,242 length 16

I've applied PKCS7 padding to the C# code because slowAES uses PKCS7 padding. I've even tried using my own implementation of PKCS7 padding and still haven't gotten the same result byte array. Please let me know if I'm missing something. Thanks much.

Was it helpful?

Solution

Don't store passwords in the database! Store a salt and hash, and use the salt to derive the hash.

Here on SO: Password hashing, salt and storage of hashed values

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top