I would try to use RC6 algorithm but i have an error:
RC6 KeyGenerator not available
How can i obtain the keygenerator of the rc6?
Exception in thread "main" java.security.NoSuchAlgorithmException: RC6 KeyGenerator not available
at javax.crypto.KeyGenerator.(KeyGenerator.java:169)
at javax.crypto.KeyGenerator.getInstance(KeyGenerator.java:223)
at RC6.encrypt(RC6.java:27)
at RC6.main(RC6.java:16)
import javax.crypto.spec.*;
import java.security.*;
import javax.crypto.*;
public class Main
{
private static String algorithm = "RC6";
public static void main(String []args) throws Exception {
String toEncrypt = "The shorter you live, the longer you're dead!";
System.out.println("Encrypting...");
byte[] encrypted = encrypt(toEncrypt, "password");
System.out.println("Decrypting...");
String decrypted = decrypt(encrypted, "password");
System.out.println("Decrypted text: " + decrypted);
}
public static byte[] encrypt(String toEncrypt, String key) throws Exception {
// create a binary key from the argument key (seed)
SecureRandom sr = new SecureRandom(key.getBytes());
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
kg.init(sr);
SecretKey sk = kg.generateKey();
// create an instance of cipher
Cipher cipher = Cipher.getInstance(algorithm);
// initialize the cipher with the key
cipher.init(Cipher.ENCRYPT_MODE, sk);
// enctypt!
byte[] encrypted = cipher.doFinal(toEncrypt.getBytes());
return encrypted;
}
public static String decrypt(byte[] toDecrypt, String key) throws Exception {
// create a binary key from the argument key (seed)
SecureRandom sr = new SecureRandom(key.getBytes());
KeyGenerator kg = KeyGenerator.getInstance(algorithm);
kg.init(sr);
SecretKey sk = kg.generateKey();
// do the decryption with that key
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, sk);
byte[] decrypted = cipher.doFinal(toDecrypt);
return new String(decrypted);
}
}
RC6 is not an algorithm that is provided by one of the Oracle security providers. The providers provide the algorithm implementations that are behind Cipher and indeed KeyGenerator.
This should work, after adding the Bouncy Castle provider .jar in the classpath:
static {
Security.addProvider(new BouncyCastleProvider());
}
You may also need to install the unlimited cryptography files in your JRE folder.
Related
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.
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
I'm relatively new to developing something with encryption. Right now I'm trying to write a class which encrypts and decrypts Strings using BouncyCastle with AES-GCM. I read about the things you have to consider when implementing encryption. One of them was that you should always use a randomized IV.
The problem is, everytime I try to initialize my Cipher with an IV it won't decrypt my text properly.
It just throws the following exception:
javax.crypto.AEADBadTagException: mac check in GCM failed
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher$AEADGenericBlockCipher.doFinal(Unknown Source)
at org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher.engineDoFinal(Unknown Source)
at javax.crypto.Cipher.doFinal(Cipher.java:2165)
at BouncyCastleEX.decrypt(BouncyCastleEX.java:78)
at BouncyCastleEX.main(BouncyCastleEX.java:43)
I'm using the following methods to encrypt and decrypt my data.
private static final String fallbackSalt = "ajefa6tc73t6raiw7tr63wi3r7citrawcirtcdg78o2vawri7t";
private static final int iterations = 2000;
private static final int keyLength = 256;
private static final SecureRandom random = new SecureRandom();
public byte[] encrypt(String plaintext, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
cipher.init(Cipher.ENCRYPT_MODE, key, generateIV(cipher),random);
return cipher.doFinal(plaintext.getBytes());
}
public String decrypt(byte[] encrypted, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key, generateIV(cipher),random);
return new String(cipher.doFinal(encrypted));
}
private SecretKey generateKey(String passphrase, String salt)
throws Exception {
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(),
salt.getBytes(), iterations, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
return keyFactory.generateSecret(keySpec);
}
private IvParameterSpec generateIV(Cipher cipher) throws Exception {
byte[] ivBytes = new byte[cipher.getBlockSize()];
random.nextBytes(ivBytes);
return new IvParameterSpec(ivBytes);
}
If I remove the "generateIV(cipher)" from my cipher.init(...) everything works flawlessly. But as far as I know it weakens the encryption tremendously.
Right know I'm unable to figure out whether this is a small mistake in the code or something else I know nothing about.
I really appreciate your help and thanks a lot!
You have to use the same IV for encryption and decryption. It doesn't have to be secret, but only unique for AES-GCM (it's technically a nonce). A common way is to prepend the IV to the ciphertext and remove it before decryption.
It's also common to use a message counter instead of randomly generating an IV. If the key is changed then you should reset the IV to an initial value and start counting again. At some number of messages, you need a new key, because the security guarantees of AES-GCM break down. That number is somewhere between 248 and 264 messages.
Here is the final version of my code which I wrote with the help of Artjom.
It seems to work great but if you find any mistakes or things that weaken the security, please let me know.
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.Arrays;
import com.sun.org.apache.xml.internal.security.utils.Base64;
public class BouncyCastleEX {
private static final int iterations = 2000;
private static final int keyLength = 256;
private static final SecureRandom random = new SecureRandom();
private static BouncyCastleEX instance = null;
public String encryptString(String plaintext, String passphrase, String salt)
throws Exception {
return Base64.encode(encrypt(plaintext, passphrase, salt));
}
public String decryptString(String encrypted, String passphrase, String salt)
throws Exception {
return decrypt(Base64.decode(encrypted), passphrase, salt);
}
private BouncyCastleEX() {
Security.addProvider(new BouncyCastleProvider());
}
public static BouncyCastleEX getInstance() {
if (instance == null) {
instance = new BouncyCastleEX();
}
return instance;
}
private byte[] encrypt(String plaintext, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
byte[] ivBytes = generateIVBytes(cipher);
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(ivBytes),
random);
return Arrays
.concatenate(ivBytes, cipher.doFinal(plaintext.getBytes()));
}
private String decrypt(byte[] encrypted, String passphrase, String salt)
throws Exception {
SecretKey key = generateKey(passphrase, salt);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding", "BC");
cipher.init(Cipher.DECRYPT_MODE, key,
new IvParameterSpec(Arrays.copyOfRange(encrypted, 0, 12)),
random);
return new String(cipher.doFinal(Arrays.copyOfRange(encrypted, 12,
encrypted.length)));
}
private SecretKey generateKey(String passphrase, String salt)
throws Exception {
PBEKeySpec keySpec = new PBEKeySpec(passphrase.toCharArray(),
salt.getBytes(), iterations, keyLength);
SecretKeyFactory keyFactory = SecretKeyFactory
.getInstance("PBEWITHSHA256AND256BITAES-CBC-BC");
return keyFactory.generateSecret(keySpec);
}
private byte[] generateIVBytes(Cipher cipher) throws Exception {
byte[] ivBytes = new byte[12];
random.nextBytes(ivBytes);
return ivBytes;
}
}
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.
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();
}
}
}