Reputation: 425
How can we convert java string to key so that it can be used for below RC4 encryption algorithm? I have a password which I need to be used as key for encryption.
private static String rc4(String plaintext, int mode, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(mode, (java.security.Key) key);
return new String(cipher.doFinal(plaintext.getBytes()));
}
public static String encrypt(String plaintext, Key key) throws Exception {
return rc4(plaintext, Cipher.ENCRYPT_MODE, key);
}
Upvotes: 3
Views: 3024
Reputation: 417
import java.io.IOException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.codec.DecoderException;
import org.bouncycastle.util.encoders.Hex;
public class RC4Algo {
public static void main(String args[])throws IOException, NoSuchAlgorithmException, DecoderException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException
{
decryptRC4();
}
static String decryptRC4() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, InvalidAlgorithmParameterException{
byte[] plainBytes = "testString".getBytes();
String hashedKey = hashedData("thisismysecretkey");
//Generate a new key using KeyGenerator
/*KeyGenerator rc4KeyGenerator = KeyGenerator.getInstance("RC4");
SecretKey key = rc4KeyGenerator.generateKey();*/
Key key = new SecretKeySpec(Hex.decode(hashedKey), "RC4"); //String to key conversion using Hex.decode to convert to byte []
// Create Cipher instance and initialize it to encrytion mode
Cipher cipher = Cipher.getInstance("RC4"); // Transformation of the algorithm
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherBytes = cipher.doFinal(plainBytes);
String encoded = encodeBase64(cipherBytes);
String decoded = decodeBase64(encoded);
// Reinitialize the Cipher to decryption mode
cipher.init(Cipher.DECRYPT_MODE,key, cipher.getParameters());
byte[] plainBytesDecrypted = cipher.doFinal(Hex.decode(decoded));
System.out.println("Decrypted Data : "+new String(plainBytesDecrypted));
return new String(plainBytesDecrypted);
}
static String decodeBase64(String encodedData){
byte[] b = Base64.getDecoder().decode(encodedData);
String decodedData = DatatypeConverter.printHexBinary(b);
return decodedData;
}
static String encodeBase64(byte[] data){
byte[] b = Base64.getEncoder().encode(data);
String encodedData = new String(b);
/*String encodedData = DatatypeConverter.printHexBinary(b);*/
return encodedData;
}
static String hashedData(String key) throws NoSuchAlgorithmException{
String password = key;
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(password.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
//convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
}
Tip: Use Hex to binary and vice versa conversions to get rid of encoding issues.
Output:
So I first hash my key into Hex format and then using Hex.decode() of org.bouncycastle API to get bytes[], I achieve the String to Key conversion.
Hope this helps!
Upvotes: 3
Reputation: 2912
In order to convert a string representing a password (that is, a short string that a human can memorize) into a key for RC4 or other cipher, it is important for security to use a Key Derivation Function intended for key stretching, parameterized so that it is appropriately slow. It is also useful that salt is included as input to this KDF (For file or session encryption, a 16-byte random salt sent in clear at each use is fine. If that extra data is an issue, salt could e.g. be built from concatenation of the ID of the password owner, server name, and a constant server-unique value. Adding something random and secret in the salt can help; some call it pepper).
The reason NOT to use a truncated hash of the password, or any other fast and un-keyed method, is that it would makes the cryptosystem very vulnerable to brute-force password cracking, even using a standard PC. Password cracking and other brute-force key recovery seems to be a real industry, using countless kilowatts of power for CPUs and GPUs, and possibly a key (pun intended) market for such FPGA racks.
A recommendable but unfortunately not-so-standard KDF is scrypt; bcrypt would be my second choice; and PBKDF2 what I probably would end up using if in a hurry to rush the thing into production on a Java platform, assuming that SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256")
is available. Beware NOT to use without careful review some code returned by querying for this, especially if it uses an iteration count of 1000 (which sadly is common, the only value mentioned in the definition of PBKDF2, and utterly insufficient nowadays facing a competent attacker). Also, adapt the key size parameter for whatever the cipher allows (that should be 256 bytes for RC4).
As rightly pointed in comment, the character set of the input is an issue that should be dealt with carefully.
Upvotes: 1
Reputation: 5490
Who is going to decrypt this message?
If you are writing both sides, encryption and decryption, fgrieu has some excellent recommendations.
On the other hand, if you want to be interoperable with other implementations of RC4 encryption, you will have to convert the string to a key in a way compatible with the implementation on the other end.
To be compatible with the CipherSaber-2 implementation, "in CipherSaber the RC4 key array consists of the user's CipherSaber key followed by the 10 byte initialization vector (IV)." -- the CipherSaber FAQ
The CipherSaber key, in turn, is typically a Diceware passphrase that is 6 or 7 words long. (The Java implementations I've seen typically use passphrase.getBytes() or passphrase.charAt() in the process generating that RC4 key byte[] array from the IV and the ASCII text passphrase string. Java implementations of decrypting simply read the IV from the beginning of the encrypted message. Java implementations of encryption typically use the default SecureRandom() to generate the IV. ).
Other implementations that use RC4 do things differently -- there's no way for me to guess which implementation you are trying to be interoperable with. Hopefully that implementation is well-documented enough for you to figure out what you need to know.
Upvotes: 0