6

My organization has decided to encrypt certain data in our database, and I've been given the task of implementing the encryption. I need to be able to encrypt the data, store the encrypted version in a VARCHAR field in our database, and later retrieve it and decrypt it back to its usual state.

On the surface it seems like a simple task. There are a number of ways to implement encryption. One I've used before is based on the AES encryption code found in this StackOverflow question.

What makes it harder in this case, is I need to write code to encrypt/decrypt the data in various applications that access our database, some of which are developed using different technologies. We have applications written in Coldfusion 5, in Classic ASP, and in ASP.NET 2.0. I need to be able to encrypt data and store it in the database with Coldfusion code, and then read and decrypt it back to its original form in ASP.NET. Or encrypt it in Classic ASP and decrypt it in Coldfusion. Or any other combination of these platforms.

This has proven to be harder than I expected. Different classes/objects/functions/libraries that claim to use the same algorithms seem to generate different results even when given the same data and the same shared secret. In the past, we've used CAPICOM to provide encryption interoperability between Coldfusion and Classic ASP. But I've run into trouble trying to get that to work in ASP.NET. I've read this article about how to get CAPICOM to work in .NET, but the suggestions haven't been working for me. I can't even seem to generate an interop class or import a reference to the COM object without getting an error. Also some of our production servers have operating systems that don't appear to be compatible with CAPICOM, so that may be a dead end anyway.

Does anyone have any suggestions as to how I can implement encryption in such a way that any of the 3 platforms can decrypt what the others have encrypted, while still using a reasonably-strong algorithm?

Edit 2011-12-29:

As noted in the comments below, I am currently hoping to find an ASP.NET solution that is compatible with some of our existing Coldfusion/ASP Classic code that uses CAPICOM. The reason for this is that our team lead doesn't want me to introduce a new encryption method into our code for our current purpose unless I also revise our older apps using encryption for a different purpose to use the same method. He wants to use the same encryption method for both purposes. Since revising our old apps to use a new encryption method means not just changing the code, but also tracking down all the data encrypted by the older apps, decrypting it, and re-encrypting it using the new method, I'm hesitant to go that route unless I have to. Hopefully, I'll find a way to get ASP.NET to read the existing encrypted data.

The encrypted data from our other Coldfusion and ASP Classic applications was encoded using the CAPICOM COM object. As far as I can tell, the settings have universally been AES encryption, maximum key size (which I believe is 256-bit in AES).

At @Leigh's request, here is a simplified example of how our existing CF apps use CAPICOM:

<cfscript>
    encryptObject = CreateObject("com","CAPICOM.EncryptedData");
    encryptObject.Algorithm.Name = 4; // 4 is AES
    encryptObject.Algorithm.KeyLength = 0; // 0 is MAX, I believe 256-bit in the case of AES
    encryptObject.SetSecret(sharedSecret);
    encryptObject.Content = stringToEncrypt;

    encryptedData = localScope.encryptObject.Encrypt();
</cfscript>
Community
  • 1
  • 1
