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);
}
}
}
Related
I'm trying to learn about rsa public key generations. After some researches I create an "simple" code that should return a public key but I don't know why, it doesn't. Can anyone tell me why and explaine it?
public static byte[] GetTokens(String paramString) {
StringTokenizer stringTokenizer = new StringTokenizer(paramString, ",");
byte[] arrayOfByte = new byte[stringTokenizer.countTokens()];
for (byte b1 = 0; stringTokenizer.hasMoreTokens(); b1++) {
arrayOfByte[b1] = Byte.parseByte(stringTokenizer.nextToken());
}
return arrayOfByte;
}
public static PublicKey GenPublicKey() throws Exception {
BufferedReader bufferedReader = new BufferedReader(new FileReader("input_text"));
try {
String str1 = bufferedReader.readLine();
String str2 = bufferedReader.readLine();
BigInteger bigInteger1 = new BigInteger(GetTokens(str1));
BigInteger bigInteger2 = new BigInteger(GetTokens(str2));
RSAPublicKeySpec rSAPublicKeySpec = new RSAPublicKeySpec(bigInteger1, bigInteger2);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(rSAPublicKeySpec);
return publicKey;
}
catch (NoSuchAlgorithmException e) {
System.out.println("Exception thrown : " + e);
throw new IOException("Error reading key, ");
}
finally {
try {
bufferedReader.close();
} catch (Exception exception) {}
}
}
To testing it I wrote aleatory numbers on "input_text" file:
8,33
6,18
I will provide the code you need to generate a RSA public key:
import java.io.*;
import java.security.*;
import java.security.spec.*;
import java.util.*;
public class Hello {
public static void main(String[] args) throws NoSuchAlgorithmException {
// We generate an instance that allows to create private/public key pairs
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
// We use 1024 bits lenght
keyPairGenerator.initialize(2048);
// We generate key pair
KeyPair keyPair = keyPairGenerator.generateKeyPair();
// Original message
String originalMessage = "Hello";
// We obtain public key
Key publicKey = keyPair.getPublic();
// We convert the string in order to send the Key to the emitter
String publicKeyText = keyToString(publicKey);
System.out.println("Public key: " + publicKeyText);
}
private static String keyToString(Key publicKey) {
byte[] publicKeyBytes = publicKey.getEncoded();
String key = Base64.getEncoder().encodeToString(publicKeyBytes);
return key;
}
}
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.
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.*;
import com.Ostermiller.util.Base64;
import com.Ostermiller.util.MD5;
import java.net.URLEncoder;
public class EnDecryptor {
public static void addProvider()
{
if (Security.getProvider("IBMJCE") == null) {
// IBMJCE is not installed, install it.
try
{
Security.addProvider
((Provider)Class.forName("com.ibm.crypto.provider.IBMJCE").newInstance());
}
catch (Exception ex) {
AuthLogger.logFatal("EnDecryptor:addProvider():Cannot install provider: " + ex.getMessage());
}
}
}
public static String encrypt(String word)
{
addProvider();
String encWord="";
byte[] encryptedWordbytes=null;
try
{
if (null == word)
{
throw new NullPointerException("EnDecryptor:encrypt(): No string to be encrypted provided!");
}
AuthLogger.logDebug("EnDecryptor:encrypt():Generating an encryption key...");
encryptedWordbytes = MD5.getHash(word);
AuthLogger.logDebug("EnDecryptor:encrypt():MD5 HASH length:"+encryptedWordbytes.length);
AuthLogger.logDebug("EnDecryptor:encrypt():MD5 HASH :"+new String(encryptedWordbytes));
// Create a Rijndael key
SecretKeySpec KeySpec = new SecretKeySpec(encryptedWordbytes, "AES");
AuthLogger.logDebug("EnDecryptor:encrypt():Done generating the key...");
Cipher cipherKey =Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");
byte[] iv = new byte[16];
IvParameterSpec spec = null;
for(int i=0;i<16;i++)
{
iv[i]=(byte)i;
}
spec = new IvParameterSpec(iv);
cipherKey.init(Cipher.ENCRYPT_MODE, KeySpec, spec);
byte[] encryptedDataBytes = cipherKey.doFinal(word.getBytes());
String base64data = new String(Base64.encode(encryptedDataBytes));
AuthLogger.logDebug("EnDecryptor:encrypt():BASE64DATA="+base64data);
byte[] encryptedKeyBytes = MD5.getHash(encryptedDataBytes);
SecretKeySpec KeySpec2 = new SecretKeySpec(encryptedKeyBytes, "AES");
Cipher cipherKey2 = Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");//Cipher.getInstance(DataEncryptDecrypt.AlgEnc);
cipherKey2.init(Cipher.ENCRYPT_MODE, KeySpec2, spec);
byte[] encryptedkey = cipherKey2.doFinal(encryptedWordbytes);
String base64Key = new String(Base64.encode(encryptedkey));
AuthLogger.logDebug("EnDecryptor:encrypt():BASE64Key="+base64Key);
String parm1 = "Data=" + URLEncoder.encode(base64data, "UTF-8") ;//$$$ encode(base64data);
String parm2 = "A=" + URLEncoder.encode(base64Key, "UTF-8") ;//$$$ encode(base64Key);
//encWord="Data="+parm1+"&A="+parm2;
encWord=parm1+"&"+parm2;
}catch(Exception e)
{
e.printStackTrace();
}
return encWord;
}
public static String decrypt(String encData, String encKey)
{
addProvider();
String decryptedData="";
byte[] abKeysKey=null;
try
{
byte[] abEncryptedKeys=(Base64.decode(encKey.getBytes()));
if (null == encData)
{
throw new NullPointerException("EnDecryptor:decrypt(): No data to be decryopted provided!");
}
AuthLogger.logDebug("EnDecryptor:decrypt():Generating a the HASH of the data...");
abKeysKey = MD5.getHash(Base64.decode(encData.getBytes()));
// Create a Rijndael key
SecretKeySpec KeySpec = new SecretKeySpec(abKeysKey, "AES");
Cipher cipherKey = Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");//Cipher.getInstance(DataEncryptDecrypt.AlgEnc);
IvParameterSpec spec = null;
byte[] iv = new byte[16];
for(int i=0;i<16;i++)
{
iv[i]=(byte)i;
}
spec = new IvParameterSpec(iv);
cipherKey.init(Cipher.DECRYPT_MODE, KeySpec, spec);
byte[] abKeys = cipherKey.doFinal(abEncryptedKeys);
String base64key = new String(Base64.encode(abKeys));
AuthLogger.logDebug("EnDecryptor:decrypt():BASE64 DECODED KEY="+base64key);
//byte[] encryptedKeyBytes = MD5.getHash(encryptedDataBytes);
SecretKeySpec KeySpec2 = new SecretKeySpec(abKeys, "AES");
Cipher cipherKey2 = Cipher.getInstance("AES/CBC/PKCS5Padding", "IBMJCE");//Cipher.getInstance(DataEncryptDecrypt.AlgEnc);
cipherKey2.init(Cipher.DECRYPT_MODE, KeySpec2, spec);
byte[] decodedData = cipherKey2.doFinal(Base64.decode(encData.getBytes()));
decryptedData= new String(decodedData);
AuthLogger.logDebug("EnDecryptor:decrypt():decoded data="+decryptedData);
}catch(Exception e)
{
e.printStackTrace();
}
return decryptedData;
}
}
in this code i can mostly encode A-Z and a-z, 0-9 and +,/ but i cannot encode any special characters like(~,#,!, etc) or international characters like(ê,etc)
can anyone suggest anything because i need to encode and decode characters like these any help will be appreciated.
New edit
if i use import java.io.IOException; will it solve my issue?
i know it's not good to use sun packages but i have done this it encodes mostly all the spacial and international characters except one or two here is the code
import java.io.IOException;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
// Java Base64 Encoder / Java Base64 Decoder
public class Base64Test {
public static void main(String[] args) {
BASE64Decoder decoder = new BASE64Decoder();
BASE64Encoder encoder = new BASE64Encoder();
try {
String encodedBytes = encoder.encodeBuffer("(####&&&&&)".getBytes());
System.out.println("encodedBytes " + encodedBytes);
byte[] decodedBytes = decoder.decodeBuffer(encodedBytes);
System.out.println("decodedBytes " + new String(decodedBytes));
} catch (IOException e) {
e.printStackTrace();
}
}
}
OUTPUT
encodedBytes KEBAQEAmJiYmJik=
decodedBytes (####&&&&&)
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.
Thanx to evry one help me ..but still there is 2 problem after editing the code
import java.io.*;
import java.math.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RCC4 {
public RCC4(){}
public static void main(String[] args)throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException{
String test = "testisperfect";
System.out.println(RCC4.keyGet());
byte b[] = RCC4.keyGet().getBytes();
byte plain[] = test.getBytes();
**byte c[] = RCC4.encrypt(plain,b);**
**byte p[] = RCC4.decrypt(c,b);**
**System.out.println(new String(c)) ;
System.out.println(new String(p));**
}
public static byte[] encrypt(byte[] plaintext,byte[] keyBytes)
{
byte[] e = null;
try
{
Key key = new SecretKeySpec(keyBytes,"RC4");
Cipher enCipher = Cipher.getInstance("RC4");
**enCipher.init(Cipher.ENCRYPT_MODE ,key);**
e = enCipher.doFinal(plaintext);
}
catch(Exception ex)
{
ex.printStackTrace();
}
return e;
}
public static byte[] decrypt(byte[] ciphertext,byte[] keyBytes)
{
byte de[] = null;
try
{
Key key = new SecretKeySpec(keyBytes,"RC4");
Cipher deCipher = Cipher.getInstance("RC4");
**deCipher.init(Cipher.DECRYPT_MODE, key);**
de = deCipher.doFinal(ciphertext);
}
catch(Exception e)
{
e.printStackTrace();
}
return de;
}
public static Key getKey()
{
Key key = null;
try
{
SecureRandom sr = new SecureRandom();
KeyGenerator kg = KeyGenerator.getInstance("RC4");
kg.init(128,sr);
key = kg.generateKey();
}catch(Exception e)
{
e.printStackTrace();
}
return key;
}
public static String keyGet()
{
Key k = RCC4.getKey();
byte[] b = k.getEncoded();
BigInteger big = new BigInteger(b);
String s = big.toString();
return s;
}
}
When I press "Build file" it says process completed but at running file a message says
112670544188765215715791498302542646231
java.security.InvalidKeyException: Illegal key size or default parameters
at RCC4.encrypt(RCC4.java:37)
at RCC4.main(RCC4.java:23)
java.security.InvalidKeyException: Illegal key size or default parameters
at RCC4.decrypt(RCC4.java:53)
at RCC4.main(RCC4.java:24)
Exception in thread "main" java.lang.NullPointerException
at java.lang.String.<init>(String.java:479)
at RCC4.main(RCC4.java:26)
Process completed.
These Lines are indicated as *
Answer to original question:
Key key = new SecretKeySpec(byte[]keyBytes,RC4);
should be
Key key = new SecretKeySpec(keyBytes, "RC4");
Also,
deCipher.init(Cipher.WHATEVER, keyBytes);
should be
deCipher.init(Cipher.WHATEVER, key);
Then it compiles, however there's still some issue with the application logic. That's up to you again :).
Answer to new question:
The problem was the unneeded usage of SecretKeySpec. Somewhere between getKey(), keyGet() all the byte[] games and SecretKeySpec it got wrong somehow. I didn't have the patience to track it, so I just deleted it and made the code somewhat more readable to make sure I didn't miss anything. I think you will still understand it since it still is basically your code and it is much simpler now.
import java.security.*;
import javax.crypto.*;
public class RCC4 {
public static void main(String[] args) throws Exception {
String plain = "testisperfect";
Key key = RCC4.getKey();
String encrypted = RCC4.encrypt(plain, key);
String decrypted = RCC4.decrypt(encrypted, key);
System.out.println(encrypted);
System.out.println(decrypted);
}
private static String rc4(String plaintext, int mode, Key key) throws Exception {
Cipher cipher = Cipher.getInstance("RC4");
cipher.init(mode, key);
return new String(cipher.doFinal(plaintext.getBytes()));
}
public static String encrypt(String plaintext, Key key) throws Exception {
return rc4(plaintext, Cipher.ENCRYPT_MODE, key);
}
public static String decrypt(String ciphertext, Key key) throws Exception {
return rc4(ciphertext, Cipher.DECRYPT_MODE, key);
}
public static Key getKey() throws Exception {
KeyGenerator kg = KeyGenerator.getInstance("RC4");
SecureRandom sr = new SecureRandom();
kg.init(128, sr);
return kg.generateKey();
}
}
You need import SecretKeySpec which is under package javax.crypto.spec.
You're not calling the method correctly in that you're passing in the parameter type with the parameter. Parameter types are only shown when declaring a method, not when calling the method.
In other words, it's not
Key key = new SecretKeySpec(byte[] keyBytes, RC4);
it's instead
Key key = new SecretKeySpec(keyBytes, RC4);
You will of course need to have a keyBytes variable declared and initialized before trying to pass it into the parameter of this method.
package test;
import java.io.*;
import java.math.*;
import java.security.*;
import javax.crypto.*;
import javax.crypto.spec.*;
public class RCC4 {
public RCC4() {
}
public static void main(String[] args) throws NoSuchAlgorithmException,
NoSuchPaddingException, InvalidKeyException, IOException {
String test = "testisperfect";
System.out.println(RCC4.keyGet());
byte b[] = RCC4.keyGet().getBytes();
byte plain[] = test.getBytes();
byte c[] = RCC4.encrypt(plain, b);
byte p[] = RCC4.decrypt(c, b);
System.out.println(new String(c));
System.out.println(new String(p));
}
public static byte[] encrypt(byte[] plaintext, byte[] keyBytes) {
byte[] e = null;
try {
Key key = new SecretKeySpec(keyBytes, "RC4");
Cipher enCipher = Cipher.getInstance("RC4");
enCipher.init(Cipher.ENCRYPT_MODE, key);
e = enCipher.doFinal(plaintext);
} catch (Exception ex) {
ex.printStackTrace();
}
return e;
}
public static byte[] decrypt(byte[] ciphertext, byte[] keyBytes) {
byte de[] = null;
try {
Key key = new SecretKeySpec(keyBytes, "RC4");
Cipher deCipher = Cipher.getInstance("RC4");
deCipher.init(Cipher.DECRYPT_MODE, RCC4.getKey());
de = deCipher.doFinal(ciphertext);
} catch (Exception e) {
e.printStackTrace();
}
return de;
}
public static Key getKey() {
Key key = null;
try {
SecureRandom sr = new SecureRandom();
KeyGenerator kg = KeyGenerator.getInstance("RC4");
kg.init(128, sr);
key = kg.generateKey();
} catch (Exception e) {
e.printStackTrace();
}
return key;
}
public static String keyGet() {
Key k = RCC4.getKey();
byte[] b = k.getEncoded();
BigInteger big = new BigInteger(b);
String s = big.toString();
return s;
}
}