How to implement password based hybrid encryption in java? - 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.

Related

how to import android class in eclipse

Good Evening
I am trying to import the android class by name"RSA.java" into Eclipse
but I have errors in these sections in decode(key, Base64.DEFAULT) and encodeToString(key, Base64.DEFAULT) error is "DEFAULT cannot be resolved or is not a field" and Base64.decode(MODULUS,0) and Base64.decode(EXPONENT,0)
error is "The method decode(String, int) is undefined for the type Base64"
public static byte[] decryptBASE64(String key) throws Exception {
return Base64.decode(key, Base64.DEFAULT);
}
public static String encryptBASE64(byte[] key) throws Exception {
return Base64.encodeToString(key, Base64.DEFAULT);
}
public static PublicKey getPublicKey(String MODULUS,String EXPONENT) throws Exception{
byte[] modulusBytes = Base64.decode(MODULUS,0);
byte[] exponentBytes = Base64.decode(EXPONENT,0);
My Android class imported into the Eclipse
package com.questdot.rsaexample;
import java.util.Base64;
import java.math.BigInteger;
import java.security.Key;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.Cipher;
public class RSA {
public static final String KEY_ALGORITHM = "RSA";
public static final String SIGNATURE_ALGORITHM = "SHA256withRSA";
private static final String PUBLIC_KEY = "RSAPublicKey";
private static final String PRIVATE_KEY = "RSAPrivateKey";
public static byte[] decryptBASE64(String key) throws Exception {
return Base64.decode(key, Base64.DEFAULT);
}
public static String encryptBASE64(byte[] key) throws Exception {
return Base64.encodeToString(key, Base64.DEFAULT);
}
public static String sign(byte[] data, String privateKey) throws Exception {
byte[] keyBytes = decryptBASE64(privateKey);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initSign(priKey);
signature.update(data);
return encryptBASE64(signature.sign());
}
public static boolean verify(byte[] data, String publicKey, String sign)
throws Exception {
byte[] keyBytes = decryptBASE64(publicKey);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
signature.initVerify(pubKey);
signature.update(data);
return signature.verify(decryptBASE64(sign));
}
public static byte[] decryptByPrivateKey(byte[] data, String key)
throws Exception {
byte[] keyBytes = decryptBASE64(key);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
public static byte[] decryptByPublicKey(byte[] data, String key)
throws Exception {
byte[] keyBytes = decryptBASE64(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
public static byte[] encryptByPublicKey(byte[] data, String key)
throws Exception {
byte[] keyBytes = decryptBASE64(key);
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key publicKey = keyFactory.generatePublic(x509KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
public static byte[] encryptByPrivateKey(byte[] data, String key)
throws Exception {
byte[] keyBytes = decryptBASE64(key);
PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
cipher.init(Cipher.ENCRYPT_MODE, privateKey);
return cipher.doFinal(data);
}
public static String getPrivateKey(Map<String, Object> keyMap)
throws Exception {
Key key = (Key) keyMap.get(PRIVATE_KEY);
return encryptBASE64(key.getEncoded());
}
public static String getPublicKey(Map<String, Object> keyMap)
throws Exception {
Key key = (Key) keyMap.get(PUBLIC_KEY);
return encryptBASE64(key.getEncoded());
}
public static Map<String, Object> initKey() throws Exception {
KeyPairGenerator keyPairGen = KeyPairGenerator
.getInstance(KEY_ALGORITHM);
keyPairGen.initialize(1024);
KeyPair keyPair = keyPairGen.generateKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
Map<String, Object> keyMap = new HashMap<String, Object>(2);
keyMap.put(PUBLIC_KEY, publicKey);
keyMap.put(PRIVATE_KEY, privateKey);
return keyMap;
}
public static PublicKey getPublicKey(String MODULUS,String EXPONENT) throws Exception{
byte[] modulusBytes = Base64.decode(MODULUS,0);
byte[] exponentBytes = Base64.decode(EXPONENT,0);
BigInteger modulus = new BigInteger(1, (modulusBytes) );
BigInteger exponent = new BigInteger(1, (exponentBytes));
RSAPublicKeySpec spec = new RSAPublicKeySpec(modulus, exponent);
KeyFactory kf = KeyFactory.getInstance(RSA.KEY_ALGORITHM);
return kf.generatePublic(spec);
}
public static byte[] encrypt(Key publicKey, String s) throws Exception{
byte[] byteData = s.getBytes();
Cipher cipher = Cipher.getInstance("RSA/None/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encryptedData = cipher.doFinal(byteData);
return encryptedData;
}
}
Any suggestions?
Thanks.

How to save and re-use keypairs in Java asymmetric encryption?

I've written code that generates the key pairs, but was wondering if there's any way to save and re-use them?
Here is the code that generaes the pair:
public static void main(String[] args) throws Exception {
String plainText = "Hello world";
Map<String, Object> keys = getRSAKeys();
PrivateKey privateKey = (PrivateKey) keys.get("private");
PublicKey publicKey = (PublicKey) keys.get("public");
System.out.println(privateKey.getEncoded());
System.out.println(publicKey.getEncoded());
String encrypted = encryptMessage(plainText, privateKey);
System.out.println(encrypted);
String decrypted = decryptMessage(plainText, publicKey, encrypted);
System.out.println(decrypted);
}
private static Map<String, Object> getRSAKeys() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
KeyPair keyPair = keyPairGenerator.generateKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
Map<String, Object> keys = new HashMap<String, Object>();
keys.put("private", privateKey);
keys.put("public", publicKey);
return keys;
}
https://docs.oracle.com/javase/tutorial/security/apisign/step2.html -- good entry point.
Also here is some example code to do exactly what you want:
package mx.playground.security;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import javax.crypto.Cipher;
public class AppForStackOverflow {
public static final int KEY_SIZE = 2048;
public static final String PUBLIC_KEY_X509 = "C:\\workspace\\rsa-pair\\public-key";
public static final String PUBLIC_KEY_PKCS1 = "C:\\workspace\\rsa-pair\\public-key-pkcs1";
public static final String PUBLIC_KEY_PEM = "C:\\workspace\\rsa-pair\\public-key-pem";
public static final String PRIVATE_KEY_PKCS8 = "C:\\workspace\\rsa-pair\\private-key";
public static final String PRIVATE_KEY_PKCS1 = "C:\\workspace\\rsa-pair\\private-key-pkcs1";
public static final String PRIVATE_KEY_PEM = "C:\\workspace\\rsa-pair\\private-key-pem";
public static final String SIGNATURE_PATH = "C:\\workspace\\rsa-pair\\signature";
public static final String PRIVATE_KEY_PATH = PRIVATE_KEY_PKCS8;
public static final String PUBLIC_KEY_PATH = PUBLIC_KEY_X509;
public static void main(String[] args) {
generateRsaKeysPair();
encryptDecryptTest();
// symmetric encryption example, use it to store your Private Key in safe manner
String message = "test message";
String rightPass = "0123456789ABCDEF"; // for AES password should be at least 16 chars
String wrongPass = "zzz";
byte[] encryptedMessage = symmetricEncrypt(message.getBytes(), rightPass);
System.out.print(new String(encryptedMessage));
byte[] decryptedMessage = symmetricDecrypt(encryptedMessage, rightPass);
System.out.println(new String(decryptedMessage));
}
public static void generateRsaKeysPair() {
try {
KeyPairGeneratorJdk kpg = new KeyPairGeneratorJdk(KEY_SIZE, "RSA");
PublicKey publicKey = kpg.getPublicKey();
PrivateKey privateKey = kpg.getPrivateKey();
save(PUBLIC_KEY_PATH, publicKey.getEncoded());
save(PRIVATE_KEY_PATH, privateKey.getEncoded());
} catch (Exception e) {
throw new RuntimeException("Failed to execute generateRsaKeysPair()", e);
}
}
public static void encryptDecryptTest() {
try {
byte[] privateKeyBytes = read(PRIVATE_KEY_PATH);
byte[] publicKeyBytes = read(PUBLIC_KEY_PATH);
KeyFactory kf = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
PrivateKey privateKey = kf.generatePrivate(privateKeySpec);
X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKeyBytes);
PublicKey publicKey = kf.generatePublic(spec);
Cipher cipher = Cipher.getInstance("RSA");
// doing encryption
String message = "test message";
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] encodedMessage = cipher.doFinal(message.getBytes("UTF-8"));
System.out.println("ENCRYPTED: " + new String(encodedMessage));
// doing decryption
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] decodedMessage = cipher.doFinal(encodedMessage);
System.out.println("DECRYPTED: " + new String(decodedMessage));
} catch (Exception e) {
throw new RuntimeException("Failed to execute encryptDecryptTest()", e);
}
}
private static void save(String path, byte[] data) {
try {
File file = new File(path);
file.getParentFile().mkdirs();
try (FileOutputStream fos = new FileOutputStream(file)){
fos.write(Base64.getEncoder().encode(data));
fos.flush();
};
} catch (IOException e) {
throw new RuntimeException("Failed to save data to file: " + path, e);
}
}
private static byte[] read(String path) {
try {
return Base64.getDecoder().decode(Files.readAllBytes(new File(path).toPath()));
} catch (IOException e) {
throw new RuntimeException("Failed to read data from file: " + path, e);
}
}
/*
* Use this to encrypt your private key before saving it to disk
*/
public static byte[] symmetricEncrypt(byte[] data, String password) {
try {
SecretKeySpec secretKey = new SecretKeySpec(password.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] result = cipher.doFinal(data);
return result;
} catch (Exception e) {
throw new RuntimeException("Failed to execute symmetricEncrypt()", e);
}
}
public static byte[] symmetricDecrypt(byte[] data, String password) {
try {
SecretKeySpec secretKey = new SecretKeySpec(password.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] result = cipher.doFinal(data);
return result;
} catch (Exception e) {
throw new RuntimeException("Failed to execute symmetricEncrypt()", e);
}
}
}

Hybrid RSA-AES encryption

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

AES-256 Password Based Encryption/Decryption in Java

I found a guide for implementing AES encryption/decryption in Java and tried to understand each line as I put it into my own solution. However, I don't fully understand it and am having issues as a result. The end goal is to have passphrase based encryption/decryption. I've read other articles/stackoverflow posts about this, but most do not provide enough explanation (I am very new to crypto in Java)
My main issues right now are that even when I set byte[] saltBytes = "Hello".getBytes();
I still get a different Base64 result in the end (char[] password is random each time, but I read that it is safer to leave passwords in char[] form. My other problem is that when the program gets to decrypt(), I get a NullPointerException at
byte[] saltBytes = salt.getBytes("UTF-8");
Thank you in advance for any help/advice you can give me.
The code in question:
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;
public static void main(String []args) throws Exception {
char[] message = "PasswordToEncrypt".toCharArray();
System.out.println("Message: " + message.toString());
System.out.println("Encrypted: " + encrypt(message));
System.out.println("Decrypted: " + decrypt(encrypt(message).toCharArray()));
}
public static String encrypt(char[] plaintext) throws Exception {
salt = getSalt();
byte[] saltBytes = salt.getBytes();
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(plaintext, saltBytes, iterations, keySize);
SecretKey secretKey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretKey.getEncoded(), "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(plaintext.toString().getBytes("UTF-8"));
return DatatypeConverter.printBase64Binary(encryptedTextBytes);
}
public static String decrypt(char[] encryptedText) throws Exception {
byte[] saltBytes = salt.getBytes("UTF-8");
byte[] encryptedTextBytes = DatatypeConverter.parseBase64Binary(encryptedText.toString());
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
PBEKeySpec spec = new PBEKeySpec(encryptedText, saltBytes, iterations, keySize);
SecretKey secretkey = skf.generateSecret(spec);
SecretKeySpec secretSpec = new SecretKeySpec(secretkey.getEncoded(), "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 decryptedTextBytes.toString();
}
public static String getSalt() throws Exception {
SecureRandom sr = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[20];
sr.nextBytes(salt);
return salt.toString();
}
}
I think that you are making two mistakes :)
I've corrected your sample code to make it work :
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;
public static void main(String []args) throws Exception {
salt = getSalt();
char[] message = "PasswordToEncrypt".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.getEncoded(), "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.getEncoded(), "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);
}
}
The first mistake is that you generate 2 different salts (when using the encrypt method), so encrypted/decrypted logs were differents (logical, but the decryption would still work because you are calling the decryption directly after encryption).
The second mistake was for the secret key. You need to generate a secret key when you are encrypting, but not decrypting. To put it more simply, it is as if i was encrypting with the password "encrypt" and that you are trying to decrypt it with the password "decrypt".
I would advise you to generate every random stuff (such as private key, salt etc on startup). But beware that when you'll stop your app, you won't be able to decrypt old stuff unless getting the exact same random stuff.
Hope I helped :)
Regards,

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