Copy link to clipboard
Copied
Hi,
Just wondering if anyone has any experience of decrypting an EncryptedAssertion from an IDP. My current workflow is:-
1. Decrypt the symetric key from EncryptedKey element using RSA and my private key. This is giving me a string like �4Q��2�r���h` (doesn't look right, or is it?)
2. Use the key extracted above to decrypt the contents of the EncryptedData/CipherData/CipherValue element. This decryption is being done using AES. This is giving me "Invalid AES key length: 28 bytes" error.
The decoded xml looks like below:-
<saml2:EncryptedAssertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
<xenc:EncryptedData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_1244b2f8ed8a27e5454455b4" Type="http://www.w3.org/2001/04/xmlenc#Element">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes128-cbc" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/>
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:RetrievalMethod Type="http://www.w3.org/2001/04/xmlenc#EncryptedKey" URI="#_81c4b6d490243e4e1cae5cf11e73102b"/>
</ds:KeyInfo>
<xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:CipherValue>VeBwqO/RmOs+aEtIsoZTlE8Gswa6+4z.....</xenc:CipherValue>
</xenc:CipherData>
</xenc:EncryptedData>
<xenc:EncryptedKey xmlns:xenc="http://www.w3.org/2001/04/xmlenc#" Id="_81c4b6d490fdsfsdfdsf5453f11e73102b">
<xenc:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" xmlns:xenc="http://www.w3.org/2001/04/xmlenc#"/>
<xenc:CipherData xmlns:xenc="http://www.w3.org/2001/04/xmlenc#">
<xenc:CipherValue>Gbl5+MF8srC2yvQu4A6m2CUCDVu7V1....</xenc:CipherValue>
</xenc:CipherData>
<xenc:ReferenceList>
<xenc:DataReference URI="#_1244b2f8ed8a27e5454455b4"/>
</xenc:ReferenceList>
</xenc:EncryptedKey>
</saml2:EncryptedAssertion>
And my functions to decrypt the key and then the actual data is below:-
<cffunction name="decrypt_key" hint="decrypts a base64 encoded string with RSA to its value" access="public" returntype="string" output="false">
<cfargument name="text" type="string" required="true" hint="the encrypted value as Base64 encoded string" />
<cfargument name="key" type="any" required="true" />
<cfargument name="key_type" type="string" default="private" hint="public or private">
<cfscript>
var local = structNew();
/* Create a Java Cipher object and get a mode */
var cipher = createObject('java', 'javax.crypto.Cipher').getInstance("RSA");
if (NOT isObject(arguments.key)) {
arguments.key = create_key_object_helper(arguments.key,arguments.key_type);
}
/* Initialize the cipher with the mode and the key */
cipher.init(cipher.DECRYPT_MODE, arguments.key);
/* Perform the decryption */
local.decrypted = cipher.doFinal(toBinary(arguments.text));
/* Convert the bytes back to a string and return it */
return toString(local.decrypted,"UTF-8");
</cfscript>
</cffunction>
<cffunction name="decrypt_string" hint="decrypts a base64 encoded string with AES to its value" access="public" returntype="string" output="false">
<cfargument name="text" type="string" required="true" hint="the encrypted value as Base64 encoded string" />
<cfargument name="key" type="any" required="true" />
<cfscript>
var local = structNew();
/* Create a Java Cipher object and get a mode */
var cipher = createObject('java', 'javax.crypto.Cipher').getInstance("AES/CBC/PKCS5Padding");
var secretkey = createObject('java', 'javax.crypto.spec.SecretKeySpec').init(toBinary(arguments.key), javaCast( "string","AES"));
/* Initialize the cipher with the mode and the key */
var iv = createObject('java', 'javax.crypto.spec.IvParameterSpec').init(ToBinary(arguments.text), 0, 16);
cipher.init(cipher.DECRYPT_MODE, secretkey , iv);
/* Perform the decryption */
local.decrypted = cipher.doFinal(toBinary(arguments.text));
/* Convert the bytes back to a string and return it */
return toString(local.decrypted,"UTF-8");
</cfscript>
</cffunction>
Can anyone shed some light on where I might be going wrong?
Thanks
The key should be 128 bits since the EncryptionMethod is aes128-cbc, but I think where your problem is is that the cipher.doFinal returns a byte[] (byte array), which is binary, and then you are calling toString().
Try doing an arrayLen() on the result of your cipher.doFinal() value, it should be 16 (16*8 bits per byte of the array = 128).
Now instead of doing toString() on that result you probably want to be doing toBase64() which will encode it as a base64 string. You can probably use the bui
...Copy link to clipboard
Copied
While you certaily could roll your own SAML implementation in CFML, if you are not a crypto expert I'd recommend using a library like java-saml https://github.com/onelogin/java-saml
I've done a ColdFusion SAML integration with that library, and can recommend it. It takes care of a lot of the hard parts for you.
You could also use the SAML functions in CF2021 which are built on that same java library.
Pete Freitag
Copy link to clipboard
Copied
Hi Pete,
I had looked at that library but was thinking it might be too elaborate for what I needed. I did look at some of the functions in there to try and see was I on the right track. I'm certainly no crypto expert and to me I think i'm pretty close to a working solution but I dont know enough to confirm i'm even decrypting the key properly.
Thanks
Copy link to clipboard
Copied
The key should be 128 bits since the EncryptionMethod is aes128-cbc, but I think where your problem is is that the cipher.doFinal returns a byte[] (byte array), which is binary, and then you are calling toString().
Try doing an arrayLen() on the result of your cipher.doFinal() value, it should be 16 (16*8 bits per byte of the array = 128).
Now instead of doing toString() on that result you probably want to be doing toBase64() which will encode it as a base64 string. You can probably use the builtin decrypt() function at this point, instead of your decrypt_string() function - you just need to make sure you are using CBC mode with AES again.
Ok, I might have said too much 😉 still need to be careful a bunch of things: https://cheatsheetseries.owasp.org/cheatsheets/SAML_Security_Cheat_Sheet.html
Pete Freitag
Copy link to clipboard
Copied
Hi Pete,
Thanks for all that I eventually got it working. I did use decrypt instead of the other function I had created. I had at some point tried to use that but went back to my other function. The one issue I had was with the algorithim. I got an error until I used "AES/CBC/NoPadding".
Thank again