Hybrid RSA-AES encryption - java

i try to create hybrid encryption using RSA-AES but for now i face a problem in this coding. From this code i try to Creating an RSA key pair , private and public key. After that i should Generating a random key symmetrical algorithm AES then i have to create an AES cipher in order to encrypt a text string with the AES key. Then after the text is encrypted with the AES key, then the AES key needs to be encrypted with the RSA public key and the encrypted AES key needs to be decrypted with the RSA private key. And finally decrypt the text message entered with AES key in order to read the message. I think i missing something in my coding. Please help me guys.
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class HybridAesRsa
{
private Cipher cipher;
// RSA keys will be generated when the client and server connect
private PrivateKey myPrivateKey;
private byte[] myPublicKey;
private byte[] interlocutorPublicKey = null;
// Strings are encoded / decoded in BASE64
private BASE64Decoder b64decoder = new BASE64Decoder();
private BASE64Encoder b64encoder = new BASE64Encoder();
public HybridAesRsa()
{
try
{
cipher = Cipher.getInstance("RSA");
Security.addProvider(new BouncyCastleProvider());
}
catch (Exception ex){
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE,null,ex);
}
}
// Generate the pair of public and private keys using 1024 bytes
public KeyPair generateKey() throws Exception
{
KeyPair keyPair = null;
try{
//generate RSA key pair
KeyPairGenerator rsaKeyGen = KeyPairGenerator.getInstance("RSA");
rsaKeyGen.initialize(1024);
keyPair = rsaKeyGen.generateKeyPair();
//RSA public and private key
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
//System.out.println("RSA public key 1 ---> "+publicKey);
//System.out.println("RSA private key 1 ---> " +privateKey);
//for Chatting
myPublicKey = publicKey.getEncoded();
setMyPrivateKey(privateKey);
//Generating a random key symmetrical algorithm AES
KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES");
SecureRandom random = new SecureRandom();
aesKeyGenerator.init(random);
SecretKey aesSecretKey = aesKeyGenerator.generateKey();
/*//The key is presented in a byte array
byte[] symmetricKey = aesSecretKey.getEncoded();
//Printing out the generated key
System.out.println("\nAES symmetric key --> " + symmetricKey); */
} catch (NoSuchAlgorithmException ex) {
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE,null,ex);
}
return keyPair;
}
// Encrypts text using public key
public String encrypt(String text, PublicKey publicKey, SecretKey aesSecretKey ) throws Exception
{
//Creating an AES cipher in order to encrypt a text string with the AES key
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
//Now that the text is encrypted with the AES key, then the AES key needs to be encrypted with the RSA public key
Cipher rsaCipher = Cipher.getInstance("RSA");
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedAESkey = rsaCipher.doFinal(aesSecretKey.getEncoded());
//Printing out the encrypted AES key
System.out.println("\nAES key encrypted with RSA --> " + encryptedAESkey);
return text;
}
// Use the public key to encrypt the interlocutor
public String encrypt(String text) throws Exception
{
return encrypt(text, bytesToPublicKey(interlocutorPublicKey), null);
}
// Decrypts text using private key
public String decrypt(String text, PrivateKey privatekey) throws Exception
{
// Now the encrypted AES key needs to be decrypted with the RSA private key
Cipher rsaCipher2 = Cipher.getInstance("RSA");
rsaCipher2.init(Cipher.DECRYPT_MODE, privatekey);
byte[] encryptedAESkey = null;
byte[] decryptedAESkey = rsaCipher2.doFinal(encryptedAESkey);
//Print out the decrypted AES key
System.out.println("AES key decrypted with RSA private key --> " + decryptedAESkey);
//And finally decrypt the text message entered with AES key in order to read the message.
Cipher aesCipher2 = Cipher.getInstance("AES");
Key aesSecretKey = null;
aesCipher2.init(Cipher.DECRYPT_MODE,aesSecretKey);
byte[] encrypt = null;
byte [] decrypt = aesCipher2.doFinal(encrypt);
return text;
}
// Use my private key to decrypt
public String decrypt(String text) throws Exception
{
return decrypt(text, myPrivateKey);
}
// Public Key the caller is sent in byte [ ] and converted into a PublicKey object
public static PublicKey bytesToPublicKey(byte[] publicKeybytes)
{
PublicKey publicKey = null;
try {
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeybytes);
publicKey = keyFactory.generatePublic(publicKeySpec);
}
catch (InvalidKeySpecException ex) {
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE, null, ex);
}
catch (NoSuchAlgorithmException ex){
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE, null, ex);
}
return publicKey;
}
// Test
public static void main(String[] args){
try {
HybridAesRsa crypto = new HybridAesRsa();
KeyPair keyPair = crypto.generateKey();
PublicKey publicKey = keyPair.getPublic();
PrivateKey privateKey = keyPair.getPrivate();
KeyGenerator aesKeyGenerator = KeyGenerator.getInstance("AES");
SecretKey aesSecretKey = aesKeyGenerator.generateKey();
byte[] publicKeyBytes = publicKey.getEncoded();
byte[] privateKeyBytes = privateKey.getEncoded();
byte[] symmetricKey = aesSecretKey.getEncoded();
System.out.println("RSA Public key: " + new BigInteger(publicKeyBytes));
System.out.println("RSA Private key: " + new BigInteger(privateKeyBytes));
System.out.println("AES symmetric key --> " + new BigInteger(symmetricKey));
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.ENCRYPT_MODE, aesSecretKey);
String testeMsg = "As a seed knows how to make a flower ? I love you.";
byte[] encrypt = aesCipher.doFinal(testeMsg.getBytes());
Cipher rsaCipher = Cipher.getInstance("RSA");
rsaCipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedAESkey = rsaCipher.doFinal(aesSecretKey.getEncoded());
String encrypted = crypto.encrypt(testeMsg, bytesToPublicKey(publicKeyBytes), aesSecretKey);
System.out.println("Encrypted Text: " + encrypted);
String decrypted = crypto.decrypt(encrypted, keyPair.getPrivate());
System.out.println("Decrypted Text: " + decrypted);
}
catch (Exception ex)
{
Logger.getLogger(HybridAesRsa.class.getName()).log(Level.SEVERE, null, ex);
}
}
public byte[] getMyPublicKey(){
return myPublicKey;
}
public void setMyPublicKey(byte[] myPublicKey) {
this.myPublicKey = myPublicKey;
}
public PrivateKey getMyPrivateKey(){
return myPrivateKey;
}
public byte[] getInterlocutorPublicKey(){
return interlocutorPublicKey;
}
public boolean hasInterlocutorPublicKey(){
return interlocutorPublicKey!=null;
}
public void setInterlocutorPublicKey(byte[] interlocutorPublicKey){
this.interlocutorPublicKey = interlocutorPublicKey;
}
public void setMyPrivateKey(PrivateKey aMyPrivateKey){
myPrivateKey = aMyPrivateKey;
}
}
Here the error for this code
Jun 19, 2016 5:50:14 PM HybridAesRsa main
SEVERE: null
java.lang.IllegalArgumentException: Null input buffer
at javax.crypto.Cipher.doFinal(Cipher.java:2117)
at HybridAesRsa.decrypt(HybridAesRsa.java:125)
at HybridAesRsa.main(HybridAesRsa.java:204)

