Sunday, May 24, 2009

Java Encryption

Update. DES is not secure. Use AES for symmetric encryption.

Most important: do not save keys and data in same location, otherwise don't bother encrypting at all. If the person has access to the key and the data obviously they can just unencrypt.

Consider key storage devises such as HSMs.

------

Ran into various issues implementing Java Encryption so just making some notes here for anyone else facing the same problems.

JCE (Java Cryptography Extension) Cipher Specifics
First of all, need to understand the encryption algorithm used and the specific requirements for using it in conjunction with the JCE (Java Cryptography Extension). For example if you're using DES algorithm to encrypt your data then JCE requires that you initialize the cipher using the IvParameterSpec class. The following post from sun Java forums was helpful in explaining some of this in conjunction with some information from various Java encryption books:

DES Java Encryption

- Cryptographics algorithms come in two flavors, asymmetric (public+private key) and symmetric (secret key).

[Note: Symmetric encryption requires that you keep your key secret because both encryption and decryption are done using the same key. Anyone who has your key can decrypt your data. Asymmetric encryption allows sending the public key to the person who wants to send you encrypted data and using a private key to decrypt the data. This latter form of encryption is useful when you want to allow web visitors, for instance, to encrypt and send you data, but you don't want anyone but yourself to be able to decrypt it - using your private or secret key]

- DES that is a symmetric algorithm.
- Symmetric algorithms come in two principal types, stream ciphers and block ciphers.
- Block ciphers encrypt data in blocks (usually 8-byte or 16-byte blocks).
- DES is a block cipher.
- Block ciphers are used in modes of operation, like ECB, CBC, OFB, etc.
- CBC requires a key and a Initialization Vector


[
Note:
Using JCE an initialization vector provided through IvParameterSpec object.

If you don't provide it you'll get the error: java.security.InvalidKeyException: Parameters missing

If you're using EBC mode it doesn't require an initialization vector and if you pass one in you may ge this error:

java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV

To fix the above error change: "DES/ECB/PKCS5Padding" to "DES/CBC/PKCS5Padding" if EBC is not a requirement. ECB is prone to replay attacks according to some sources.
]

- Initialization vectors are usually random numbers, transmitted in clear, but can be made fixed if your problem requires it.
- If you can have random initialization vectors, you can avoid replay attacks.
[i.e. someone cannot re-use your key unless they have the initialization vector]

Error: java.security.InvalidKeyException: Parameters missing

If using DES this is probably caused by not providing the initialization vector using the IvParameterSpec object.

To use the IvParameterSpec object you need to pass in a parameter which in this case is an array of 8 bytes. This is not a good example because it would be obvious to guess (1, 2, 3, 4... like password 12345) but explains the concept:

byte[] iv = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
IvParameterSpec ivSpec = new IvParameterSpec(iv);

//initialize the cipher using the IvParameterSpec
cipher.init(Cipher.DECRYPT_MODE, key, iv);

DES Key Size

I also found an example of some code which specifies the key size for DES which may prevent errors related to key being too short (not sure about this one but it worked):

String x = "DES/CBC/PKCS5Padding";
KeyGenerator gen = KeyGenerator.getInstance("DES");
gen.init(56); // 56 is the keysize. Fixed for DES
SecretKey key = gen.generateKey();

SecretKey

I did read somewhere that a secret key is problematic because it stores the key in a file somewhere. Will need to do more research on that later. There may be a better alternative than the SecretKey class.

SecureRandom

Initializing the keyGenerator with SecureRandom will help ensure randomness of keys. Some encryption mechanisms are weakened by the ability to guess or obtain keys using brute force because generation of keys uses a pattern that is easy to crack.

gen.init(new SecureRandom());

or for the example above:

gen.init(56, new SecureRandom());

Cross platform encoding of input data - UTF-8:

When getting the bytes of text you are trying to encode you'll want to ensure you're getting them in a format understood by all the systems using or displaying the data. UTF-8 is a good choice for web applications and email. Encode the text you want to encrypt like this:

String stringToEncrypt="encrypt this stuff";

instead of:
byte[] b = stringToEncrypt.getBytes();

use:
byte[] b = stringToEncrypt.getBytes("UTF-8");

javax.crypto.BadPaddingException: Given final block not properly padded

Some encryption algorithms have padding and others do not. The padding will tack on extra characters at the end of something that is encrypted to make it a fixed length. For instance:

test

may become

test===

The === are used to make test 8 characters long in the example above if that is the length I want according to the specification of the algorithm I'm using. The encryption algorithms will probably actually not have equal signs but nulls or some other means of creating a fixed length value.

You'll want to understand how padding is or is not used with your particular encryption algorithm and that padding is handled appropriately. Make sure you are using the correct algorithms, modes, etc. to encrypt and decrypt and that everything you're using matches up.

Additionally if you are transporting or persisting data you may need to encode it so it doesn't get altered in transit. Padding may be trimmed. Some modes of transport (passing data through HTTP via URLs) or persisting data to a database that doesn't understand all the characters in the encrypted bytes may cause characters to be lost or altered. Trying to put encryption data into a String without proper encoding won't work in most cases.

Base64 Encoding encrypted bytes before transported or stored will encode the encryption characters into characters that most systems understand. If you encode to Base64 for transport remember to decode again before you decrypt. Also note that encoding is not the same as encryption. If you encode your data using Base64 anyone can decode it using Base64.

To use Base64 you can download Apache Commons Codec from Apache.org

Import the package:

import org.apache.commons.codec.binary.*;

Code snippet:

Base64 b64 = new Base64();

byte[] a = "encrypt me".getBytes("UTF-8");
byte[] b = b64.encode(a);
encrypt(b) // call your encryption method

Before decrypting:

Byte[] c = b64.decode(b);
decrypt(c); // call your decryption method

Saving Keys to Database

Keys can be saved to a Java keystore which is basically a file. However you may also want to save your keys to a database if you have many keys and performance may be an issue or for other reasons. Remember if anyone gets a hold of your keys they can decrypt all your data so you'll want to think about how to do this securely. Using an encryption algorithm that also requires an initialization vector in addition to your key is helpful because the keys alone will not allow someone to decrypt the data. You may also limit use of keys for a short time period or use some other method to ensure keys are not reused in unintended ways.

If you want to save keys to a database then you can save your keys in VarBinary data type since that will store your byte data in the size it was passed in (no extra padding). Once you create a key you use the .getEncoded() method to get the encoded key bytes and save them to the database. Since the key is already encoded you shouldn't need to further encode it using Base64. Then you can retrieve it from the database using the getBytes("fieldname") Java sql method use it to decrypt your data.

Java Security by Scott Oaks has an example of implementation of a KeyStoreSpi class to use a database with a keystore for key management.

Friday, May 22, 2009

Special Characters to Block in Web Requests

Microsoft suggests weeding out these special characters in web requests:

< > " ' % ; ) ( & + -

Some people simply delete these characters, but a better approach is to encode them appropriately depending on what you are doing with them in your application.

Wednesday, May 13, 2009

XSS

Just reading up on XSS (cross site scripting) attacks on web sites.

I ran across XSS shell which was linked from a few newsgroup postings where users were blatantly asking questions about how to hijack a web site using basic authentication and steal passwords. Some information was posted by securiteam.com about XSS-Shell:

http://www.securiteam.com/tools/6X00120HFO.html

This site states:

You can steal basic authentication, you can bypass IP restrictions in administration panels, you can DDoS some systems with a permanent XSS vulnerability etc. Attack possibilities are limited with ideas. Basically this tool demonstrates that you can do more with XSS.

Nice.

I then linked over to XSS Proxy which explains that Cross Site Scripting does not actually require a user to click on a link to execute if they visit a hijacked or purposefully set up web site that includes XSS code. This page has a bunch of links to more information about XSS and information about XSS-Proxy.

http://xss-proxy.sourceforge.net/

HTML Form File Upload

This is a good tutorial that makes it pretty easy to create a file upload form when using a Jetty web server:

Jetty File Upload

Basically you can just copy and paste the code and have a working file upload page in minutes.

The caveat here (as is true with any code snippet that is easy to copy and paste off the web) is that you're going to want to wrap all this in some kind of security rather than open up your web server to uploading files from anywhere on the Internet.

Additionally you'll probably want to limit the directories that can be accessed and make the directories where the files are uploaded to be non-executable and probably read only after the file is created as well.

You will want to make this form available only over SSL to help prevent files from being altered in transit and make sure your web server only uses secure SSL algorithms. You may trust your customers that are uploading files but what about all the servers those files pass through en route to your web server?

Another option would be limiting access to file upload to people on your VPN and/or restrict to certain IP Addresses.

File uploads should also be checked for viruses and malware. Making them non-executable is a good first step, assuming someone cannot hack your server and escalate privileges in such a way they can give themselves rights to change that user account to allow execution of the files. Checking to see that the files are only limited file types such as .jpgs or .gifs is helpful, however search Google for "jpg malware" or "gif malware" and you'll find plenty of examples of jpgs and gifs that have been altered to create a malicious file that can take over a machine or cause other problems.

The user on the system that is responsible for performing the file upload should also have limited rights on the system.

Of course with any web form you'll want to prevent insertion of special characters that can be used for code injection, etc. All requests should be scrubbed for potentially dangerous content.

Another thing I noticed about this code is that they are simply suppressing certain errors and warnings and sending some exceptions back to the screen. A better approach would be to catch and log all errors - including the IP address and request information when the error occurs - so you can see if someone is trying to hack your server an upload malicious content.

Just a few suggestions and I'm sure there's more that can be done to secure this simple example form.

Tiny url back to this page: http://tinyurl.com/secureforms

More on File Upload Security

Saturday, May 09, 2009

Singletons, Multithreading and Class Loaders

This is a pretty good article talking about use of Singletons and the implications of multi-threaded programming, distributed technologies and different class loaders.

Singleton Java