2

Once again I'm tasked with converting ColdFusion code used for a single sign-on to C# and am running short on time. This one is completely different than my question that was answered here, so I'm back to being in over my head.

The original ColdFusion code was executed in a <cfscript> tag. I've replaced the src and pwd variables with abbreviated placeholders just to obscure their actual values:

//create a key to be used
src="xxx";
pwd="abc";

// Base64 Decoding the key
base64Decoder = createObject("java", "sun.misc.BASE64Decoder");
desKeyData = base64Decoder.decodeBuffer(pwd);


// Initialize the constructor of DESedeKeySpec with private key
KeySpec=createObject("java", "javax.crypto.spec.DESedeKeySpec");
KeySpec=KeySpec.init(desKeyData);

// Generate the secret key using SecretKeyFactory
keyFac=createObject("java", "javax.crypto.SecretKeyFactory").getInstance("DESede");
secretKey =keyFac.generateSecret(KeySpec);


// Get CIPHER OBJ ready to use
decodecipher = createObject("java", "javax.crypto.Cipher").getInstance("DESede/ECB/PKCS5Padding");
decodecipher.init(2, secretKey);

encodecipher = createObject("java", "javax.crypto.Cipher").getInstance("DESede/ECB/PKCS5Padding");

encodecipher.init(1, secretKey);

stringBytes = toString(src).getBytes("UTF8");
raw = encodecipher.doFinal(stringBytes);

// Base64Encoding of generated cipher
cipherText=ToBase64(raw);

I also have a document from the other party that outlines the steps for creating the single sign-on as follows:

Creating the encrypted token

  • Create the plain text (this corresponds to the variable src above, and that part I've done successfully in C#)
  • Pad the plain text

  • Decode the key (the key corresponds to the variable pwd above, and must be base 64 decoded; I think I've successfully gotten up to this point as well.)

  • Perform the encryption (use the decoded key obtained above and the plain text to do the encryption)

  • Encode the cipher text (url encoded)

I have the BouncyCastle libraries installed and am trying to make use of those, but I'm stuck on the actual encryption step. So far the beginning of my C# conversion looks like this (once again the token and key have abbreviated placeholders to obscure the actual values):

//steps omitted here to create src string
string token = "xxx";
string key = "abc";
byte[] decodedKeyBytes = Convert.FromBase64String(key);

I know that's not a whole lot to go on, but I've tried so many things that haven't worked that I've lost track. Eventually when I get to the piece where I'm initializing the cipher, I assume I need something like this:

PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DesEdeEngine());

Thanks very much for any suggestions/examples.

Update:

Thanks to the very helpful answer below, I was able to get this working using the following code:

string token = "xxx";
string key = "abc";

byte[] base64DecodedKeyBytes = Convert.FromBase64String(key);
byte[] inputBytesToken = System.Text.Encoding.UTF8.GetBytes(token);

// initialize for EBC mode and PKCS5/PKCS7 padding
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DesEdeEngine());
KeyParameter param = new KeyParameter(base64DecodedKeyBytes);
cipher.Init(true, param);

// encrypt and encode as base64
byte[] encryptedBytesToken = cipher.DoFinal(inputBytesToken);
string tokenBase64 = System.Convert.ToBase64String(encryptedBytesToken); 
Community
  • 1
  • 1
user3562286
  • 151
  • 2
  • 13

1 Answers1

0

This one is completely different

Not so much ;-) You already answered your own question.

Do not let the java code throw you. Ignoring some unused variables, it is doing exactly the same thing as encrypt() on your other thread - except with "TripleDES" instead of "Blowfish". encrypt() hides a lot of the complexity, but internally it is does the same thing - using those same java classes FWIW. That means you can use the same C# code. As you already guessed, you just need to swap out the crypto engine:

....
// initialize for EBC mode and PKCS5/PKCS7 padding
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DesEdeEngine());
...

Update:

Just to elaborate a bit, when you use encrypt( someUTF8String, base64Key, algorithm, encoding), CF performs the same steps as your java code internally:

  1. Decodes the key from base64, and creates a KeySpec object for the given algorithm, ie

    // Base64 Decoding the key // CF may use a different decoder, but the overall process is the same base64Decoder = createObject("java", "sun.misc.BASE64Decoder"); .... secretKey =keyFac.generateSecret(KeySpec);

  2. Next it extracts the UTF-8 bytes of the plain text, ie

    stringBytes = toString(src).getBytes("UTF8");

  3. CF then creates a cipher, which pads and encrypts the plain text, ie:

    encodeCipher = createObject("java", "javax.crypto.Cipher").getInstance(algorithm); encodeCipher.init(1, secretKey); // 1 - ENCRYPT_MODE raw = encodeCipher.doFinal(stringBytes);

  4. Finally, CF encodes the encrypted bytes as base64, ie:

    cipherText=ToBase64(raw);

So as you can see, the java code and encrypt do exactly the same thing.

Leigh
  • 28,765
  • 10
  • 55
  • 103
  • Ah okay, thank you! At least I wasn't terribly off with the cipher initialization. :) I'm still a little unsure about the encryption part though - in the code from my other question, I only had the static key, but in this one I've got a key and a dynamically generated encrypted token, so I'm not quite sure how to combine both of those in the encryption step. – user3562286 Feb 04 '15 at 04:26
  • EDIT: *combine both of those in the encryption step.* Maybe my brain is tired, but I am not seeing the full picture in what you posted. The original CF/java code is just a basic `encrypt()`. Run the C# code with the TripleDES class and you will get the same result. Could they mean "use the code above to generate a 'key' to be used for the "Blowfish" encryption"? – Leigh Feb 04 '15 at 04:40
  • Any luck? It seemed like you were simply trying to convert the cfscript code. If not, could you post more details because it sounds like there is a piece of the puzzle missing. – Leigh Feb 04 '15 at 13:53
  • Yes, I was finally able to get this working just now - thank you again for your help and the very clear explanation, I really appreciate it! I didn't realize that, as you pointed out, encrypt() does so many of those steps behind the scenes; the CF code looked so different to me, and I was getting hung up trying to recreate each piece. I might have actually been better off trying to translate the instructions directly into C# without the CF code for reference. :) I've updated my post with the successful code. – user3562286 Feb 04 '15 at 20:51
  • Yes, for the most part CF uses java's core crypto library. Since there is only one way to use that API, `encrypt()`uses the same methods internally as any other java application. Glad I could help :) – Leigh Feb 06 '15 at 17:14