You have this code:
byte[] encrypt = null;
byte [] decrypt = aesCipher2.doFinal(encrypt);
where you try to encrypt with a buffer that's initialised to null .. that is not possible.
The exception is quite clear:
java.lang.IllegalArgumentException: Null input buffer

Related

I am getting BadPaddingException while decrypting an 128 bit AES key which has been encoded by using RSA generated public key(.jks)

package demo123;
import java.io.File;
import java.io.FileInputStream;
import java.nio.file.Files;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
// Java 8 example for RSA-AES encryption/decryption.
public class AESwithRSA {
public static void main(String[] args) throws Exception {
String plainText = "{\"scope\":\"payments\",\"x-mig-bank\": \"ICICI\",\"x-mig-channel\": \"RC\",\"tpp_redirect_uri\": \"www.tpp-app.com?query=123\",\"x-tpp-client-id\": \"Ck234567890112\",\"tpp-app-name\": \"amazon\",\"Consent Id\": \"d25a6f26-3ad5-4dd8-96fd-2582abfa3f58\",\"Type\": \"Domestic Payment\" }";
// Generate public and private keys using RSA
Key privateKey = getPrivate("KeyPair/privateKey.jks");
System.out.println("Private key success");
System.out.println("Private key :" + privateKey);
Key publicKey = getPublic("KeyPair/publicKey.");
System.out.println("Public key success");
System.out.println("Public key :" + publicKey);
// First create an AES Key
String secretAESKeyString = getSecretAESKeyAsString();
System.out.println("Secret Key "+secretAESKeyString);
// Encrypt our data with AES key
String encryptedText = encryptTextUsingAES(plainText, secretAESKeyString);
System.out.println("Encrypted text "+encryptedText);
// Encrypt AES Key with RSA Private Key
byte[] encryptedAESKeyString = encryptAESKey(secretAESKeyString, publicKey);
System.out.println("Encrypted AES key with RSA "+encryptedAESKeyString);
// First decrypt the AES Key with RSA Public key
String decryptedAESKeyString = decryptAESKey(encryptedAESKeyString, privateKey);
System.out.println("Decrypted AES key with RSA "+decryptedAESKeyString);
// Now decrypt data using the decrypted AES key!
String decryptedText = decryptTextUsingAES(encryptedText, decryptedAESKeyString);
//Showing all the outputs
System.out.println("input: " + encryptedText);
System.out.println("AES Key: " + secretAESKeyString);
System.out.println("decrypted: " + decryptedText);
System.out.println("Text New:" + textNew);
System.out.println("Encrypted New:" + encryptedTextNew);
//System.out.println("Decrypted New:" + decryptedTextNew);
}
// Create a new AES key. Uses 128 bit (weak)
public static String getSecretAESKeyAsString() throws Exception {
KeyGenerator generator = KeyGenerator.getInstance("AES");
generator.init(128); // The AES key size in number of bits
SecretKey secKey = generator.generateKey();
String encodedKey = Base64.getEncoder().encodeToString(secKey.getEncoded());
return encodedKey;
}
// Encrypt text using AES key
public static String encryptTextUsingAES(String plainText, String aesKeyString) throws Exception {
byte[] decodedKey = Base64.getDecoder().decode(aesKeyString);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
// AES defaults to AES/ECB/PKCS5Padding in Java 7
Cipher aesCipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
aesCipher.init(Cipher.ENCRYPT_MODE, originalKey);
byte[] byteCipherText = aesCipher.doFinal(plainText.getBytes());
return Base64.getEncoder().encodeToString(byteCipherText);
}
// Decrypt text using AES key
public static String decryptTextUsingAES(String encryptedText, String aesKeyString) throws Exception {
byte[] decodedKey = Base64.getDecoder().decode(aesKeyString);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES");
// AES defaults to AES/ECB/PKCS5Padding in Java 7
Cipher aesCipher = Cipher.getInstance("AES");
aesCipher.init(Cipher.DECRYPT_MODE, originalKey);
byte[] bytePlainText = aesCipher.doFinal(Base64.getDecoder().decode(encryptedText));
return new String(bytePlainText);
}
// Encrypt AES Key using RSA private key
private static byte[] encryptAESKey(String plainAESKey, Key publicKey ) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return Base64.getEncoder().encode(cipher.doFinal(plainAESKey.getBytes()));
}
// Decrypt AES Key using RSA public key
private static String decryptAESKey(byte[] encryptedAESKey, Key privateKey) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return new String(cipher.doFinal(Base64.getDecoder().decode(encryptedAESKey)));
}
//Getting public and private .jks format key
public static Key getPrivate(String filename) throws Exception {
String password = "123456";
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(is, password.toCharArray());
String alias = "rib_pub_priv_ob";
Key key = keystore.getKey(alias, password.toCharArray());
return key;
}
// https://docs.oracle.com/javase/8/docs/api/java/security/spec/X509EncodedKeySpec.html
public static Key getPublic(String filename) throws Exception {
String password = "123456";
FileInputStream is = new FileInputStream(filename);
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(is, password.toCharArray());
String alias = "tmsx_pub_priv_ob";
Key key = keystore.getKey(alias, password.toCharArray());
return key;
}
}
//Following is the output
Private key success
Private key :sun.security.rsa.RSAPrivateCrtKeyImpl#ffd2dcac
Public key success
Public key :sun.security.rsa.RSAPrivateCrtKeyImpl#fff19d78
Secret Key XsZue3ATt4OAQFP5C4sa8Q==
Encrypted text mjynBmIDhsj9L3jhFmzb4CFaJr+i5k2B1luuTdg0ls3NoAvI3wLfeU54Sxo7IDBrqH3i3F3RNM4DDPhWdbtEMNQ+27EcQOugidB2BcTFigzIImNohZOVjBi+qrPC7KWGLf9JWlJHUsoUz+oKiuAJGjitrrIMg/qQN7He87hH6hxfNZ7vceZV2N6HihYsQ4R1S6YFRUDVBwuG+IjvEyzihkw4mmlmjq4FIspXmaYuxYE/6urevUD/dY7HSLVrVRst83VRKnqDrzf32RolGsM12Ebyk0XJGGOYHV/OWfYExkaQdfUaEVMhU3h/tTmSoVJHEHTf1YdMxv5x/HZd2aXoYw==
Encrypted AES key with RSA [B#5f150435
Exception in thread "main" javax.crypto.BadPaddingException: Decryption error
at sun.security.rsa.RSAPadding.unpadV15(RSAPadding.java:380)
at sun.security.rsa.RSAPadding.unpad(RSAPadding.java:291)
at com.sun.crypto.provider.RSACipher.doFinal(RSACipher.java:363)
at com.sun.crypto.provider.RSACipher.engineDoFinal(RSACipher.java:389)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at demo123.AESwithRSA.decryptAESKey(AESwithRSA.java:135)
at demo123.AESwithRSA.main(AESwithRSA.java:60)
The error is caused by loading in getPublic the private key instead of the public key. This can be easily seen in the output: For both keys, objects of the type sun.security.rsa.RSAPrivateCrtKeyImpl are displayed, whereas the public key should actually be of the type sun.security.rsa.RSAPublicKeyImpl. To load the public key in getPublic replace the line
Key key = keystore.getKey(alias, password.toCharArray());
by
Key key = keystore.getCertificate(alias).getPublicKey();
See also [1][2]. With this fix the code works on my machine.
Update: In the current code, the Base64-encoded AES key (from getSecretAESKey) is encrypted with RSA and this key is then again Base64-encoded (in encryptAESKey). Such a double Base64-encoding is actually not necessary, as it would be sufficient to encrypt the raw AES key with RSA, as each Base64-encoding has a 33% overhead.

How can I have the java ciper algorithm and ruby cipher algorithm in sync?

I have this code in my rails app:
require 'openssl'
require 'digest/sha1'
require 'base64'
KEY="secret_key"
data = "secret message"
def encrypt_value(data)
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.encrypt
cipher.key = Digest::SHA256.digest(KEY)
encrypted = cipher.update(data)+cipher.final
return encrypted
end
def decrypt_value1(data)
cipher = OpenSSL::Cipher::Cipher.new("aes-256-cbc")
cipher.decrypt
cipher.key = Digest::SHA256.digest(KEY)
decrypted = cipher.update(data)+cipher.final
data = Base64.decode64(decrypted)
return data
end
And java code:
import java.security.AlgorithmParameters;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;
public class EncryptionDecryption {
private static String salt;
private static int iterations = 65536 ;
private static int keySize = 256;
private static byte[] ivBytes;
// private static SecretKey secretKey;
private static final byte[] secretKey = "secret_key".getBytes();
public static void main(String []args) throws Exception {
salt = getSalt();
char[] message = "secret message".toCharArray();
System.out.println("Message: " + String.valueOf(message));
System.out.println("Encrypted: " + encrypt(message));
System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray()));
}
public static String encrypt(char[] plaintext) throws Exception {
byte[] saltBytes = salt.getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize);
//secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretSpec);
AlgorithmParameters params = cipher.getParameters();
ivBytes = params.getParameterSpec(IvParameterSpec.class).getIV();
byte[] encryptedTextBytes = cipher.doFinal(String.valueOf(plaintext).getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(encryptedTextBytes);
}
public static String decrypt(char[] encryptedText) throws Exception {
System.out.println(encryptedText);
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(new String(encryptedText));
SecretKeySpec secretSpec = new SecretKeySpec(secretKey, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretSpec, new IvParameterSpec(ivBytes));
byte[] decryptedTextBytes = null;
try {
decryptedTextBytes = cipher.doFinal(encryptedTextBytes);
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
return new String(decryptedTextBytes);
}
public static String getSalt() throws Exception {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
sr.nextBytes(salt);
return new String(salt);
}
}
How can I have both of them work with each other, for example if I send an encrypted data to java app from rails app it should be able to decode it and vice-versa.
As far as you are using the same cypher algorithms and message padding characters, they should work just fine.
Also, it is better to use some key exchange protocol, like Diffie-Hellman. Both Ruby's OpenSSL wrapper and Java's Crypto lib support it. It is a safer way to generate per session keys.
PS. Your code as you have it, seems to be written for a standalone execution. For example, your Java code for decoding assumes that your string was encoded with the same instance's encode method. Because, your decode method is using IV that was initialized in encode method (ivBytes).

