http://qs1969.pair.com?node_id=233642

diotalevi has asked for the wisdom of the Perl Monks concerning the following question:

Is Crypt::CBC with the Crypt::Blowfish algorithm safe for encrypting many plain text values with a single key value? I'm encrypting e-mail addresses for this application but don't know whether I'm doing things correctly or not. I recall hearing that it isn't safe to use the same key for multiple plaintexts with Crypt::RC4. So I'm just checking first.

# $self is a CGI::Application object my $encrypted = encrypt_address( address => $address, key => $self -> param('encryption_key'), cipher => $self -> param('encryption_cipher') ); .... sub encrypt_address { my %arg = @_; require Crypt::CBC; Crypt::CBC -> new( { key => $arg{key}, cipher => $arg{cipher} } ) -> encrypt_hex( $arg{address} ); }

Seeking Green geeks in Minnesota

Replies are listed 'Best First'.
Re: Safe symmetric encryption - Crypt::CBC + Crypt::Blowfish?
by John M. Dlugosz (Monsignor) on Feb 08, 2003 at 07:19 UTC
    As far as Blowfish is concerned, each call to encrypt a block of 128 bits (if I recall the size correctly) 64 bits is a different plaintext on the same key. You call it as many times as needed for the length of your message. What's the difference between calling it once for a 2K message or twice for two different 1K messages?

    In terms of breaking the code mathematically, it's the total number of blocks that matters, not whether their logically one or n email notes. So, ongoing use like SSL/TLS will switch keys every so often. How many is too many? It's really only an issue with DES and variations because the block size is 64 bits.

    With AES and other modern 256-bit block ciphers, it's not an issue. For 128-bit blocks, I don't know what the size is but it's probably more than you have to worry about for modern applications.

    Update: With AES and other finalists, having 128-bit blocks means the size safety limit is more than a typical application needs to worry about. If that's not enough, many of those are defined with larger block sizes (up to 256 bit), rendering that kind of attack a total non-issue.

    There is a difference between 1 large vs. 2 small messages, for a different kind of attack. If you know that the messages begin with the same stuff (e.g. the TO: headers) you might be able to make use of that. You could, for example, tell that the first n blocks of the two emails were the same, indicating they might be to the same person. However, the use of an "initialization vector" (iv) will prevent this problem, and two 1K messages is no different than 1 2K message. So I say the only thing missing from your example is a different random iv. Note that if you use the last output block of one message as the iv for the next, the result of concatenating the two ciphertexts is literally NO DIFFERENT than concatenating the two plaintexts together and encoding as one CBC sweep. Take that as a proof of the principle stated above.

    Now RC4 is a stream cipher, as opposed to a block cipher. It's totally different. If you encode two messages using RC4 with the same key, then someone can XOR the two ciphertexts and the key cancells out! He's left with the same result as XORing the two plaintexts together, and untangling that is not nearly as hard as breaking the cipher.

    —John

    Update: was confusing block size values with key size values.

      I'd just like to add a few things to John's excellent post.

      An amplification: Changing keys regularly is always good cryptographic practice. It reduces the amount of data you lose from a single compromised key. It's only with some ciphers (like RC4) that changing the key becomes critical.

      In your mail application, you'll definitely want it to be possible to change keys without a major hassle. Maybe you'll want to use per-message session keys, each encrypted with a (changeable!) master key. Maybe using the same key for everything, and changing it once a month, is enough. Sorry we're all giving the same non-answer, but it depends on your requirements.

      Yes, random IV's are good. By default, Crypt::CBC uses them.

      A minor correction: AES uses 128-bit blocks, not 256-bit. Rijndael goes up to 256-bit blocks, but the AES specification doesn't include that. I can't think of any other cipher that uses such large blocks, and there's really not much reason for them. A birthday attack against a 64-bit block cipher (like DES or Blowfish) in a chaining mode is going to need around 30 gigabytes of encrypted data before you expect to see the same block twice. With 128-bit blocks, that goes up to 2**68 bytes, or sixty thousand years at gigabit ethernet speed.

