What is the best way to encrypt an URL with parameters in Java?
Can you be more specific? You can encrypt anything you want using an MD5 hash.
Are you sure you don't mean URL encode? Encoding is available through java.net.URLEncoder.encode.
java security api(http://java.sun.com/javase/technologies/security/) + url encoding
A HTTP service needs to be invoked from my application with certain parameters set in the URL. Those parameters are sensitive and needs to encrypted over the network. I am looking for a correct and simpler way of doing this in Java.
The only way to do this is to use SSL/TLS (https). If you use plain old HTTP, the URL will definitely be sent in the clear.
It depends on your threat model. For example, if you want to protect the parameters sent by your Java app to your server from an attacker who has access to the communication channel, you should consider communicating with the server via TLS/SSL (i.e., HTTPS in your case) and the likes. If you want to protect the parameters from an attacker who has access to the machine where your Java client app runs, then you're in deeper trouble.
If you really can't use SSL, I'd suggest a pre-shared key approach and adding a random iv.
You can use any decent symmetric encryption method ex. AES using a pre-shared key you're communicating out of band (email, phone etc.).
Then you generate a random initialization vector and encrypt your string with this iv and the key. Finally you concatenate your cipher text and the iv and send this as your parameter. The iv can be communicated in the clear without any risk.
Unfortunatelly almost noting is simple in java :-) , for this simple and usual task I wasnt able to find a prepared library, I ended up writing this (this was the source):
import java.net.URLDecoder;
import java.net.URLEncoder;
import javax.crypto.Cipher; import javax.crypto.SecretKey; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEParameterSpec;
/** * An easy to use class to encrypt and decrypt a string. Just call the simplest * constructor and the needed methods. * */
public class StringEncryptor {
private Cipher encryptCipher;
private Cipher decryptCipher;
private sun.misc.BASE64Encoder encoder = new sun.misc.BASE64Encoder();
private sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
final private String charset = "UTF-8";
final private String defaultEncryptionPassword = "PAOSIDUFHQWER98234QWE378AHASDF93HASDF9238HAJSDF923";
final private byte[] defaultSalt = {
(byte) 0xa3, (byte) 0x21, (byte) 0x24, (byte) 0x2c,
(byte) 0xf2, (byte) 0xd2, (byte) 0x3e, (byte) 0x19 };
/**
* The simplest constructor which will use a default password and salt to
* encode the string.
*
* @throws SecurityException
*/
public StringEncryptor() throws SecurityException {
setupEncryptor(defaultEncryptionPassword, defaultSalt);
}
/**
* Dynamic constructor to give own key and salt to it which going to be used
* to encrypt and then decrypt the given string.
*
* @param encryptionPassword
* @param salt
*/
public StringEncryptor(String encryptionPassword, byte[] salt) {
setupEncryptor(encryptionPassword, salt);
}
public void init(char[] pass, byte[] salt, int iterations) throws SecurityException {
try {
PBEParameterSpec ps = new javax.crypto.spec.PBEParameterSpec(salt, 20);
SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithMD5AndDES");
SecretKey k = kf.generateSecret(new javax.crypto.spec.PBEKeySpec(pass));
encryptCipher = Cipher.getInstance("PBEWithMD5AndDES/CBC/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, k, ps);
decryptCipher = Cipher.getInstance("PBEWithMD5AndDES/CBC/PKCS5Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, k, ps);
} catch (Exception e) {
throw new SecurityException("Could not initialize CryptoLibrary: " + e.getMessage());
}
}
/**
*
* method to decrypt a string.
*
* @param str
* Description of the Parameter
*
* @return String the encrypted string.
*
* @exception SecurityException
* Description of the Exception
*/
public synchronized String encrypt(String str) throws SecurityException {
try {
byte[] utf8 = str.getBytes(charset);
byte[] enc = encryptCipher.doFinal(utf8);
return URLEncoder.encode(encoder.encode(enc),charset);
}
catch (Exception e)
{
throw new SecurityException("Could not encrypt: " + e.getMessage());
}
}
/**
*
* method to encrypting a string.
*
* @param str
* Description of the Parameter
*
* @return String the encrypted string.
*
* @exception SecurityException
* Description of the Exception
*/
public synchronized String decrypt(String str) throws SecurityException {
try {
byte[] dec = decoder.decodeBuffer(URLDecoder.decode(str,charset));
byte[] utf8 = decryptCipher.doFinal(dec);
return new String(utf8, charset);
} catch (Exception e) {
throw new SecurityException("Could not decrypt: " + e.getMessage());
}
}
private void setupEncryptor(String defaultEncryptionPassword, byte[] salt) {
java.security.Security.addProvider(new com.sun.crypto.provider.SunJCE());
char[] pass = defaultEncryptionPassword.toCharArray();
int iterations = 3;
init(pass, salt, iterations);
}
}
The standard way to encrypt HTTP traffic is to use SSL. However, even over HTTPS, the URL and any parameters in it (i.e. a GET request) will be sent in the clear. You would need to use SSL and do a POST request to properly encrypt your data.