Quick Tip: Encrypted Pass Through Authentication (EPTA) Initialization Vectors

When setting up Encrypted PTA, configuring the correct Initialization Vector in the PTA_ENCRYPTION_IV configuration setting can be confusing. I find the setting documentation misleading unless you really understand what it is asking for.

Per the field documentation:

Specifies the initialization vector value to use for PTA encryption. Valid values are an up-to 16 byte value given as a hex encoded (base 16) list of bytes appropriate for the encryption type specified by PTA_ENCRYPTION_METHOD: 16 bytes for 'aes' encryptions and 8 bytes for 'des3' encryption. Values less than the maximum will be zero padded.


The following special values are also acceptable:

  • Blank : Empty IV (all zeros)
  • 'ENCODED' : Decryption expects the IV to be read from the encrypted string (after the salt (if any) and before the actual encrypted value).

Note: From a security standpoint, the use of the 'ENCODED' keyword is preferred over blank or hard-coded values, assuming the proper cryptographically random values are sent along in the encrypted data.


The default is blank.


Examples:

  • des3 [8 bytes]:
    • '53616c7479426974'
    • '466f6f' (Will be padded to '466f6f00')
  • aes [16 bytes]:
    • '557365466f7241657344656372797074'
    • '466f6f' (Will be padded to '466f6f0000000000')

What they mean by "all zeros"

The point of confusion for most developers is around the Blank (all zeros) option. When setting the IV for AES, you may think that you need to set a 16 character string of all 0's, such as 0000000000000000.

In C#, this would look like this.

// IV is 16 bytes encoded aes.IV = Encoding.Default.GetBytes("0000000000000000");

When you try to decrypt that PTA token using an empty PTA_ENCRYPTION_IV setting, most of the PTA token would be decrypted except for the first block, which would be jumbled. This indicates that you have an IV problem since the framework is using CBC mode.

What the framework is really looking for is not an "all 0" string, but 16 null bytes which when transalted to HEX is represented as 32 "0" characters.

In C#, you would get 16 null bytes like this.

// IV is 16 bytes encoded aes.IV = new byte[16];

What the PTA_ENCRYPTION_IV setting is looking for is not a "string" representation of the IV, but instead a HEX encoded representation. Understanding this, the correct PTA_ENCRYPTION_IV setting for an IV of "0000000000000000" is actually 30303030303030303030303030303030; the character "0" transaltes to 0x30 in HEX encoding while null translates to 0x00 (or, "all zeros")

I often mix up the behavior of the PTA_ENCRYPTION_IV setting because the PTA_SECRET_KEY, in contrast, does want a string representation of the encryption key. Next time you are configuring EPTA keep in mind that PTA_ENCRYPTION_IV and PTA_ENCRYPTION_SALT want HEX values, while the PTA_SECRET_KEY wants a string representation.

Comments

Andy, you are the only person I've found with references to the Syndicated Conditional Chat Link and asp.net. I'm trying to successfully locate a contact in the RightNow system using "p_userid=keffner" as a login string. I'm getting both cannot decode base64 string errors (3) and cannot decrypt errors (9). I've also randomly had error 5 returned stating that the userid was not located. Here is my code where cipherMode=CBC, Keysize=256, paddingMode=ANSIX923, and SecretKey is a 16byte value. IV and Salt are blank. Is there something I have wrong here???

// convert to byte[]
byte[] textBytes = Encoding.UTF8.GetBytes(plainText);

using (AesCryptoServiceProvider csp = new AesCryptoServiceProvider())
{
csp.Mode = cec.CipherMode;
csp.KeySize = cec.KeySize;
csp.Padding = cec.PaddingMode;
csp.Key = cec.GenerateSecretKey();
// csp.IV = cec.GenerateIV();

// Overestimate encrypted size requirements
byte[] encryptedDataBuffer = new byte[textBytes.Length + 32];
MemoryStream encryptedOutput = new MemoryStream(encryptedDataBuffer, true);

CryptoStream encStream = new CryptoStream(encryptedOutput, csp.CreateEncryptor(),
CryptoStreamMode.Write);
encStream.Write(textBytes, 0, textBytes.Length);

encStream.FlushFinalBlock();
byte[] encryptedData = new byte[encryptedOutput.Position];
Array.Copy(encryptedDataBuffer, encryptedData, encryptedData.Length);
encStream.Close();

return encryptedData;

Any help very much appreciated!

Zircon - This is a contributing Drupal Theme
Design by WeebPal.