Encryption using AES

I am encrypting the string using AES but it is not decrypting "1234567812345678" character back to plain text from encrypted string. For other text (like "Hello World") it is working fine. Also want to keep the encrypted code to accept only UTF-8 characters. I am using below code
import java.security.*;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class StrongAES
{
public static void main(String[] args)
{
//listing all available cryptographic algorithms
/* for (Provider provider: Security.getProviders()) {
System.out.println(provider.getName());
for (String key: provider.stringPropertyNames())
System.out.println("\t" + key + "\t" + provider.getProperty(key));
}*/
StrongAES saes = new StrongAES();
String encrypt = saes.encrypt(new String("Bar12346Bar12346"),new String("1234567812345678"));
//String encrypt = saes.encrypt(new String("Bar12346Bar12346"),new String("Hello world"));
System.out.println(encrypt);
String decrypt = saes.decrypt(new String("Bar12346Bar12346"), new String(encrypt));
System.out.println(decrypt);
}
String encrypt(String key, String text)
{
String encryptedText="";
try{
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(text.getBytes());
encryptedText = new String(encrypted);
// System.out.println(encryptedText);
}
catch(Exception e)
{
e.printStackTrace();
}
return encryptedText;
}
String decrypt(String key, String encryptedText)
{
String decryptedText="";
try{
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
decryptedText = new String(cipher.doFinal(encryptedText.getBytes()));
// System.out.println("Decrypted "+decryptedText);
}
catch(Exception e)
{
e.printStackTrace();
}
return decryptedText;
}
}
You must keep bytes, not converting to String.
explanations in this post:
Problems converting byte array to string and back to byte array
If you want a keep a String, think of convert to B64
String my_string=DatatypeConverter.printBase64Binary(byte_array);
and
byte [] byteArray=DatatypeConverter.parseBase64Binary(my_string);
you can also convert to Hexa (it's bigger)
I have chenged my code to below. Used BASE64Encoder to convert incrypted byte to string same converted with BASE64Decoder while decrypting. And UTF-8 for each getByte.
import java.security.*;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class StrongAES
{
public static void main(String[] args)
{
StrongAES saes = new StrongAES();
String encrypt = saes.encrypt(new String("Bar12346Bar12346"),new String("1234567812345678"));
System.out.println(encrypt);
String decrypt = saes.decrypt(new String("Bar12346Bar12346"), new String(encrypt));
System.out.println(decrypt);
}
String encrypt(String key, String text)
{
String encryptedText="";
try{
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes("utf-8"), "AES");
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(text.getBytes("utf-8"));
BASE64Encoder encoder = new BASE64Encoder();
encryptedText = encoder.encodeBuffer(encrypted);
}
catch(Exception e)
{
e.printStackTrace();
}
return encryptedText;
}
String decrypt(String key, String encryptedText)
{
String decryptedText="";
try{
// Create key and cipher
Key aesKey = new SecretKeySpec(key.getBytes("utf-8"), "AES");
Cipher cipher = Cipher.getInstance("AES");
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
BASE64Decoder decoder = new BASE64Decoder();
decryptedText = new String(cipher.doFinal(decoder.decodeBuffer(encryptedText)));
}
catch(Exception e)
{
e.printStackTrace();
}
return decryptedText;
}
}