Joshua Carmody
  • 13,410
  • 16
  • 64
  • 83
  • Please pay more attention to your tag choices. The `asp` tag had proved ambiguous, and was cleaned up in favor of `asp-classic`. You would have had the only question on Stack Overflow tagged `asp`, and that should have sent up a big red flag. – Joel Coehoorn Dec 28 '11 at 22:19
  • @Joel My apologies. I didn't notice, but I'll look more carefully in the future. – Joshua Carmody Dec 28 '11 at 22:20
  • What database product are you using? – Jake Feasel Dec 28 '11 at 22:23
  • @Jake Feasel - SQL Server 2005 – Joshua Carmody Dec 28 '11 at 22:23
  • 2
    is an encrypted column a choice? http://msdn.microsoft.com/en-us/library/ms179331(v=sql.90).aspx – Peter Dec 28 '11 at 22:27
  • When you say you achieved interop between CAPICOM and CF - which algorithm (key size, encoding, ...) was used? Can you post a sample of the CF code? – Leigh Dec 29 '11 at 18:37
  • @Leigh - Code sample added to question. – Joshua Carmody Dec 29 '11 at 18:51
  • 1
    @Joshua - Oh I did not realize you were using CAPICOM from CF, rather than the built in encrypt functions. From what I have read, CAPICOM does things a little differently as described in this broken link: http://www.jensign.com/JavaScience/dotnet/DeriveBytes/ . You can view it with the [wayback machine](http://wayback.archive.org). What problems did you have with the interop assembly, because that would seem the simplest approach? – Leigh Dec 29 '11 at 19:52
  • @Leigh - Thanks for continually following up on this question. I was starting to write up a question about my issues with the interop and I was going to drop a link to it here in the comments. But due to time constraints, I haven't been able to. We might end up going with a stop-gap method our team lead came up with, but I'm not sure yet. Thanks for your help. – Joshua Carmody Jan 03 '12 at 20:45
  • @Joshua - Okay. Let us know how it turns out (when time allows). – Leigh Jan 04 '12 at 16:18

4 Answers4

6

Since you have the common database platform between all of the systems, I would leave your encryption/decryption there. Here's an article about column-specific encryption within SQL 2005:

http://msdn.microsoft.com/en-us/library/ms179331(v=sql.90).aspx

Jake Feasel
  • 16,785
  • 5
  • 53
  • 66
  • Thanks! That's a solid suggestion. I had no idea that was an option. I'm going to run that by the team and see if anyone has a problem with it. – Joshua Carmody Dec 28 '11 at 22:30
  • 1
    Just dont store the key in the database. – Dale Fraser Dec 29 '11 at 03:25
  • This is a good suggestion. I ran it by the project lead though, and he said he was ok with me using it **IF** I modified all of our existing encryption/decryption code to also be SQL-based so our methods are consistent. Ugh. That's still on the table, but it'll be less work if I can find ASP.NET code that plays well with the CAPICOM method we've used in CF and classic ASP in the past. So I'm going to keep trying for that for now. – Joshua Carmody Dec 29 '11 at 14:39
  • I realize my question has morphed a bit from what I originally asked. I liked this answer the best and I think it's a great solution for the problem I originally described, so I'm accepting it. Thanks! – Joshua Carmody Jan 03 '12 at 20:46
2

I just did a similar thing (encrypting between Classic ASP and ASP .NET, ignoring Coldfusion) and I came across CAPICOM several times too, but after a lot of toing and froing (and searching) I found a COM AES/Rijndael library which I ended up using, Hyeongryeol.Security.Cryptography (for some reason the download is named .wma - it is a zip file so manually open it with 7-Zip or whatever you use).