Re: Safe symmetric encryption - Crypt::CBC + Crypt::Blowfish?
by Ryszard (Priest) on Feb 08, 2003 at 08:12 UTC
    It depends on your security requirements really.

    If you want some hardcore security i'd consider something like a public key system, or something like a revolving token (ala secure_id from RSA).

    If you want to protect your data from a casual browser, then a simple ROT13 scheme may be ok, but given the availability of cypher modules on CPAN and how easy they are to use, you've got a choice of a very wide range of very good cyphers. There is no point implementing a deliberately insecure "cypher" ala ROT13 IMO when all these others are available.

    So, back to the original question, how to manage your keys. Well I guess it depends on the level of complexity you wish to maintain.

    Key management in the most secure sense is difficult to get right, and some may say, it just cant be done. the difficulty comes with key distro, how can you ensure the key has not been intercepted? you cant, (unless you use the "in the research phase" quantum method (ie, the very act of viewing the key changes the stream making the indication the key has been previously viewed)).

    So, in a this case, you're data may not be that important, and so you may very well choose to use the same key for all crypts. Not very secure as once the key is compromised, then all your data is vulnerable.

    Take it a step up and use a public key system, and keep the private key "somewhere safe" public key systems are typically harder to brut force than a symetric key system (such as DES, 3DES, blowfish, twofish etc etc).

    One key for all? or different keys? if you choose a one key method, how are you going to manage the keys? a file? something offline? your biological memory? how automated does the solution need to be? It sounds to me like the solution may need full automation, and given the nature of the data (email addresses) it could be easier to use a single key.

    If you keep your keys in a secure location (ie appropriate permissions on a file, it probably doesnt really matter if you use may keys or a single key, if you're automating it, its not going to be too much extra effort to manage multiple keys.

    We havent even touched on other aspects of security, such as circumventing the cypher entirely by sniffing the network traffic, rubber hose cryptanalysis (probably not so appropriate in this situation), and other attack methods...

    So, bottom line, as always, is it depends. It doesnt make life easier, but you should know your rquirements completely depend on your individual sutation.

Re: Safe symmetric encryption - Crypt::CBC + Crypt::Blowfish?
by belg4mit (Prior) on Feb 08, 2003 at 04:50 UTC
    My understanding of crypto is, regardless of the algorythm you NEVER USE THE SAME KEY TWICE. Public key systems get around this though. You aren't.

    --
    I'm not belgian but I play one on TV.

      never use the same key twice for a one-time pad. other symmetric algorithms are designed to allow you to reuse keys (with some eventual loss of security; see the other posts below this for more). public key systems just get around key distribution problems.

      anders pearson

        A Block cipher in CBC mode allows you to reuse the key. A Stream cipher is no different than a one-time pad in this respect. RC4 is a stream cipher. Think of a stream cipher as a condensed instruction on how to generate the one-time pad. The key is just a seed for a pseudo-random number generator.

**Another 2 questions: Encrypting forms and credit card numbers
by mattr (Curate) on Feb 09, 2003 at 11:07 UTC
    Hi, I'd like to add two questions of my own as I need to do two encryptions in an app I am building (asap) now.

    The needs are encrypting forms and encrypting some credit card numbers.

    1. Encrypted Forms. This is mainly to obfuscate so that a casual cafe user can't read user data, as SSL is used if delicate info is needed.

    I have a module I built for myself, Quickcrypt.pm which I've used in a couple of recent projects to encrypt multipage form data. Part of it I made after looking at the EncryptForm module on CPAN. I freeze a hash, websafe pack it, encrypt with CBC (Blowfish) and drop it into a hidden input field on the next HTML::Template generated page.

    As I understand the thread, it would be totally unsafe to use RC4, in particular that would allow someone to detect the server's password and potentially use that later to get other people's session info. Whereas Blowfish would be okay, or better yet AES. Presumably changing server password every few months also not needed with Blowfish/AES keyspace sizes. Is this correct? Some machines only RC4 worked.

    2. "A few Credit Cards". Highest priority question for me. I have a seminar signup system which will accept credit cards for the overseas users. In the future if everyone was allowed to do so I could have hundreds of credit cards per seminar.

    The idea is that user data will be stored in a CSV text file but the credit card number will be encrypted. Site management staff can download all or part of the CSV and have it open in Excel, with the credit card numbers still encrypted. Or, they can first type in a password, which will then cause the credit card number column in the spreadsheet to be completely decrypted and you can view the plaintext of the spreadsheet including cc#'s in Excel just fine.

    This would seem to require a public key system. Which module would be best? Consider this system must run on an old perl on a cheap provider, I can compile modules though would rather not have to build openssl if not crucial. While I only expect under 20 cc#s this time, in the future I might want to have thousands. I wonder if the pure perl modules I see on CPAN here would be fast enough to decrypt them before browser timeout.

    So right now I would like to find the easiest to install/use package to solve this answer and do more later if I need faster. I've used perl/openssl for live credit card authorization in the past, it's a bit much for now. I'm thinking about Crypt::OpenPGP. Thanks for your help.

      On the general question I asked — theorbtwo had a wonderful suggestion that lets me completely avoid having to deal with encryption at all. If I had to use encrypted data then I wouldn't be able to cycle through keys at will since other people would be holding the encrypted data. The best comprimise might be to use new keys for new data and switch as the opportunity arised.

      If you're curious, theorbtwo suggested that I store all the data myself and only pass out tokens which reference the stored data. To do this, I'd store a key, an incrementing counter and then publish counter values and the Digest::SHA1 value of counter+secret. This also lets me change the key at will since all I have to do is store the expected counter and hash. Since random data is precious I have no idea how often I'd get a new secret but its also overkill for this application.


      Now, mattr. This whole credit card deal is a tricky business. My first suggestion to you is to subscribe to the secprog list on securityfocus.com. You are about to step right from the deep-end of the swimming pool into the Atlantic ocean. You are going to need to be well armed when you go back to your client and change the requirements (what you've described so far requires an unsecure configuration). Read the archive and especially read the entire thread named "PGP Scripting". It sounds like that person's problem somewhat parallels yours.

      Now here's my inexpert analysis (but augmented by what I've learned from being on that list). You cannot allow the server to decrypt the data. Ever. The key ideas to follow here are obfuscation and barriers. You're installing a level of obfuscation by doing things that might make the job technically more difficult but will not stop a determined attacker (oh yes, you must also write up an attack summary). This includes any use of encryption on the server where an attacker can decrypt your data.

      The other level: a barrier is where you need to get to. The difficulty is that this is difficult. In general, your best bet is to use some form of encryption on the unsecure server, send the data elsewhere and on unrelated networks, only then can you decrypt the data and it never goes back to the front-facing server. This of course, implies that your application can never deliver plaintext card data. Your user cannot enter a password to get the data. That's just bad design. What you might do is restrict access to the encrypted data and then have your user do the decryption.

      I think your question is too important and too hairy to be addressed by me in a response thread to an unrelated question. Ask in a new SoPW question and ask on the secprog list. I'm suggesting both because while the secprog list will probably furnish better answers the perl folk here will benefit by whatever gems are mentioned in responses but since secprog is chock full of people whose job it is to think of these problems, it'll have superior answers, generally.


      Seeking Green geeks in Minnesota

        Thank you very much for your detailed response. I understand what you are saying and of course I could provide a perl app to run on the adminitrator's local machine which would decrypt a downloaded csv file.

        I do require ssl and a login to get to the management page, though hearing your opinion I would be inclined to be doubly sure I am not storing password as plaintext. Also I have a different login/password for the staff and for the manager(s) at the company who actually need to see the credit card numbers. Question of whether that is enough or not. Considering it's just a junky virtual host account somewhere I guess the admin can do many bad things to it, but I think getting the cc numbers would require that either he can listen in on the script's decrypting process (possible if he changes my code) or crack the ssl session (I don't think so but hey it's his openssl).

        My insights so far: I need to ask a SOPW and immediately plan on providing a perl utility (hopefully perlcc since installing perl might be a hassle) then try some perl gui-ness.. can you spell ballooning?

        Oh the insights from that thread, right.. it is not tamperproof hardware, memory is not safe especially since I'm not root. Also I don't have time to look at strings /dev/kmem or looking at /proc/*/kmem or ptrace which I guess maybe someone could do if they're really quick while script is executing for a few seconds a day. Realistically this is really not a problem for my current app but what if I used the same system for something bigger in the future.. Okay I'm only half way through and it is a long thread. I think the question to ask (think I know the answer already though) is how safe is perl when decrypting from remote machine over ssl? If I get more insights from rest of thread will update here. Thanks.

        This post I'm not familiar with the systems he mentions. Sounds like something a bit magical which is definitely not going to be available on a cheap provider anyway.