How to implement password based hybrid encryption in java?

I'm currently working on an Android project for developing a Hybrid File Encryption. From this site, I've already created a hybrid encryption which only able to encrypt text/string. While all the keys are automatically generated within the code. Any idea on how to make the keys to be user input password based and able to encrypt files?
Here is the code:
// Some codes here
// Create key pair (public and private key) for RSA encryption and decryption
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
kp = kpg.genKeyPair();
publicKey = kp.getPublic();
privateKey = kp.getPrivate();
} catch (Exception e) {
Log.e(TAG, "RSA key pair error");
}
}
private void encHybrid() throws GeneralSecurityException {
// Create random secret key with AES algorithm
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128, sr) ;
SecretKey cipherKey = kg.generateKey() ;
// Encrypt secret key asymmetry algorithm (RSA)
encryptedSecretKey = encrypt(cipherKey.getEncoded(), kp.getPublic());
textHybrid = etHybrid.getText().toString();
// Encrypt inputted text/string with symmetry algorithm using encrypted secret key
encryptedData = encrypt(textHybrid.getBytes(), cipherKey);
}
// Method to encrypt the text/string
public static byte[] encrypt(byte[] toEncrypt, SecretKey key)
throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("AES") ;
cipher.init(Cipher.ENCRYPT_MODE, key) ;
return cipher.doFinal(toEncrypt);
}
// Method to encrypt the secret key
public static byte[] encrypt(byte[] toEncrypt, PublicKey key)
throws GeneralSecurityException {
Cipher cipher = Cipher.getInstance("RSA") ;
cipher.init(Cipher.ENCRYPT_MODE, key) ;
return cipher.doFinal(toEncrypt);
}
private void decryptHybrid() throws GeneralSecurityException {
// Decrypt secret key with private key
byte[] decryptedSecretKey = decrypt(encryptedSecretKey, kp.getPrivate()) ;
// Decrypted secret key will be stored in sKey
SecretKey sKey = new SecretKeySpec(decryptedSecretKey, "AES") ;
textHybrid = etHybrid.getText().toString();
// Decrypt encrypted text/string with decrypted secret key
byte[] decryptedData = decrypt(encryptedData, sKey) ;
}
// Method to decrypt the text/string
public static byte[] decrypt(byte[] toDecrypt, SecretKey key)
throws GeneralSecurityException {
Cipher deCipher = Cipher.getInstance("AES") ;
deCipher.init(Cipher.DECRYPT_MODE, key) ;
return deCipher.doFinal(toDecrypt);
}
// Method to decrypt the secret key
public static byte[] decrypt(byte[] toDecrypt, PrivateKey key)
throws GeneralSecurityException {
Cipher deCipher = Cipher.getInstance("RSA") ;
deCipher.init(Cipher.DECRYPT_MODE, key) ;
return deCipher.doFinal(toDecrypt);
}
You don't really want to generate the key pair from the password. The problem with that scheme is that there is no way to trust the public key. What is usually done is to encrypt the private key with a secret (symmetric) key that has been generated from a password.
So, in addition to the hybrid encryption you would have a scheme that does it entirely the other way around. It's a bit of code, but it should be readable enough. Or you could use PGP, which essentially performs the same kind of operations.
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class PassphraseWrapRSA {
private static KeyPair generateRSAKeyPair(final int size) {
KeyPairGenerator kpgen;
try {
kpgen = KeyPairGenerator.getInstance("RSA");
} catch (final NoSuchAlgorithmException e) {
throw new IllegalStateException();
}
kpgen.initialize(size);
return kpgen.generateKeyPair();
}
public static byte[] generateSalt() {
final SecureRandom rng = new SecureRandom();
final byte[] salt = new byte[16];
rng.nextBytes(salt);
return salt;
}
private static SecretKey deriveAESKey(final byte[] salt,
final char[] password) {
try {
final SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
final KeySpec spec = new PBEKeySpec(password, salt, 65536, 256);
final SecretKey keyWrapKey = factory.generateSecret(spec);
final SecretKey secret = new SecretKeySpec(keyWrapKey.getEncoded(),
"AES");
return secret;
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
private static byte[] encryptRSAPrivateKey(final RSAPrivateKey rsaPrivateKey,
final SecretKey aesKey) {
try {
final Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
final SecureRandom ivGen = new SecureRandom();
final byte[] iv = new byte[c.getBlockSize()];
ivGen.nextBytes(iv);
c.init(Cipher.WRAP_MODE, aesKey, new IvParameterSpec(iv));
final byte[] wrappedKey = c.wrap(rsaPrivateKey);
return concat(iv, wrappedKey);
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(e);
}
}
public static byte[] wrapRSAPrivateKey(final String passphrase,
final RSAPrivateKey rsaPrivateKey) {
// --- generate salt
final byte[] newSalt = generateSalt();
// --- derive symmetric key from salt and password
final SecretKey aesKey = deriveAESKey(newSalt,
passphrase.toCharArray());
final byte[] encryptedPrivate = encryptRSAPrivateKey(rsaPrivateKey, aesKey);
final byte[] saltedAndEncryptedPrivate = concat(newSalt,
encryptedPrivate);
return saltedAndEncryptedPrivate;
}
private static RSAPrivateKey decryptRSAPrivateKey(final byte[] encryptedRSAPrivateKey,
final SecretKey aesKey) throws InvalidKeyException {
try {
final Cipher c = Cipher.getInstance("AES/GCM/NoPadding");
int offset = 0;
final byte[] iv = Arrays.copyOfRange(encryptedRSAPrivateKey, 0,
c.getBlockSize());
offset += c.getBlockSize();
c.init(Cipher.UNWRAP_MODE, aesKey, new IvParameterSpec(iv));
final Key key = c.unwrap(Arrays.copyOfRange(encryptedRSAPrivateKey, offset,
encryptedRSAPrivateKey.length), "RSA", Cipher.PRIVATE_KEY);
return (RSAPrivateKey) key;
} catch (final InvalidKeyException e) {
throw e;
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(e);
}
}
public static RSAPrivateKey unwrapRSAPrivateKey(final String passphrase,
final byte[] saltedAndEncryptedPrivate) throws InvalidKeyException {
int offset = 0;
final byte[] backSalt = Arrays.copyOfRange(saltedAndEncryptedPrivate,
offset, 16);
offset += 16;
final SecretKey backAESKey = deriveAESKey(backSalt,
passphrase.toCharArray());
final byte[] backEncryptedPrivateKey = Arrays.copyOfRange(
saltedAndEncryptedPrivate, offset,
saltedAndEncryptedPrivate.length);
final RSAPrivateKey decryptedPrivate = decryptRSAPrivateKey(
backEncryptedPrivateKey, backAESKey);
return decryptedPrivate;
}
public static RSAPublicKey decodeRSAPublicKey(
final byte[] x509EncodedPUblicKey) throws InvalidKeySpecException {
try {
final KeyFactory rsaPublicKeyFactory = KeyFactory.getInstance("RSA");
final PublicKey pubKey = rsaPublicKeyFactory
.generatePublic(new X509EncodedKeySpec(x509EncodedPUblicKey));
return (RSAPublicKey) pubKey;
} catch (final InvalidKeySpecException e) {
throw e;
} catch (final GeneralSecurityException e) {
throw new IllegalStateException(e);
}
}
public static byte[] encodeRSAPublicKey(final RSAPublicKey rsaPublicKey) {
return rsaPublicKey.getEncoded();
}
private static byte[] concat(final byte[] a, final byte[] a2) {
final byte[] result = new byte[a.length + a2.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(a2, 0, result, a.length, a2.length);
return result;
}
public static void main(final String[] args) throws Exception {
// --- not required for Java 8
Security.addProvider(new BouncyCastleProvider());
// --- setup key pair (generated in advance)
final String passphrase = "owlstead";
final KeyPair kp = generateRSAKeyPair(1024);
final RSAPublicKey rsaPublicKey = (RSAPublicKey) kp.getPublic();
final RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) kp.getPrivate();
// --- encode and wrap
byte[] x509EncodedRSAPublicKey = encodeRSAPublicKey(rsaPublicKey);
final byte[] saltedAndEncryptedPrivate = wrapRSAPrivateKey(
passphrase, rsaPrivateKey);
// --- decode and unwrap
final RSAPublicKey retrievedRSAPublicKey = decodeRSAPublicKey(x509EncodedRSAPublicKey);
final RSAPrivateKey retrievedRSAPrivateKey = unwrapRSAPrivateKey(passphrase,
saltedAndEncryptedPrivate);
// --- check result
System.out.println(retrievedRSAPublicKey);
System.out.println(retrievedRSAPrivateKey);
}
}
WARNING: for demonstration purposes only, please implement using classes and a more flexible method of handling the protocol (include e.g. a version number) etc.

Encrypt Decrypt my own key not generated java

I am new to cryptography, so I have a question:
How can I create my own key (let`s say like a string "1234"). Because I need to encrypt a string with a key (defined by me), save the encrypted string in a database and when I want to use it, take it from the database and decrypt it with the key known by me.
I have this code :
import java.security.InvalidKeyException;
import java.security.*;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
public class LocalEncrypter {
private static String algorithm = "PBEWithMD5AndDES";
//private static Key key = null;
private static Cipher cipher = null;
private static SecretKey key;
private static void setUp() throws Exception {
///key = KeyGenerator.getInstance(algorithm).generateKey();
SecretKeyFactory factory = SecretKeyFactory.getInstance(algorithm);
String pass1 = "thisIsTheSecretKeyProvidedByMe";
byte[] pass = pass1.getBytes();
SecretKey key = factory.generateSecret(new DESedeKeySpec(pass));
cipher = Cipher.getInstance(algorithm);
}
public static void main(String[] args)
throws Exception {
setUp();
byte[] encryptionBytes = null;
String input = "1234";
System.out.println("Entered: " + input);
encryptionBytes = encrypt(input);
System.out.println(
"Recovered: " + decrypt(encryptionBytes));
}
private static byte[] encrypt(String input)
throws InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] inputBytes = input.getBytes();
return cipher.doFinal(inputBytes);
}
private static String decrypt(byte[] encryptionBytes)
throws InvalidKeyException,
BadPaddingException,
IllegalBlockSizeException {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] recoveredBytes =
cipher.doFinal(encryptionBytes);
String recovered =
new String(recoveredBytes);
return recovered;
}
}
Exception in thread "main" java.security.spec.InvalidKeySpecException: Invalid key spec
at com.sun.crypto.provider.PBEKeyFactory.engineGenerateSecret(PBEKeyFactory.java:114)
at javax.crypto.SecretKeyFactory.generateSecret(SecretKeyFactory.java:335)
at LocalEncrypter.setUp(LocalEncrypter.java:22)
at LocalEncrypter.main(LocalEncrypter.java:28)
A KeyGenerator generates random keys. Since you know the secret key, what you need is a SecretKeyFactory. Get an instance for your algorithm (DESede), and then call its generateSecret méthode with an instance of DESedeKeySpec as argument:
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(someByteArrayContainingAtLeast24Bytes));
Here is a complete example that works. As I said, DESedeKeySpec must be used with the DESede algorithm. Using a DESede key with PBEWithMD5AndDES makes no sense.
public class EncryptionTest {
public static void main(String[] args) throws Exception {
byte[] keyBytes = "1234567890azertyuiopqsdf".getBytes("ASCII");
DESedeKeySpec keySpec = new DESedeKeySpec(keyBytes);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(keySpec);
byte[] text = "Hello world".getBytes("ASCII");
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encrypted = cipher.doFinal(text);
cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] decrypted = cipher.doFinal(encrypted);
System.out.println(new String(decrypted, "ASCII"));
}
}
Well, I found the solution after combining from here and there. The encrypted result will be formatted as Base64 String for safe saving as xml file.
package cmdCrypto;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.xml.bind.DatatypeConverter;
public class CmdCrypto {
public static void main(String[] args) {
try{
final String strPassPhrase = "123456789012345678901234"; //min 24 chars
String param = "No body can see me";
System.out.println("Text : " + param);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede");
SecretKey key = factory.generateSecret(new DESedeKeySpec(strPassPhrase.getBytes()));
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
String str = DatatypeConverter.printBase64Binary(cipher.doFinal(param.getBytes()));
System.out.println("Text Encryted : " + str);
cipher.init(Cipher.DECRYPT_MODE, key);
String str2 = new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(str)));
System.out.println("Text Decryted : " + str2);
} catch(Exception e) {
e.printStackTrace();
}
}
}

Categories