So I have generated a key pair in keytool and generated a symmetric key and the encrypted a String with the symmetric key and then encrypted the symmetric key. Now I have to decrypt the symmetric key and I am having some trouble. The code I am using for decryption is not throwing back any errors but it is not actually doing anything either and I am not sure what I am doing wrong.
package ReadFileExample;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.security.Key;
import java.security.KeyException;
import java.security.KeyPair;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.security.cert.Certificate;
import java.security.KeyStore;
import java.security.Key;
import java.io.FileInputStream;
public class generatekey {
static Cipher cipher;
public static void main(String[] args) throws Exception {
// generating a symmetric key using the AES algorithm
KeyGenerator generator = KeyGenerator.getInstance("AES");
// 128 bit key
generator.init(128);
//generates a secret key
SecretKey secretkey = generator.generateKey();
// returns an AES cipher
cipher = Cipher.getInstance("AES");
//print key
System.out.println("Key: " + cipher);
String plainText = "Hello World";
// call to method encrypt
String encryptedText = encrypt(plainText, secretkey);
// print orignial text and encrypted text
System.out.println("Plain Text: " + plainText);
System.out.println("Encrypted Text: " + encryptedText);
String publicKey = "C:/Users/girgich/public.cert";
// allows to write data to a file
FileOutputStream fos = null;
// write bytes to file
BufferedOutputStream bos = null;
// create file to which data needs to be written
String fileName = "C:/Users/girgich/newFile.txt";
try{
// allows written data to go into the written path
fos = new FileOutputStream(fileName);
// converts written data into bytes
bos = new BufferedOutputStream(fos);
// writes the encrypted text into file
bos.write(encryptedText.getBytes());
System.out.println("encryptedText has been written successfully in "
+fileName);
// allows to catch bug in code
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
// check for null exception
if (bos != null){
bos.close();
}
// check for null exception
if (fos != null){
fos.close();
}
} catch (IOException e){
e.printStackTrace();
}
}
// creates a file input stream by opening a path to the file needed
FileInputStream fin = new
FileInputStream("C:/Users/girgich/public.cert");
// implements the X509 certificate type
CertificateFactory f = CertificateFactory.getInstance("X.509");
// initalizes data found in the file
X509Certificate certificate =
(X509Certificate)f.generateCertificate(fin);
// gets public key from this certificate
PublicKey pk = certificate.getPublicKey();
System.out.println(pk);
String encryptedTextKey = encryptedKey(pk, secretkey);
System.out.println("Encrypted Key: " + encryptedTextKey);
// allows to write data to a file
FileOutputStream newFos = null;
// write bytes to file
BufferedOutputStream newBos = null;
// create file to which data needs to be written
String fileNameKey = "C:/Users/girgich/symmetric.txt";
try{
// allows written data to go into the written path
newFos = new FileOutputStream(fileNameKey);
// converts written data into bytes
newBos = new BufferedOutputStream(newFos);
// writes the encrypted text into file
newBos.write(encryptedTextKey.getBytes());
System.out.println("encryptedKey has been written successfully in "
+fileNameKey);
// allows to catch bug in code
} catch (IOException e) {
e.printStackTrace();
} finally {
try{
// check for null exception
if (newBos != null){
newBos.close();
}
// check for null exception
if (newFos != null){
newFos.close();
}
} catch (IOException e){
e.printStackTrace();
}
}
String decrypt = (encryptedTextKey);
}
public static String encrypt(String plainText, SecretKey secretkey) throws
Exception {
//Encodes the string into a sequence of bytes
byte[] plainTextByte = plainText.getBytes();
//intialize cipher to encryption mode
cipher.init(Cipher.ENCRYPT_MODE, secretkey);
//data is encrypted
byte[] encryptedByte = cipher.doFinal(plainTextByte);
Base64.Encoder encoder = Base64.getEncoder();
//encodes bytes into a string using Base64
String encryptedText = encoder.encodeToString(encryptedByte);
// return the string encrypted text to the main method
return encryptedText;
}
public static String encryptedKey(PublicKey pk, SecretKey secretkey) throws Exception {
// data written to byte array
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// writes data types to the output stream
ObjectOutputStream writter = new ObjectOutputStream(baos);
//specific object of secretkey is written to the output stream
writter.writeObject(secretkey);
//creates a byte array
byte[] plainTextByteKey = baos.toByteArray();
//creates a cipher using the RSA algorithm
Cipher cipher = Cipher.getInstance("RSA");
// initalizes cipher for encryption using the public key
cipher.init(Cipher.ENCRYPT_MODE, pk);
//encrypts data
byte[] encryptedByteKey = cipher.doFinal(plainTextByteKey);
Base64.Encoder encoderKey = Base64.getEncoder();
// encodes the byte array into a string.
String encryptedTextKey = encoderKey.encodeToString(encryptedByteKey);
return encryptedTextKey;
}
public void decrypt(String encryptedTextKey) {
byte[] decryptedData = null;
String password = "******";
try {
FileInputStream is = new FileInputStream("C:/Users/girgich/keystore.jks");
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(is, password.toCharArray());
String alias = "mykey";
Key key = keystore.getKey(alias, password.toCharArray());
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, key);
decryptedData = cipher.doFinal(encryptedTextKey.getBytes());
System.out.println("Decrypted Key: " + decryptedData);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Related
Below is my code.
when I try to print sealed object it only displays
"javax.crypto.SealedObject#34dac684"
private void encryptUserCodes(List<UserCode> userCodes) {
try {
// generate a secret key using the DES algorithm
key = KeyGenerator.getInstance("DES").generateKey();
ecipher = Cipher.getInstance("DES");
dcipher = Cipher.getInstance("DES");
// initialize the ciphers with the given key
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
// create a sealed object
SealedObject sealed = new SealedObject((Serializable) userCodes, ecipher);
//PRINT SEALED OBJECT HERE
}
catch(Exception e){
e.printStackTrace();
}
}
1. Encrypt:
Create Outputstreams and use Base64 Encoder to get the String.
2. Decrypt:
Create a new Cipher, Inputstreams and use Base 64 Decoder to get back your original String.
Fully working example (just copy and paste):
import javax.crypto.SecretKey;
import javax.crypto.KeyGenerator;
import javax.crypto.Cipher;
import javax.crypto.SealedObject;
import java.io.Serializable;
import java.io.ByteArrayOutputStream;
import javax.crypto.CipherOutputStream;
import java.io.ObjectOutputStream;
import java.io.ByteArrayInputStream;
import javax.crypto.CipherInputStream;
import java.io.ObjectInputStream;
import java.util.Base64;
public class MyClass {
public static void main(String args[]) {
OtherClass myObject = new OtherClass();
myObject.print();
}
}
// you can add other public classes to this editor in any order
class OtherClass
{
public void print() {
try {
String userCodes = "Test123";
// generate a secret key using the DES algorithm
SecretKey key = KeyGenerator.getInstance("DES").generateKey();
Cipher ecipher = Cipher.getInstance("DES");
// initialize the ciphers with the given key
ecipher.init(Cipher.ENCRYPT_MODE, key);
// create a sealed object
SealedObject sealed = new SealedObject((Serializable) userCodes, ecipher);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
CipherOutputStream cipherOutputStream = new CipherOutputStream(
outputStream, ecipher);
ObjectOutputStream oos = new ObjectOutputStream(cipherOutputStream);
oos.writeObject( sealed );
cipherOutputStream.close();
byte[] values = outputStream.toByteArray();
String base64encoded = Base64.getEncoder().encodeToString(values);
System.out.println(base64encoded);
// decrypt
Cipher fcipher = Cipher.getInstance("DES");
fcipher.init(Cipher.DECRYPT_MODE, key);
ByteArrayInputStream istream = new ByteArrayInputStream(Base64.getDecoder().decode(base64encoded));
CipherInputStream cipherInputStream = new CipherInputStream(istream, fcipher);
ObjectInputStream inputStream = new ObjectInputStream(cipherInputStream);
SealedObject sealdedObject = (SealedObject) inputStream.readObject();
System.out.println(sealdedObject.getObject(key));
}
catch(Exception e){
e.printStackTrace();
}
}
}
System.out.println will always print value of toString() method. In your case printing Class#hex is default implementation in Object class which gets inherited in all classes in java.
You can create a custom method to print the your object.
Provide method definition with traversing the desire result by calling getter methods from your object and print them. Concatenation and return is also an option.
Your sealed object is serializable. Thus you can write it to ObjectOutputStream:
try(ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos)) {
out.writeObject(sealed);
byte [] bytes = bos.toByteArray();
System.out.println(bytes);
} catch (IOException e) {
e.printStackTrace();
}
To print it more user friendly, you can encode it in base64:
String base64encoded = Base64.getEncoder().encodeToString(bytes);
System.out.println(base64encoded);
I have a problem with my code, when I encrypt data, for example, in this case, the simmetric key I encrypted with the receiver's public key, then saved to a text file, when I read that text file and try to decrypt it, using the receiver's private key, I get a different key, therefore I cannot use it to decrypt the encrypted message.
Sender's code:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
class Sender{
public static void main(String[] args) {
//infile.txt
File inFile = new File(args[0]);
//outfile.txt
File outFile = new File(args[1]);
//mykeystore.jks
File keyStoreFile = new File(args[2]);
//mykeystore info
String alias = args[3];
String password = args[4];
String storepass = args[5];
//receptor certificate
String receptorCert = args[6];
try {
//Read plain text
FileInputStream rawDataFromFile = new FileInputStream(inFile);
byte[] plainText = new byte[(int) inFile.length()];
rawDataFromFile.read(plainText);
//Create simmetric key
String key = "Bar12345Bar12345"; // 128 bit key
String initVector = "RandomInitVector"; // 16 bytes IV
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
//Encrypt plaintext
byte[] ciphertext = cipher.doFinal(plainText);
//Hash plaintext
MessageDigest md = MessageDigest.getInstance("SHA");
md.update(plainText);
byte[] digest = md.digest();
//Encrypt simmetric key with receiver's public key
Cipher rsaCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
PublicKey receptorPublicKey = getPublicKeyFromCert(receptorCert);
rsaCipher.init(Cipher.ENCRYPT_MODE, receptorPublicKey);
byte[] simmetricKey = rsaCipher.doFinal(skeySpec.getEncoded());
//Encrypt hash with my private key
KeyStore myKeyStore = KeyStore.getInstance("JKS");
FileInputStream inStream = new FileInputStream(keyStoreFile);
myKeyStore.load(inStream, storepass.toCharArray());
PrivateKey privatekey = (PrivateKey) myKeyStore.getKey(alias, password.toCharArray());
rsaCipher.init(Cipher.ENCRYPT_MODE, privatekey);
byte[] encodedHash = rsaCipher.doFinal(digest);
//Write to outputfile
FileOutputStream outToFile = new FileOutputStream(outFile);
outToFile.write(simmetricKey);
outToFile.write(encodedHash);
outToFile.write(ciphertext);
outToFile.close();
rawDataFromFile.close();
} catch (Exception e) {
e.printStackTrace();
e.getMessage();
}
}
public static PublicKey getPublicKeyFromCert(String certLocation) {
PublicKey pub = null;
try {
InputStream inStream = new FileInputStream(certLocation);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509Certificate cert = (X509Certificate) cf.generateCertificate(inStream);
inStream.close();
pub = (PublicKey) cert.getPublicKey();
} catch (Exception e) {
e.printStackTrace();
}
return pub;
}
}
Receiver's code:
import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import java.security.PrivateKey;
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Receiver {
public static void main(String[] args) {
//Sender's out file
File inFile = new File(args[0]);
//receiver's keystore
File keyStoreFile = new File(args[1]);
//receiver's keystore info
String password = args[2];
String alias = args[3];
String storepass = args[4];
//sender's cetificate
File cert = new File(args[5]);
try {
//get Sender's out file
FileInputStream rawDataFromFile = new FileInputStream(inFile);
byte[] simmetricKey = new byte[256];
byte[] hash = new byte[256];
byte[] message;
rawDataFromFile.read(simmetricKey);
rawDataFromFile.read(hash);
int b = rawDataFromFile.available();
message = new byte[b];
rawDataFromFile.read(message);
//decrypt the simmetric key with receiver's private key
KeyStore myKeyStore = KeyStore.getInstance("JKS");
FileInputStream inStream = new FileInputStream(keyStoreFile);
myKeyStore.load(inStream, storepass.toCharArray());
PrivateKey privatekey = (PrivateKey) myKeyStore.getKey(alias, password.toCharArray());
//
Cipher deCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
deCipher.init(Cipher.DECRYPT_MODE, privatekey);
byte[] key = deCipher.doFinal(simmetricKey);
System.out.println(Base64.encodeBase64String(key));
} catch (Exception e) {
System.out.println("Error del sistema " + e);
e.printStackTrace();
}
}
}
UPDATE:
Now I can decrypt the simmetric key using the receiver's private key. But I dont know how to create a decoder using the same argument when I encrypted the message.
Sender's code to encrypt plain text.
String key = "Bar12345Bar12345"; // 128 bit key
String initVector = "RandomInitVector"; // 16 bytes IV
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"));
System.out.println(iv.getIV());
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] ciphertext = cipher.doFinal(plainText);
Receiver's decryption 1
SecretKeySpec keySpec = new SecretKeySpec(decryptedKeySpec, "AES");
Cipher decoder = Cipher.getInstance("AES");
decoder.init(Cipher.DECRYPT_MODE, keyspec);
byte[] original = descipher.doFinal(message);
ERROR: Given final block not properly padded
Receiver's decryption 2
SecretKeySpec keySpec = new SecretKeySpec(decryptedKeySpec, "AES");
Cipher decoder = Cipher.getInstance("AES/CBC/PKCS5PADDING");
decoder.init(Cipher.DECRYPT_MODE, keyspec);
byte[] original = descipher.doFinal(message);
ERROR: Parameters missing
FINAL UPDATE:
Now my code works, thanks for all the help.
This code can be downloaded from here (btw, it's in spanish, but i don't think it matters):
download
The issue is you are using AES to encrypt
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
whereas to decipher,
you are using RSA,
Cipher deCipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
Code snippet to use for encrypt/decrypt using AES
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
public class EncryptionDecryptionAES {
static Cipher cipher;
public static void main(String[] args) throws Exception {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey secretKey = keyGenerator.generateKey();
cipher = Cipher.getInstance("AES");
String plainText = "AES Symmetric Encryption Decryption";
System.out.println("Plain Text Before Encryption: " + plainText);
String encryptedText = encrypt(plainText, secretKey);
System.out.println("Encrypted Text After Encryption: " + encryptedText);
String decryptedText = decrypt(encryptedText, secretKey);
System.out.println("Decrypted Text After Decryption: " + decryptedText);
}
public static String encrypt(String plainText, SecretKey secretKey)
throws Exception {
byte[] plainTextByte = plainText.getBytes();
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedByte = cipher.doFinal(plainTextByte);
Base64.Encoder encoder = Base64.getEncoder();
String encryptedText = encoder.encodeToString(encryptedByte);
return encryptedText;
}
public static String decrypt(String encryptedText, SecretKey secretKey)
throws Exception {
Base64.Decoder decoder = Base64.getDecoder();
byte[] encryptedTextByte = decoder.decode(encryptedText);
cipher.init(Cipher.DECRYPT_MODE, secretKey);
byte[] decryptedByte = cipher.doFinal(encryptedTextByte);
String decryptedText = new String(decryptedByte);
return decryptedText;
}
}
Please check http://javapapers.com/java/java-symmetric-aes-encryption-decryption-using-jce/
It seems that your receiver tries to read 256 byte for the encrypted symmetric key, but I think the RSA encrypted key only is 128 byte long.
So maybe it works using
byte[] simmetricKey = new byte[128];
I want to take a piece of plain text, a symmetric key(from a previous computation) in the form of a byte[] and output a cipher text. cipherText = encrypt(plainText,sharedSecret)
How do I merge the plain text and the shared secret?
public static String encrypt(String plainText, byte[] sharedSecret){
String cipherText = "";
//combining the sharedSecret with the plainText
return cipherText;
}
Check this code for symmetric key encryption. You can refactor to suit your encrypt method.
import java.security.AlgorithmParameters;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
public class SymmEncryption {
public static void main(String[] args) throws InvalidAlgorithmParameterException {
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(256); // 56 is the keysize. Fixed for DES
//Initialization Vector
byte[] iv = "1234567812345678".getBytes();
IvParameterSpec ivSpec = new IvParameterSpec(iv);
SecretKey secretKey = keyGenerator.generateKey();
System.out.println(secretKey.getFormat());
Cipher desCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");//algorithm/mode/padding
//Electronic Codebook (ECB)
System.out.format("Secret Key: %s--%s--%s%n", secretKey.getAlgorithm(), secretKey.getFormat(), secretKey.getEncoded());
// Initialize the cipher for encryption
desCipher.init(Cipher.ENCRYPT_MODE, secretKey, ivSpec);
// sensitive information
byte[] text = "No body can see me".getBytes();
System.out.println("Hex text: " + byteArrayToHex(text));
System.out.println("Text [Byte Format] : " + text);
System.out.println("Text : " + new String(text));
// Encrypt the text
byte[] textEncrypted = desCipher.doFinal(text);
System.out.println("Text Encryted : " + textEncrypted);
System.out.println("Hex Encrypted text: " + byteArrayToHex(textEncrypted));
// Initialize the same cipher for decryption
desCipher.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
// Decrypt the text
byte[] textDecrypted = desCipher.doFinal(textEncrypted);
System.out.println("Text Decryted : " + new String(textDecrypted));
System.out.println("Hex Decrypted text: " + byteArrayToHex(textDecrypted));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}
}
static String byteArrayToHex(byte[] a) {
StringBuilder sb = new StringBuilder();
for (byte b : a)
sb.append(String.format("%02x", b & 0xff));
return sb.toString();
}
}
Here it is program for encryption and Decryption using DES. program is working when passing the output of encryption directly for decryption. but when taking input from user in string to decrypt, it showing this exception. how to pass cipher string in bytes so it becomes compatible for decryption?
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.DESKeySpec;
import javax.xml.bind.DatatypeConverter;
public class DESEncryptionDecryption {
private static Cipher encryptCipher;
private static Cipher decryptCipher;
public static void main(String[] args) throws InvalidKeySpecException {
try {
String desKey = "0123456789abcdef"; // value from user
byte[] keyBytes = DatatypeConverter.parseHexBinary(desKey);
System.out.println(keyBytes);
SecretKeyFactory factory = SecretKeyFactory.getInstance("DES");
SecretKey key = factory.generateSecret(new DESKeySpec(keyBytes));
encryptCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
encryptCipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedData = encryptData("Confidential data"); //String from user
String s=encryptedData.toString();//String input to decrypt From user
byte[] bb=s.getBytes();
decryptCipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
decryptCipher.init(Cipher.DECRYPT_MODE, key);
decryptData(bb); //Exception
}catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
}}
//method for encryption
private static byte[] encryptData(String data)
throws IllegalBlockSizeException, BadPaddingException {
System.out.println("Data Before Encryption :" + data);
byte[] dataToEncrypt = data.getBytes();
byte[] encryptedData = encryptCipher.doFinal(dataToEncrypt);
System.out.println("Encryted Data: " + encryptedData);
return encryptedData;
}
//method for decryption
private static void decryptData(byte[] data)
throws IllegalBlockSizeException, BadPaddingException {
byte[] textDecrypted = decryptCipher.doFinal(data); //Exception trigered here
System.out.println("Decryted Data: " + new String(textDecrypted));
}}
I can't easily tell whether this is all that's wrong, but this is definitely wrong:
byte[] encryptedData = encryptData("Confidential data"); //String from user
String s=encryptedData.toString();//String input to decrypt From user
byte[] bb=s.getBytes();
Just decrypt encryptedData instead of of bb. Your s value is basically useless, because you've called toString() on a byte[], which won't give you what you're apparently expecting. The value of s will be something like "[B#15db9742" because arrays don't override toString() in Java.
If you really want to turn arbitrary binary data (such as the result of encryption) into text, use base64 instead. Encode the result of encryption using base64 to get a string, and then later base64-decode it from the string to a byte array, then decrypt that byte array.
Oh, and I'd strongly recommend against using String(byte[]) or String.getBytes() too - always use the overloads which take a character encoding instead.
For over a week, I've been using this to implement a RSA secured communication with my server that is in python.
However, I can not for the life of me figure out the proper imports for all the jars.
I have included all the jars found on bouncy castles website and still no dice!
I read that they moved stuff around. If this code is old or broken, what other implementation of RSA with pkcs1 padding is put there?
EDIT:
pub key is in a file named key.pub. how do I read that file in to be used as the key
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv2B0wo+QJ6tCqeyTzhZ3
AtPLgAHEQ/fRYDcR0BkQ+lXEhD277P2fPZwla5AW6szqsjR1olkZEF7IuoI27Hxm
tQHJU0ROhrzstHgK42emz5Ya3BWcm+oq5pLDZnsNDnNlrPncaCT7gHQQJn3YjH8q
aibtB1WCoy7ZJ127QxoKoLfeonBDtt7Qw6P5iXE57IbQ63oLq1EaYUfg8ZpADvJF
b2H3MASJSSDrSDgrtCcKAUYuu3cZw16XShuKCNb5QLsj3tR0QC++7qjM3VcG311K
7gHVjB6zybw+5vX2UWTgZuL6WVtCvRK+WY7nhL3cc5fmXZhkW1Jbx6wLPK3K/JcR
NQIDAQAB
-----END PUBLIC KEY-----
EDIT 2: Adding Broken Code based on an answer
package Main;
import org.bouncycastle.util.encoders.Base64;
import javax.crypto.Cipher;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.Security;
import java.security.spec.X509EncodedKeySpec;
public class EncDecRSA {
public static byte[] pemToDer(String pemKey) throws GeneralSecurityException {
String[] parts = pemKey.split("-----");
return DatatypeConverter.parseBase64Binary(parts[parts.length / 2]);
}
public static PublicKey derToPublicKey(byte[] asn1key) throws GeneralSecurityException {
X509EncodedKeySpec spec = new X509EncodedKeySpec(asn1key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
return keyFactory.generatePublic(spec);
}
public static byte[] encrypt(PublicKey publicKey, String text) throws GeneralSecurityException {
Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding", "BC");//PKCS1-OAEP
rsa.init(Cipher.ENCRYPT_MODE, publicKey);
byte[] cipher = rsa.doFinal(text.getBytes());
String s = new String(cipher);
System.out.print(s);
// return cipher;
// return Base64.encode(rsa.doFinal(text.getBytes()));
cipher = Base64.encode(cipher);
return cipher;
}
static String readFile(String path)
throws IOException
{
String line = null;
BufferedReader br = new BufferedReader(new FileReader(path));
try {
StringBuilder sb = new StringBuilder();
line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
return sb.toString();
} finally {
br.close();
}
}
public static void main(String[] args) throws IOException, GeneralSecurityException {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
System.out.println("Working Directory = " +
System.getProperty("user.dir"));
String publicKey = readFile("key.public");
byte[] pem = pemToDer(publicKey);
PublicKey myKey = derToPublicKey(pem);
String sendMessage = "{'vid_hash': '917ef7e7be4a84e279b74a257953307f1cff4a2e3d221e363ead528c6b556edb', 'state': 'ballot_response', 'userInfo': {'ssn': '700-33-6870', 'pin': '1234', 'vid': '265jMeges'}}";
byte[] encryptedDATA = encrypt(myKey, sendMessage);
Socket smtpSocket = null;
DataOutputStream os = null;
DataInputStream is = null;
try {
smtpSocket = new Socket("192.168.1.124", 9999);
os = new DataOutputStream(smtpSocket.getOutputStream());
is = new DataInputStream(smtpSocket.getInputStream());
} catch (UnknownHostException e) {
System.err.println("Don't know about host: hostname");
} catch (IOException e) {
System.err.println("Couldn't get I/O for the connection to: hostname");
}
if (smtpSocket != null && os != null && is != null) {
try {
System.out.println("sending message");
os.writeBytes(encryptedDATA+"\n");
os.close();
is.close();
smtpSocket.close();
} catch (UnknownHostException e) {
System.err.println("Trying to connect to unknown host: " + e);
} catch (IOException e) {
System.err.println("IOException: " + e);
}
}
}
}
Which has the following error:
Here is the bit of python code that does that:
def _decrypt_RSA(self, private_key_loc, package):
'''
param: public_key_loc Path to your private key
param: package String to be decrypted
return decrypted string
'''
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_OAEP
from base64 import b64decode
key = open('key.private', "r").read()
rsakey = RSA.importKey(key)
rsakey = PKCS1_OAEP.new(rsakey)
decrypted = rsakey.decrypt(package)
# decrypted = rsakey.decrypt(b64decode(package))
return decrypted
Lastly:
Is this padding scheme with PKCS1-OAEP.
That is a major requirement for this to work.
Note that I have tried it with both base64 encode and without
This example is for SpongyCastle - Android repackage of BouncyCastle. They differ as you noticed. However, making encryption in Java is as simple as this
Convert Base64 encoded key string to ASN.1 DER encoded byte array
public static byte[] pemToDer(String pemKey) throws GeneralSecurityException {
String[] parts = pemKey.split("-----");
return DatatypeConverter.parseBase64Binary(parts[parts.length / 2]);
}
Convert ASN.1 DER encoded public key to PublicKey object
public static PublicKey derToPublicKey(byte[] asn1key) throws GeneralSecurityException {
X509EncodedKeySpec spec = new X509EncodedKeySpec(asn1key);
KeyFactory keyFactory = KeyFactory.getInstance("RSA", "BC");
return keyFactory.generatePublic(spec);
}
Encrypt data
public static byte[] encrypt(PublicKey publicKey, String text) throws GeneralSecurityException {
Cipher rsa = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding", "BC");
rsa.init(Cipher.ENCRYPT_MODE, publicKey);
return rsa.doFinal(text.getBytes());
}
bcprov-jdk15on-150.jar is the only jar needed.