So, to start off, I want to point out that I know that these things are never fool-proof and if enough effort is applied anything can be broken.
But: Say I hand a piece of software to someone (that I have written) and get them to run it. I want to verify the result that they get. I was thinking of using some sort of encryption/hash that I can use to verify that they've run it and obtained a satisfactory result.
I also don't want the result to be "fakeable" (though again, I know that if enough effort to break it is applied etc etc...). This means therefore, that if I use a hash, I can't just have a hash for "yes" and a hash for "no" (as this means the hash is going to be only one of 2 options - easily fakeable).
I want the user of the tool to hand something back to me (in possibly an email for example), something as small as possible (so for example, I don't want to be trawling through lines and lines of logs).
How would you go about implementing this? I possibly haven't explained things the greatest, but hopefully you get the gist of what I want to do.
If anyone has implemented this sort of thing before, any pointers would be much appreciated.
This question is more about "how to implement" rather than specifically asking about code, so if I've missed an important tag please feel free to edit!
I think what you're looking for is non-repudiation. You're right, a hash won't suffice here - you'd have to look into some kind of encryption and digital signature on the "work done", probably PKI. This is a pretty wide field, I'd say you'll need both authentication and integrity verification (e.g. Piskvor did that, and he did it this way at that time).
To take a bird's eye view, the main flow would be something like this:
On user's computer:
run process
get result, add timestamp etc.
encrypt, using your public key
sign, using the user's private key (you may need some way to identify the user here - passphrases, smart cards, biometrics, ...)
send to your server
On your server:
verify signature using the user's public key
decrypt using your private key
process as needed
Of course, this gets you into the complicated and wonderful world that is Public Key Infrastructure; but done correctly, you'll have a rather good assurance that the events actually happened the way your logs show.
I'm pasting in one of your comments here, because it goes to the heart of the matter:
Hi Eric. I should have pointed out
that the tool isn't going out
publically, it will go to a select
list of trusted users. The tool being
disassembled isn't an issue. I'm not
really bothered about encryption, all
I need to do is be able to verify that
they ran a specific process and got a
legitimate result. The tool verifies
stuff, so I don't want them to just
assume that something works fine and
not run the tool.
So basically, the threat we're protecting against is lazy users, who will fail to run the process and simply say "Yes Andy, I ran it!". This isn't too hard to solve, because it means we don't need a cryptographically unbreakable system (which is lucky, because that isn't possible in this case, anyway!) - all we need is a system where breaking it is more effort for the user than just following the rules and running the process.
The easiest way to do this is to take a couple of items that aren't constant and are easy for you to verify, and hash them. For example, your response message could be:
System Date / Time
Hostname
Username
Test Result
HASH(System Date / Time | Hostname | Username | Test Result)
Again, this isn't cryptographically secure - anyone who knows the algorithm can fake the answer - but as long as doing so is more trouble than actually running the process, you should be fine. The inclusion of the system date/time protects against a naive replay attack (just sending the same answer as last time), which should be enough.
How about you take the output of your program (either "yes" or "no"?), and concatenate it with a random number, then include the hash of that string?
So you end up with the user sending you something like:
YES-3456234
b23603f87c54800bef63746c34aa9195
This means there will be plenty of unique hashes, despite only two possible outputs.
Then you can verify that md5("YES-3456234") == "b23603f87c54800bef63746c34aa9195".
If the user is not technical enough to figure out how to generate an md5 hash, this should be enough.
A slightly better solution would be concatenate another (hard-coded, "secret") salt in order to generate the hash, but leave this salt out of the output.
Now you have:
YES-3456234
01428dd9267d485e8f5440ab5d6b75bd
And you can verify that
md5("YES-3456234" + "secretsalt") == "01428dd9267d485e8f5440ab5d6b75bd"
This means that even if the user is clever enough to generate his own md5 hash, he can't fake the output without knowing the secret salt as well.
Of course, if he is clever enough, he can extract the salt from your program.
If something more bullet-proof is needed, then you're looking at proper cryptographic signature generation, and I'll just refer you to Piskvor's answer, since I have nothing useful to add to that :)
In theory this is possible by using some sort of private salt and a hashing algorithm, basically a digital signature. The program has a private salt that it adds to the input before hashing. Private means the user does not have access to it, you however do know the salt.
The user sends you his result and the signature generated by the program. So you can now confirm the result by checking if hash(result + private_salt) == signature. If it is not, the result is forged.
In practice this is almost impossible, because you cannot hide the salt from the user. It's basically the same problem that is discussed in this question: How do you hide secret keys in code?
You could make the application a web app to which they have no source code access or access to the server on which it runs. Then your application can log its activity, and you can trust those logs.
Once a user has an executable program in their hands, then anything can be faked.
It's worth noting that you aren't really looking for encryption.
The "non-repudiation" answer is almost on the money, but all you really need to guarantee where your message has come from is to securely sign the message. It doesn't matter if someone can intercept and read your message, as long as they can't tamper with it without you knowing.
I've implemented something similar before information was sent plaintext - because it wasn't confidential - but an obfuscated signing mechanism meant that we could be (reasonably) confident that the message was generated by our client software.
Note that you can basically never guarantee security if the app is on someone else's hardware - but security is never about "certainty", it's about "confidence" - are you confident enough for your business needs that the message hasn't been tampered with?
Related
I am creating an application with the purpose of receiving an encrypted string, decrypting it and passing the clear text string as arguments to a PowerShell script.
The executable has to be self contained, cannot connect to things like a SQL DB or anything alike. The cipher will always be the same, which means that the password/salt can't really be random either.
I know that hardcoding the password/salt is not really a good idea, but I'm struggling with how store a password/salt that doesn't change in a secure way in a self-contained executable.
Right now what I'm doing is rather than having a static string as the password/hash, I create a password and salt based on the modified date of the executable itself (with a few more things done to it). If the executable changes I'll have to recreate the cipher as the previous one cannot be decoded anymore, but at least I'm not really hardcoding a password and/or salt.
Still, I'm not sure just how secure this is and am sure there has to be a better way.
Any suggestions?
EDIT
The only place where this will be used is inside a task sequence running inside SCCM, which means that users won't be able to interact with the computer at all during the time that the task sequence is running (assuming that debug mode is not enabled, else there's also far worse things to worry about).
So I could potentially pass it in clear text to the script as no one would be able to read it since they can't interact with the PC, but then SCCM would automatically output it to logs, which obviously I don't want. I could write it on the script which would avoid having it on the logs, but if someone gets a hold of the script, bearing in mind it's a script and not compiled code, they'd know the password.
Remember the password/salt are not actually hardcoded strings as it is, they are generated during runtime, so they will not be visible using a disassembler.
This article can help you to decide how you need to design password storage
http://flagdefenders.blogspot.in/2012/12/how-to-save-password-securely.html
I need some ideas how to create a activation algorithm. For example i have demo certificate. Providing that the application runs in demo mode. When full version certificate is provided then application runs in full mode.
Is it even possible and how would be a good way creating this system?
One simple was i was thinking would be just have a 2 encrypted strings, now when the decryption is succsessful with the demo public key certificate then the application will run in demo mode and etc..
You could do something like:
Generate public/private key pair
As owner of private key, you can sign those "activation certificates" (called AC from now on)
In your app, with public key, you can check if the sign is correct
As Overbose mentioned -- you can't prevent reverse engineering. In general someone could take functionality and put it in his/hers own app and thus eliminate any possible activation algorithm. So you can only assume (or make) this is hard enough not to be worth the effort (this is the same as for cryptography -- when you make the cost of breaking the message greater then the profit of gaining it you can say it is well secured).
So you could:
Make executable self-verifying (signed by you, self-checking based on hard-coded public key (one thing: you must skip this value when self-checking)).
Do some tricks with pointers (point to the activation function, go to 7th bit and change value of it for something based on value of another pointer; in some weird places change hard-coded values to those based on occurrence of some bits in other places of the code; generally -- make it more difficult to break than by simply changing bits in executable with hex editor)
Try to make some protocol that your server would use to ask questions about the app ("gimme the value of 293 byte of yourself") and check answers.
Use imagination and think of some weird self-checking method nobody used before :)
As mentioned -- none of this is secure from cutting the authentication part off. But nothing is and this could make it harder for crackers.
Background: I've deployed an activation based system built on top of a third-party license system, i.e. server, database, e-commerce integrations. I've also separately written a C# activation system using RSA keys, but never deployed it.
Product Activation commonly means that the software must be activated on a given machine. I assume that's what you mean. If all you want to do is have two strings that mean "demo" and "purchased", then they will be decrypted and distributed within hours (assuming your product is valuable). There is just no point.
So. assuming you want "activation", then when the user purchases your software, the following process needs to happen:
Order-fulfillment software tells Server to generate "Purchase Key" and send to user
User enters "Purchase Key" into software
Software sends Purchase Key and unique Machine ID to server.
Server combines Purchase Key and Machine ID into a string and signs it with its certificate and returns it to user.
Software checks that signature is valid using Servers public key.
Software could check in lots of places: loading the sig in lots of places, checking it in others.
When generating Purchase Keys, the server can store not only what produce was purchased, but what level of product. You can also have "free" products that are time limited, so the user can try the full version of the software for 30 days.
You are using C#, so make sure you obfuscate the binaries, using dotfuscator or equivalent. However, even with that there is nothing you can do against a determined hacker. Your goal, I assume, is to force non-paying users to either be hackers themselves, or to have to risk using a cracked version: kids wont care, corporations might. YMMV.
The code that does the checking needs to be in every assembly that needs protecting, otherwise an attacker can trivially remove protection by replacing the assembly that does the checking. Cut and paste the code if you have to.
Or just buy something.
Another option is to have the server pre-generate "Purchase Keys" and give them to the Order fulfillment service, but then you dont get to link the key to the customers details (at least not until they register). Better to have the ecommerce server hit your server when a purchase has been made, and have your server send it out.
The hard part isn't so much the generation of activation keys as it is the creation of the server, database, and the integration with e-commerce software, and most of all, human issues: do you allow unlimited installs per Purchase Key? Only 1? If only 1 then you have to have customer-support and a way to allow a user to install it on a new machine. That's just one issue. All sorts of fun.
This guy wrote a blog post about a similar idea, explaining what he did with their own commercial software. Also wrote a list of recommendations about the most obvious cracking techniques. Hope it helps.
One simple was i was thinking would be just have a 2 encrypted
strings, now when the decryption is succsessful with the demo public
key certificate then the application will run in demo mode and etc..
Could be a simple solution. But this way you won't prevent someone to reverse engineer your binaries and make the execution jump to the correct line. Everyone has your program, has a complete version of it, so it's only a matter of find how to break this simple mechanism.
Maybe a better solution is encrypt a part of the binaries needed to use the full application version, instead of a simple string. This way to execute the application complete version someone need to decrypt those binaries in order to execute them.
Please take in consideration that even that solution isn't enough. There are other problems with that:
Does all the version of your tool will share the same encryption key? Breaking one of them for breaking all..
Even if you use a different key for each binary application released, does the encrypted binary are identical? Once cracked one, you can reuse the unencrypted binaries for all distributed applications.
How to solve these problems? There's no simple solution. Most of the more important commercial software with even sophisticated protection systems are broken just few hours or days after they have been released.
Product activation is not a problem that asymmetric cryptography can solve. Asymmetric cryptography is about keeping secrets from your adversary. The problem is that you can't keep a secret that is stored on you're adversaries machine, that would be security though obscurity.
The correct way to do product activation. Is to generate a Cryptographic Nonce that is stored in a database on your server. You give this Nonce to the customer when they buy the product, and then they activate it online. This activation process could download new material, which would make it more difficult for the attacker to modify the copy they have to "unlock" new features.
But even with DRM systems that require you to be online while using the product. Like the ones found in new games like "From Dust" are still broken within hours of their release.
One of the benefits of public key encryption is that you can verify the origin of a given piece of data. So if you store the public key in your assembly, then sign a given piece of data (say an authorization code or serial number) your assembly can verifiably determine that you were the one that created that data - and not a hacker. The actual data itself isn't all that important - it can be a simple pass/fail value.
This is actually pretty easy to do with .NET. You can use an x509 certificates or like we use in DeployLX Licensing the RSACryptoServiceProvider.
I would highly recommend buying a commercial product (doesn't really matter which one, though DeployLX is excellent) and not doing this yourself for 2 reasons
Even if you're a great developer, you'll probably get it wrong the first time. And any savings you might have enjoyed by rolling your own will be lost to recovering from that mistake.
You'll spend far more time working on your own system - time that you should spend making your product great.
The second phase in protecting the software is to make sure that it runs the way you created it - and hasn't been modified by a hacker. It really doesn't matter what encryption you use if hackers can check if( licensed ) to if( true ).
You can use AsProtect to solve this problem. This is good staring point.
My application makes use of the RijndaelManaged class to encrypt data. As a part of this encryption, I use a SecureString object loaded with a password which get's get converted to a byte array and loaded into the RajindaelManaged object's Key at runtime.
The question I have is the storage of this SecureString. A user entered password can be entered at run-time, and that can be "securely" loaded into a SecureString object, but if no user entered password is given, then I need to default to something.
So ultimately the quesiton comes down to:
If I have to have some known string or byte array to load into a SecureString object each time my application runs, how do I do that? The "encrypted" data ultimately gets decrypted by another application, so even if no user entered password is specified, I still need the data to be encrypted while it goes from one app to another. This means I can't have the default password be random, because the other app wouldn't be able to properly decrypt it.
One possible solution I'm thinking is to create a dll which only spits out a single passphrase, then I use that passphrase and run it through a couple of different hashing/reorganizing functions at runtime before I ultimately feed it into the secureString object. Would this be secure enough?
Edit For clarity*: The encrypted data is being passed via files between machines. Think of it as a Zip file which always has a password, a default one is assumed if nothing is directly entered by the user.
There is no point in symmetrically encrypting with a string that's hard-coded into your executable. It will only give a false sense of security. No amount of hashing fixes this scheme.
See this Pidgin FAQ for the same point in a different context.
I am unclear why you think you need the inter-app communication to be encrypted. If this communication is local to the machine, then I don't see the need for encryption, particularly encryption that isn't user-specific. Is this a DRM scheme?
EDIT: If it's being passed to a different machine, perhaps you can hard-code a public key, and then have the other machine decrypt with the matching private key.
Let me tackle your final question first.
"Would this be secure enough?"
The only one that can answer that is you. Nobody here knows what "secure enough" means in the context of your application.
Are you building an application to keep the diary of teenage girls? Sure, it would be "secure enough".
Are you building an application to encrypt information or authentication for military grade secure systems? Nope, not even close.
You can only rely on one type of security if you intend to store the password in your source code and thus executable, and that is security by obscurity.
If your problem is that you can't, or won't, store the password in the source code, then moving it into a separate dll solves nothing, you've just moved the problem to a different project.
However, I'm wondering about something. You say "I have to default to something". Is that it? You're trying to store a default value for the secure password string in the source code? How about "THISISNOTAPASSWORD"?
Eric Lippert's You Want Salt With That? (original blog post)
Also read his post to Use the right tool for the job where he ends with the following tips:
If you possibly can, simply don’t go there. Encryption is extremely difficult to get right and is frequently the wrong solution in the first place. Use other techniques to solve your security problems.
If the problem is an untrustworthy client then don’t build a security solution which requires trusting the client.
If you can use off-the-shelf parts then do so.
If you cannot use off-the-shelf-parts and do have to use a cryptosystem then don’t use a cryptosystem that you don’t fully understand.
If you have to use a cryptosystem that you don’t fully understand, then at least don’t use it to solve problems it was not designed to solve.
If you have to use a cryptosystem to ski through the trees, then at least don’t allow the presumably hostile client to choose the message which is encrypted. Choose the token yourself. If the token must include information from the client then sanitize it in some way; require it to be only straight ASCII text, insert random whitespace, and so on.
If you have to allow the client to choose the token, then don’t encrypt the token itself. Sign a cryptographically-secure hash of the token. Its much harder for the attacker to choose a token which produces a desired hash.
Don’t use the same key pair for encrypting outgoing messages as you do for protecting incoming messages. Get a key pair for each logically different operation you're going to perform.
Encrypt the communications both ways.
Consider having a revocation mechanism, so that once you know that Eve is attacking you, you can at least revoke her license. (Or you can revoke a known-to-be compromised license, and so on.)
This article on securing SQL connection strings should be just as applicable for storing encrypted passwords, where you let the OS handle the encryption of the salting seed for your decryption.
It sounds to me like perhaps you should be using a PKI solution instead of encryption/decryption. If you have another application that needs to consume the encrypted data, then you could have a key pair for that application, and give the public key to the app that is doing the encryption. That way you are still keeping your data secure, but not introducing a bunch of additional code that ultimately doesn't give all that much protection.
A quick google search gave me this Code Project article that talks about using the Windows Certificate Store in .Net
I am about to sell a program I have written in C# and I want to control licenses for it, strictly. That means I want to let the client connect to my server every single time it starts. This also gives me the ability to disable keys (in case of chargebacks on paypal or distribution of the code). Of course this might be a hassle for other users, but it is necessary in this case.
Since I was unable to find any good .NET Licensing systems that are uncracked, I wanted to take the approach of writing a little one myself.
My plan was to do the following:
Generate a key.dat containing 1024 characters that gets shipped with the software (individual to each user)
In the application entrypoint add a httprequest to my server that sends the key.dat + current timestamp, encrypted.
My HTTP server (running PHP) decrypts the request and checks if the key is valid (in my database) and replies with the "access level" (license type). If the key is invalid or disabled it replies with an errorcode. Just like with the request, the reply is being salted with a timestamp, so someone can't validate his program by sending a valid packet to himself. The timestamp is being checked in the client. The reply is encrypted with RSA and a previously generated public key.
Client receives response, decrypts with private key and reacts.
Is RSA the correct approach for this, so I can assure that the packets are sent by me and are not crafted (by noone else having the public key)?
Is there a better approach for solving this problem?
Someone who wants your software bad enough will just decompile it and remove the part of the code that phones home on startup.
If you were to add a checksum to the app that checks whether the code has been altered, someone can just change the checksum the program checks against (or remove the check entirely).
People who want your application enough will find ways around any type of protection you can conceive. You're better off sticking to something simple, having a product that is worth paying for (and easily) and make sure it's worth the price you're asking.
EDIT
Given that protection is important, the fact that the users will have code running on their machines is a risk you can avoid. If the users don't have the code, they can't crack it. They can't copy it and share it.
Now, it might not apply to the application you intend to write, but you should consider writing a web, Flash or Silverlight application instead of a regular client application. That way you don't have to distribute the code to customers. All you have to do is manage credentials into the application, which should be a lot easier than your round-about RSA system.
It's also easier to push out new versions of the software in a centralized model, and you won't have to worry about theft at all. Of course, load will become an issue when it wasn't before. And not all applications can be centralized easily (or at all). I'm just proposing this to make sure you consider it because it is a valid solution to your problem.
A web-based application will have the same issues as your application (i.e. it will be down whenever the user is offline, whenever the network is down, whenever your server is down, etc). So there's no added risk in that regard.
Is RSA the correct approach for this?
I do not think RSA is your best choice.
One of the capabilities of PKE (Public Key Encryption) is that it lets parties talk to each other who previously have never exchanged information before (eg. strangers).
I do not see this applying to your case. Your software knows your server well. They are not "strangers".
Consider instead Shared Secret Key encryption, where each copy of the software you distribute is given a unique secret key, and your server knows each user's secret key as well. The keys are never sent, and must be protected, but can still be used to encrypt, sign, and validate communications.
Edit After considering the comments and other answers.
Anyone who wants your software badly enough will be able to bypass the authentication completely. RSA does nothing to prevent that.
The real question is: Does breaking a single license make all licenses vulnerable/worthless. In both cases, (RSA and Secret Key), the answer is No. Just because one copy of the software got hacked and got its key exposed, or the licenses system bypassed, other copies are no more exposed. PKE and SSE seem equal in that respect to me.
Because Shared Secret Key is easier to implement, and computationally faster to execute, I think it is preferred in this case over RSA/PKE. That is not to say RSA is "wrong". It will accomplish what you are after, to the same degree that SSE will (no more, no less). But I think SSE is the smarter choice.
I have a business requirement that forces me to store a customer's full credit card details (number, name, expiry date, CVV2) for a short period of time.
Rationale: If a customer calls to order a product and their credit card is declined on the spot you are likely to lose the sale. If you take their details, thank them for the transaction and then find that the card is declined, you can phone them back and they are more likely to find another way of paying for the product. If the credit card is accepted you clear the details from the order.
I cannot change this. The existing system stores the credit card details in clear text, and in the new system I am building to replace this I am clearly not going to replicate this!
My question, then, is how I can securely store a credit card for a short period of time. I obviously want some kind of encryption, but what's the best way to do this?
Environment: C#, WinForms, SQL-Server.
Basically avoid by all means taking the responsiblity to save the CC details on your side, however I can assume you are using a thirdparty service to do your transaction such as PayPal/Verisign or whatever, most of them have API's that enables you to save CC credentials at their side, and they give you back a key that you can then use later to complete or initiate transactions, so they take care of the hard part, while all what you have to do is store this string key in your DB.
I don't believe it's actually illegal to store CVV info (in the sense that it's against any law), but it does violate Payment Card Industry rules, and they could impose any number of different sanctions. So, your requirements could actually result in you not being able to accept credit cards ;-(
Andrew, you need to understand the PCI-DSS, no small task. Personally, I find it extremely vague but here is what I understand.
First off, from the scenario you describe I would attempt to authorize the card for the full amount and then if that failed I would store the customer's information (but not the cardholder data) so someone could contact the user. Where I use to work some of our customers would only charge $1.00 and then void the transaction immediately, just to make sure the card was valid. They would then process all orders manually.
Where you will need to store the number is on a successful authorization. The only number you need then is the credit card number and the transaction code (at least with every gateway I have ever worked with).
The standard, last time I looked at it, is not specific on encryption algorithms but instead makes it clear it should be currently unbreakable encryption.
Now, one thing you cannot do is store the CCV subsequent to authorization. My understanding is that you can store it prior to authorization but I could never get anyone that would put that in writing. Basically, you authorize the card, you better wipe it.
And it is not illegal at this point but if you get nailed they will bring the hammer down on you. They have within their authority to level heavy fines against you, but it seems like what they usually do is put you in remediation. If you don't comply I don't know what happens because everyone I have heard this happening to complied. But then they really go up your booty with a microscope.
Ultimately, I believe their only stick they really have is to prevent you from accepting credit cards. Most merchants I have worked with were scared to death of exactly that.
If you just want to store the string for a short period of time in memory, you can take a look at System.Security.SecureString.
Taken from this answer:
SecureString values are stored encrypted (obfuscated, rather), but most importantly, they are never swapped to disk and can be disposed of immediately when you're done with them.
They're tricky to use because you can only build them one character at a time (to encourage you to build them by capturing keystrokes as the user types their password), and require three lines of code to recover and then wipe their plain text, but when used properly they can make a program more secure by avoiding the virtual-memory vulnerability.
At the end of the example the SecureString is converted into a regular managed string, which makes it vulnerable again (be sure to use the try-catch-finally pattern to Zero the string after you're done with it). SecureString's use is in reducing the surface-area of attack by limiting the number of copies the Garbage Collector will make of the value, and reducing the likelihood of being written to the swap file.
// Make a SecureString
SecureString sPassphrase = new SecureString();
Console.WriteLine("Please enter your passphrase");
ConsoleKeyInfo input = Console.ReadKey(true);
while (input.Key != ConsoleKey.Enter)
{
sPassphrase.AppendChar(input.KeyChar);
Console.Write('*');
input = Console.ReadKey(true);
}
sPassphrase.MakeReadOnly();
// Recover plaintext from a SecureString
// Marshal is in the System.Runtime.InteropServices namespace
try {
IntPtr ptrPassphrase = Marshal.SecureStringToBSTR(sPassphrase);
string uPassphrase = Marshal.PtrToStringUni(ptrPassphrase);
// ... use the string ...
}
catch {
// error handling
}
finally {
Marshal.ZeroFreeBSTR(ptrPassphrase);
}
If you are going to store credit card information you really need to be PCI compliant or you're just asking for trouble.
Having said that look at the cell level encryption available in SQL Server 2005 and above. Coincidentally :) I have recently given a presentation with T-SQL samples on encryption with SQL Server 2005/2008 available here: http://moss.bennettadelson.com/Lists/Events/Attachments/9/June2008.zip (Link location updated December 23, 2008)
Agreed that you should avoid storing the data if you can. But maybe you are that third party? If so, get familiar with PCI standards. Look around a bit on the site and you'll find the security measures you are required to implement.
It costs somewhere in the neighborhood of $30,000 to become properly compliant and to be able to do that kind of stuff. You are better off using a 3rd party payment service. Personally, I recommend Element Express, and they have a "Hosted" solution that bypasses the PCI-DSS PAPDB compliance. I've had to convert to this for my own applications, even a Point of Sale machine!!! It's a big pain, but we're a small company.
http://www.elementps.com/software-providers/our-security-edge/hosted-payments/PA-DSS-Certification-vs-Elements-Hosted-Payments/
The above link has some good information about the costs associated with becoming compliant. We have had customers ask us to store credit card numbers, and we won't do it because we could be fined as well. Not good. Don't open yourself up to liability.
Edit:
Additionally, if you DO decide to store the credit card information you definitely need to consider the forms of encryption you are going to use. Symmetric ? Asymmetric ?
If you do Symmetric encryption (Passkey) then you open yourself up to some serious security vulnerabilities if the server(site) that has the key (needed to encrypt) is compromised in any way. Remember, even compiled code won't hide a text key.
If you use Asymmetric encryption (public/private keypairs) then you run into some additional issues, but if the primary public facing server is compromised they will only have the public key, and if they also access your database.. they won't be able to decrpyt the contents.
The question then is, where do you store the private key ? Do you have someone paste it in from their local computers when running admin functions.. have a separate application that runs on the desktop to view orders, etc.
There are a lot of things to take into consideration.
Final note: Use a payment gateway (Element Express, Authorize.NET, Paypal, etc.) and don't store any credit card info locally. :P
Here is a link about using X509 Asymmetric Encryption in C#: http://www.csharpbydesign.com/2008/04/asymmetric-key-encryption-with.html
Lets look at the requirement a little differently. Currently it looks like this:
As a product owner for website X i want the system to temporarily store a customers cc details so that i can recover a sale that was declined by the CC company
Ppl tend to think like that and request features in that manner. Now i think your requirement is more conveniently described as follows:
As a user i want website X to be able to retry payment for my purchase so i dont have the hassle of having to go thru the checkout process again coz that is a real pain in the...
So there's no explicit requirement for storing anything (on your side) is there? Its only implied
Payment providers can provide programmatic APIs to your merchant account and the ability to attempt a re-auth on a declined attempt. i think #bashmohandes eluded to this earlier
Not all payment providers can do this however i think its dependent on their relationships with the banks involved. Thats the stuff you want to avoid ie. having a close relationship with banks.
Scenario 1: Assuming all i said is true
You don't have to store anything but a reference to the authorization attempt. Some payment providers even give you a sweet backoffice tool so you dont have to make your own to do re-auths. I think paygate does this
Your best bet i believe is to interview a number of payment providers. they should know this stuff like the back of their hands. This is potentially a zero-code solution
Scenario 2: Assuming i'm like totally wrong but legally this storing CC stuff is ok
So you have to store that data somewhere temporarily. I advise:
use a 2-way encryption method (naturally) that is non-vendor specific so you can use any language/platform to encrypt/decrypt
decouple the encrypt/decrypt service from your app and treat it like a black box
use public/private keys for authentication to this service
put this machine on a private network with its own elevated firewall rules (doesn't have to be a hardware firewall but hardware is better)
have your app servers communicate with this machine via ssl (you could get away with a self-signed cert since its on your private LAN)
All i've suggested in scenario 2 is hurdles but eventually persistence wins the race to get to your data. The only way to absolutely secure data is to unplug your server from the ether but that option is a little radical :-)
Scenario 1 would be nice. Wouldn't it?
Consider your t logs!
If you explain to your customer the full impact (and remedial requirements if they are found out of compliance) then trust me, your 'business requirements' will change very quickly.
If you must store the credit card number (and I advance the thought here that there is no reasonable scenario where you should) and you intend to use a native encryption built-in to your database, then consider this: what about your transaction logs?
If your transaction logs could reflect a credit card number in the clear, then you are out of compliance and should budget for a $10,000 to $50,000 forensic audit at your site if you get caught. Budget for your own attorney in case your customer sues you because you should have known all this stuff.
So if you are going to store a credit card number, run the cipher in code so the transaction logs (insert or update) reflect a ciphered string, not the card number in the clear.
And don't even have a field or column in your database for CVV - encrypted or not - that forensic audit will reveal this (so will the logs) and then your customer is in BIG, BIG trouble. They will pay a fine and could lose their ability to accept credit cards. Your attorney will be very happy.
I have a blog post that deals with this exact situation of storing sensitive data in the database. The blog post uses a String Encryptor class that I built using a Triple DES algorithm but you can plug in your own if you would like.
The blog post contains the video and source code that was used. You can check it out at http://www.wrightin.gs/2008/11/how-to-encryptdecrypt-sensitive-column-contents-in-nhibernateactive-record-video.html. I think it will definitely solve your issue.