Encryping/decrypting in .NET uses the RijndaelManaged class (there's an example in the download).

All-in-all it's very simple to get working. Just register the COM DLL (for Classic ASP) and it should be good to go. Here's an extract from our build.bat which ensures (hopes) it's registered:

echo Registering HyeongryeolStringEncrypter.dll
copy Libraries\Hyeongryeol.Security.Cryptography\ASP\HyeongryeolStringEncrypter.dll %system32%\HyeongryeolStringEncrypter.dll
regsvr32 /s %system32%\HyeongryeolStringEncrypter.dll

Just make sure you use the same key/IV either side.

akiller
  • 2,462
  • 22
  • 30
  • I'm aware of the `RijndaelManaged` class, but I'm not sure how to get it to play nice with the cryptography functions available to me in ASP and CF. For example, one thing I don't understand - In our existing ASP classic code when we encrypt with CAPICOM, the we need only set the data, encryption method, and key. But the `CreateEncryptor` function of the RijndaelManaged class wants a key and a _vector_. What's a vector, why doesn't CAPICOM require it, and what can I pass to `CreateEncryptor` that'll yield the same results as CAPICOM does? – Joshua Carmody Dec 29 '11 at 14:36
  • If you use the Hyeongryeol COM DLL you don't need to use CAPICOM. Hyeongryeol accepts both a key/IV parameter (the same as RijndaelManaged) and in all of my tests I was able to encrypt/decrypt strings successfully at either the ASP or the ASP .NET side and get the same result. – akiller Dec 29 '11 at 16:20
  • Understood. Unfortunately we already have some applications using CAPICOM, and it'd be ideal if the solution for this project were compatible. I'm going to try to find an ASP.NET decryption method that's compatible with our existing CAPICOM code first. If I can't find one, I'll look into Hyeongryeol or SQL Server-based encryption. – Joshua Carmody Dec 29 '11 at 16:39
  • 1
    @Joshua - Re: What's a vector, why doesn't CAPICOM require it RijndaelManaged uses CBC mode by default which requires an [`iv`](http://en.wikipedia.org/wiki/Initialization_vector). Perhaps CAPICOM uses the less secure EBC mode (like CF) which does not require an iv. – Leigh Dec 29 '11 at 18:01
1

After an extensive search on multiple sites, others suggesting SSO but obviously with limitations, I came to the code below which allowed me what I wanted.

  1. We have an existing CF site and we are redesigning it using ASP.NET and Membership provider.
  2. We wanted to keep the passwords from existing CF but transfer them to aspnet_membership table, and hash them.
  3. We also wanted to be able to change password from either system as they will run concurrently for at most 3 months.
  4. This means we wanted to be able to update the aspnet_membership table from CF and to also authenticate against that table.

The below code allows us to hash the password from CF and match it against the aspnet_membership table. If theBased64Hash is the same as password in the table, then the user can be authenticated. We can now encrypt the password should the user want to change the password from the CF side, and still be validated in ASP.NET side.

Update (Fixed issue with concatenation)

<cfscript>
    thePassword = "originalPassword";
    base64Salt = "JZjdzUXREM0A7DPI3FV3iQ==";

    // extract bytes of the salt and password
    saltBytes = binaryDecode(base64Salt, "base64");
    passBytes = charsetDecode(thePassword, "UTF-16LE" );

    // next combine the bytes. note, the returned arrays are immutable, 
    // so we cannot use the standard CF tricks to merge them    
    ArrayUtils = createObject("java", "org.apache.commons.lang.ArrayUtils");
    dataBytes = ArrayUtils.addAll( saltBytes, passBytes );

    // hash binary using java
    MessageDigest = createObject("java", "java.security.MessageDigest").getInstance("SHA-1");
    MessageDigest.update(dataBytes);    
    theBase64Hash = binaryEncode(MessageDigest.digest(), "base64");

    WriteOutput("<br />theBase64Hash= "& theBase64Hash &"<br/>");
</cfscript>
Leigh
  • 28,765
  • 10
  • 55
  • 103
RealSollyM
  • 1,530
  • 1
  • 22
  • 35
  • If at all possible, you should switch to a more secure algorithm. [CFMX_COMPAT](http://help.adobe.com/en_US/ColdFusion/9.0/CFMLRef/WSc3ff6d0ea77859461172e0811cbec22c24-7c2f.html) is extremely weak and only included for backward compatibility. – Leigh Jun 03 '13 at 15:24
  • Thanks @Leigh for the sample code. It's really working for us. The reason we had to use SHA1 hash was due to ASP.NET membership control. – RealSollyM Jun 04 '13 at 08:56
  • Yes, the code works. It is just not very secure. Hence the suggestion of switching to a stronger algorithm ;-) – Leigh Jun 04 '13 at 14:09
  • FYI, updated the code sample to resolve [an issue with certain values when concatenated](http://stackoverflow.com/a/17114221/104223). – Leigh Dec 02 '16 at 17:13
0

Encryption is just modifying your data so that its not human readable then modify it back using the reverse of the original formula.

I personally would stick with AES and you should be able to get AES for those platforms.

Depending on how strong you want it to be, you could just write a simple function to do it your self.

Could be as simple as adding a series of bits to the info based on some key.

Dale Fraser
  • 4,623
  • 7
  • 39
  • 76