Encrypt with RSA - ZipException: invalid entry size - java

I'm writing a program which takes as input from the console - the name of a zip file, name of a zip file to be made containig the encrypted files generate from the first zip and a file containing the public key. I get an exception every time the stream closes:
Exception in thread "main" java.util.zip.ZipException: invalid entry size (expected 11 but got 128 bytes)
at java.util.zip.ZipOutputStream.closeEntry(ZipOutputStream.java:288)
at java.util.zip.ZipOutputStream.finish(ZipOutputStream.java:361)
at java.util.zip.DeflaterOutputStream.close(DeflaterOutputStream.java:238)
at java.util.zip.ZipOutputStream.close(ZipOutputStream.java:378)
at javax.crypto.CipherOutputStream.close(CipherOutputStream.java:217)
at com.Main.main(Main.java:107)
How can I fix this? The code is bellow:
import java.io.BufferedReader;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.Enumeration;
import java.util.Scanner;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
public class Main {
public final static int BUFFER_SIZE = 1024;
public static String getPublicKeyString(String fileName){
String key = new String();
try {
BufferedReader buf = new BufferedReader(new FileReader(fileName));
key = buf.readLine();
} catch ( IOException e) {
e.printStackTrace();
}
return key.trim();
}
public static PublicKey makePublicKey(String stored) throws GeneralSecurityException {
byte[] data = Base64.getDecoder().decode(stored);//Base64.decode(keyBytes, Base64.DEFAULT);
X509EncodedKeySpec spec = new X509EncodedKeySpec(data);
KeyFactory fact = KeyFactory.getInstance("RSA");
return fact.generatePublic(spec);
}
public static void main(String[] args) throws Exception {
Scanner scan = new Scanner(System.in);
System.out.println("Enter type of operation:");
String line = scan.nextLine();
if(line.equals("encrypt")){
// Reading from console
System.out.println("Enter name of original ZIP file:");
String originalZipFileName = scan.nextLine();
System.out.println("Enter name of new ZIP file:");
String newZipFileName = scan.nextLine();
System.out.println("Enter name of file containg public key:");
String publicKeyFileName = scan.nextLine();
String publicKey = getPublicKeyString(publicKeyFileName);
// Declaration
ZipFile originalZipFile = new ZipFile(originalZipFileName);
byte[] buffer = new byte[BUFFER_SIZE];
ZipOutputStream newZipFile = new ZipOutputStream(new FileOutputStream(newZipFileName));
Enumeration<? extends ZipEntry> zipEntries = originalZipFile.entries();
//
PublicKey key = makePublicKey(publicKey);
//System.out.println(key.toString());
//
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, key);
while(zipEntries.hasMoreElements()){
ZipEntry entry = zipEntries.nextElement();
ZipEntry copy = new ZipEntry(entry);
newZipFile.putNextEntry(copy);
int read;
InputStream input = originalZipFile.getInputStream(entry);
CipherOutputStream cos = new CipherOutputStream(newZipFile, cipher);
while((read = input.read(buffer)) != -1){
cos.write(buffer, 0, read);
}
input.close();
cos.close();
newZipFile.closeEntry();
}
}
}
}

RSA can only be used to encrypt relatively tiny amounts of data, less the size in bytes of the RSA modulus. When you execute cos.close(), the wrapped cipher object has its doFinal() method called which generates an IllegalBlockSizeException which is silently swallowed by CipherOutputStream. However, since no data made it through the cipher object the ZipOutputStream is messed up, so it throws an exception upon closure.
You can't use RSA the way you are trying to.

Related

Issue with Decryption of text file in JCE

I have to do encryption of text file using JCE (Java SE 1.6). For this I have written a method aes256CBCEncrypt which returns CipherOutputstream which I write in file 'encryptedtest'. Now when I am trying to do decryption of this file(named 'encryptedtest') using the method aes256CBCDecrypt, It returns me CipherInputStream which I am writing in 'decryptedtest' to verify its content. Surprisingly, this file is empty.
Can somebody help me out what is wrong with my code.
Code Snippet:
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
class MyTest{
public static OutputStream aes256CBCEncrypt(OutputStream os, String passPhrase) throws NoSuchAlgorithmException, NoSuchPaddingException, IOException, InvalidKeyException, InvalidAlgorithmParameterException
{
// MessageDigest md = MessageDigest.getInstance("SHA-256");
// md.update(passPhrase.getBytes());
// byte[] key = md.digest();
Cipher aesCipher = Cipher.getInstance("AES/CBC/ISO10126Padding");
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(System.currentTimeMillis());
byte[] bb = new byte[16];
secureRandom.nextBytes(bb);
os.write(bb);
aesCipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(passPhrase.getBytes(), "AES"), new IvParameterSpec(
bb));
return new CipherOutputStream(os, aesCipher);
}
public static InputStream aes256CBCDecrypt(File f, String passPhrase)
throws FileNotFoundException
{
FileInputStream fis = null;
try
{
//MessageDigest md = MessageDigest.getInstance("SHA-256");
// md.update(passPhrase.getBytes());
// byte[] key = md.digest();
Cipher aesCipher = Cipher.getInstance("AES/CBC/ISO10126Padding");
fis = new FileInputStream(f);
byte[] bb = new byte[16];
fis.read(bb);
aesCipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(passPhrase.getBytes(), "AES"), new IvParameterSpec(
bb));
return new CipherInputStream(fis, aesCipher);
}
catch (final Exception e)
{
}
return null;
}
public static void main(String args[]) throws InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidAlgorithmParameterException, IOException{
String keyFile = "C:\\contentProducer" + File.separator + "test";
String encryptedFile = "C:\\contentProducer" + File.separator + "encryptedtest";
String decryptedFile = "C:\\contentProducer" + File.separator + "decryptedtest";
FileInputStream in = new FileInputStream(keyFile);
FileOutputStream bos = new FileOutputStream(new File(encryptedFile));
//Call method for Encryption
OutputStream encryptedBos = aes256CBCEncrypt(bos,"0123456789abcdef");
int inByte;
while ((inByte = in.read()) != -1 ) {
encryptedBos.write(inByte);
}
in.close();
bos.close();
encryptedBos.close();
//Call Method for Decryption
InputStream inputStream = aes256CBCDecrypt(new File(encryptedFile), "0123456789abcdef");
FileOutputStream deos = new FileOutputStream(new File(decryptedFile));
while ((inByte = inputStream.read()) != -1 ) {
deos.write(inByte);
}
inputStream.close();
deos.close();
}
}
You are closing your FileOutputStream before you close your CipherOutputStream. This prevents the latter from completing its work and writing the encrypted data to disk.
bos.close();
encryptedBos.close();
should change to:
encryptedBos.close();
bos.close();

getting Base64 cannot be resolved at Decryptor... while trying to decrypt file

I'm writing a program that decrypt a file that was encrypted.
i recive the folowing output:
==============================
== Receiver\Decryptor side ==
==============================
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
Base64 cannot be resolved
Base64 cannot be resolved
Base64 cannot be resolved
at Decryptor.DecryptFileAndValidateSignature(Decryptor.java:97)
at Decryptor.main(Decryptor.java:65)
the error happens somwhere at these 3 lines -
ks.load(ksStream, receiverConfigurations.get("keyStorePass").toCharArray());
/* Loads private key from keyStore, needed to decrypt the symmetric key from configuration file */
PrivateKey receiverPrivateKey = (PrivateKey) ks.getKey(receiverConfigurations.get("receiverAlias"), receiverConfigurations.get("receiverKeyPass").toCharArray()); //private key of receiver
i guess something is wring with my imports..
as you can see i tried a lot. any help will be aprricated tnx
here is my code -
import java.io.File;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.Key;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.util.HashMap;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.security.KeyStore;
import java.security.Key;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Base64InputStream;
public class Decryptor {
public static void main(String args[]) throws Exception
{
if (args.length!=2)
{
System.out.println("Wrong number of parameters, please insert the path of encryptedTextFile.txt, cipherConfigurations.xml and the path for keystore file.\n" +
"Make sure that path is ended with '\\\\'. Example: c:\\\\test\\\\crypto\\\\keyStore.jks c:\\\\test\\\\crypto\\\\"
+ "\nAborting...\n");
return;
}
if (!Files.exists(Paths.get(args[0])))
{
System.out.println("Path "+args[0]+" doesn't exist.\nAborting...\n");
return;
}
String basePath = args[0];
String keyStore = args[1];
basePath = "c:\\test\\crypto\\";
System.out.println("-------------------------------------------------------------");
System.out.println("==============================");
System.out.println("== Receiver\\Decryptor side ==");
System.out.println("==============================");
/* Configurations that are known to the receiver */
HashMap<String,String> receiverConfigurations = new HashMap<>();
receiverConfigurations.put("encryptedTextFile" ,basePath+"encryptedTextFile.txt");
receiverConfigurations.put("configurationFile",basePath+"cipherConfigurations.xml");
receiverConfigurations.put("keyStorePass","gilperryB");
receiverConfigurations.put("receiverAlias","b_side");
receiverConfigurations.put("receiverKeyPass","gilperryB");
receiverConfigurations.put("decryptedTextFile",basePath+"decryptedText.txt");
receiverConfigurations.put("keyStorePath",keyStore);
receiverConfigurations.put("senderAlias","a_side");
DecryptFileAndValidateSignature(receiverConfigurations);
System.out.println("-------------------------------------------------------------");
}
/*
* Decrypts and validates a signature of an encrypted file that was sent between a sender and a receiver, in the following way:
* 1. Uses private key to encrypt a symmetric key from a configuration file.
* 2. Uses the symmetric key to decrypt the message sent in a different file
* 3. Calculates digital signature over the file, and compares it with the one received in the configuration file.
* 4. If the signatures match - returns true, else - returns false
* */
static public boolean DecryptFileAndValidateSignature(HashMap<String,String> receiverConfigurations) throws Exception
{
/* Load data from keyStore .jks file */
KeyStore ks = KeyStore.getInstance("jks"); // Load public key from keyStore
FileInputStream ksStream = new FileInputStream(receiverConfigurations.get("keyStorePath"));
ks.load(ksStream, receiverConfigurations.get("keyStorePass").toCharArray());
/* Loads private key from keyStore, needed to decrypt the symmetric key from configuration file */
PrivateKey receiverPrivateKey = (PrivateKey) ks.getKey(receiverConfigurations.get("receiverAlias"), receiverConfigurations.get("receiverKeyPass").toCharArray()); //private key of receiver
/* Load data received by the cipher configurations XML sent by sender */
HashMap<String,String> cipherConfigurations = ReadConfigurationXML(receiverConfigurations.get("configurationFile"));
if (cipherConfigurations == null)
{
System.out.println("Error reading cipher configurations XML.\nAborting...");
}
System.out.println("Read data Cipher configurations XML.");
/* Initialize the encryptor */
Cipher encryptor = Cipher.getInstance(cipherConfigurations.get("encryptionAlgoForSymmetricKey"), cipherConfigurations.get("encryptionAlgoForSymmetricKeyProvider"));
/* Get data from cipher configurations XML*/
byte[] symetricKeyEncrypted = Base64.decodeBase64(cipherConfigurations.get("symetricKeyEncrypted"));
/* Initialize the symmetric key encryptor */
Cipher rsaEncryptor = Cipher.getInstance(cipherConfigurations.get("encryptionAlgoForSendingSharedKey"), cipherConfigurations.get("encryptionAlgoForSendingSharedKeyProvider")); // encryptor for the secret key
byte[] symetricKeyDecrypted = DecryptText(symetricKeyEncrypted,rsaEncryptor,receiverPrivateKey, null);
byte[] ivConfig =Base64.decodeBase64(cipherConfigurations.get("ivspec"));
byte[] iv = DecryptText(ivConfig, rsaEncryptor, receiverPrivateKey, null);
IvParameterSpec ivSpec = new IvParameterSpec(iv);
byte[] digitalSignature = Base64.decodeBase64(cipherConfigurations.get("digitalSignature"));
Key symmetricKeyAfterDecription = new SecretKeySpec(symetricKeyDecrypted, cipherConfigurations.get("encryptionAlgoForKeyGeneration")); //build a new secret key from text
System.out.println("Decrypted symmetric key using his own private key");
/* Decrypt file into decryptedFile */
DecryptFile(receiverConfigurations.get("encryptedTextFile"), receiverConfigurations.get("decryptedTextFile"), encryptor, symmetricKeyAfterDecription,ivSpec);
System.out.println("Decrypted text file "+receiverConfigurations.get("encryptedTextFile")+" into "+receiverConfigurations.get("decryptedTextFile"));
/* Verify digital signature */
PublicKey senderPublicKey = ks.getCertificate(receiverConfigurations.get("senderAlias")).getPublicKey(); //publicKey holds the public key for sender
boolean signatureValidated = ValidateDigitalSignature(receiverConfigurations.get("decryptedTextFile"),cipherConfigurations.get("digitalSignatureAlgorithm"),senderPublicKey,digitalSignature);
if (!signatureValidated)
{
System.out.println("Error decrypting text or validating digital signature.\nAborting...");
return false;
}
else
{
System.out.println("File was successfully decrypted, digital signature was successfully validated.\n");
return true;
}
}
/*
* Simulates the process where the receiver is calculating the signature of a message he received
* and compares it to the signature sent to him by sender.
* Calculates the digital signature over the decrypted file, using the digital signature algorithm in digitalSignatureAlgorithm,
* and public key in senderPublicKey.
* returns true iff the signatures match.
* */
private static boolean ValidateDigitalSignature(String decryptedFile,
String digitalSignatureAlgorithm, PublicKey senderPublicKey, byte[] signatureToVerify) throws Exception {
Signature dsa = Signature.getInstance(digitalSignatureAlgorithm); /* Initializing the object with the digital signature algorithm */
dsa.initVerify(senderPublicKey);
/* Update and sign the data */
FileInputStream fis = new FileInputStream(decryptedFile);
byte[] block = new byte[8];
int i;
while ((i = fis.read(block)) != -1) { //read all blocks in file
dsa.update(block); // update digital signature after each block
}
fis.close();
return dsa.verify(signatureToVerify);
}
/*
* Reads an encrypted text file and decrypts it using a Cipher object (encryptor).
* The decrypted file will be the returned value.
* Decryption process contains also Base64 encoding of the text.
*/
private static void DecryptFile(String inputFile,String outputFile, Cipher encryptor, Key key, IvParameterSpec ivspec) throws Exception
{
assert (CreateFileIfNecessery(outputFile) == true); //creates output file if necessery
FileInputStream fis = new FileInputStream(inputFile);
Base64InputStream b64os = new Base64InputStream(fis);
CipherInputStream cis = new CipherInputStream(b64os, encryptor);
FileOutputStream fos = new FileOutputStream(outputFile);
encryptor.init(Cipher.DECRYPT_MODE, key, ivspec); //initilize cipher in decryption mode with IV
byte[] block = new byte[8];
int i;
while ((i = cis.read(block)) != -1) { //read all blocks in file
{
fos.write(block,0,i); // write each block encrypted to the output file
}
}
b64os.close();
fos.close(); // close output file
cis.close(); // close input file
}
/*
* Reads the configuration XML from file in 'path'.
* Retuns a HashMap containing the entries and their value.
* if not possible - returns null.
*/
public static HashMap<String,String> ReadConfigurationXML(String path) throws Exception
{
HashMap<String,String> cipherConfigurations = new HashMap<>();
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc;
try{
doc = builder.parse(path);
}catch (Exception e)
{
System.out.println("Error reading configurations file "+path+"\nAborting...");
return null;
}
NodeList mainNode = null;
try
{
mainNode = doc.getElementsByTagName("CipherConfigurations");
}
catch (Exception e)
{
System.out.println("Could not find element EncryptionConfigurations in the configurations file.\nAborting...");
return null;
}
if (mainNode.getLength()!=1)
{
System.out.println("Wrong structure of cipher configutarion element.\nAborting...");
return null;
}
NodeList cipherConfigurationsRoot = (NodeList) mainNode.item(0); // get the root element of the configurations
for (int i = 0; i < cipherConfigurationsRoot.getLength(); ++i)
{
Element elem = (Element) cipherConfigurationsRoot.item(i);
String paramName = elem.getNodeName();
String innerText = elem.getTextContent();
cipherConfigurations.put(paramName, innerText);
}
return cipherConfigurations;
}
/*
* Reads an encrypted text and decrypts it using a Cipher object (encryptor).
* The decrypted text will be the returned value.
* Decryption process contains also Base64 encoding of the text.
*/
public static byte[] DecryptText(byte[] text, Cipher encryptor, Key key, IvParameterSpec ivspec) throws Exception
{
OutputStream os = new ByteArrayOutputStream();
InputStream is = new ByteArrayInputStream(text);
Base64InputStream b64is = new Base64InputStream(is);
CipherInputStream cis = new CipherInputStream(b64is, encryptor);
encryptor.init(Cipher.DECRYPT_MODE, key, ivspec); //initilize cipher in decryption mode with IV
byte[] block = new byte[8];
int i;
while ((i = cis.read(block)) != -1) { //read all blocks in file
{
os.write(block,0, i); // write each block encrypted to the output file
}
}
b64is.close();
os.close(); // close output file
is.close(); // close input file
cis.close();
return ((ByteArrayOutputStream) os).toByteArray();
}
/*
* Creates file and its paths if not exist.
* Example: path = c:\\test\\test1\\foo.txt
* Method will check if this path and file exists, if not - will create full hierarchy.
*/
private static boolean CreateFileIfNecessery(String path) throws Exception
{
File f = new File(path);
if (!f.mkdirs()) return false; //creates the directories for the file
if (!f.createNewFile()) return false; // creates the output file
return true;
}
}
You're missing Apache's commons-codec-1.10.jar
or
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
if you're using Maven

AES Key From File Trouble

Program is running now. It runs but then crashes. In my files folder it creates an encrypted file but it is blank. It also does not produce a decrypted file at all. I also changed the bit size to 128. What else I am missing in order to properly implement AES?
This is the modified program
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.Cipher;
import java.security.NoSuchAlgorithmException;
import java.security.InvalidKeyException;
import java.security.InvalidAlgorithmParameterException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.DESKeySpec;
public class MyCiphers {
public static void main(String[] args) {
try {
BufferedReader br = new BufferedReader(new FileReader("key.txt"));
String key = br.readLine();
br.close();
FileInputStream fis = new FileInputStream("original.txt");
FileOutputStream fos = new FileOutputStream("encrypted.txt");
encrypt(key, fis, fos);
FileInputStream fis2 = new FileInputStream("encrypted.txt");
FileOutputStream fos2 = new FileOutputStream("decrypted.txt");
decrypt(key, fis2, fos2);
} catch (Throwable e) {
e.printStackTrace();
}
}
public static void encrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.ENCRYPT_MODE, is, os);
}
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
}
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
SecretKeySpec dks = new SecretKeySpec(key.getBytes(),"AES");
Cipher cipher = Cipher.getInstance("AES");
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, dks);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, dks);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
}
public static void doCopy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[128];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
os.flush();
os.close();
is.close();
}
}
As the error message says, there is no method getBytes() for the type InputStream.
You need to read the key and store it as a String.
eg.
rather than FileInputStream fisk ... do
BufferedReader br = new BufferedReader(new FileReader("Key.txt"));
String key = br.readLine();
br.close();
(assuming that your key file just contains the key on one line)
Then change your encrypt/decrypt and encryptOrDecrypt methods to take in the key as a String rather than InputStream
eg. encrypt(String key, InputStream is, OutputStream os)
Then you can call SecretKeySpec(key.getBytes(),"DES");
Also you realise that this is DES, not AES as you say right? If you want to use AES you will need a 128 bit key (or 192/256 bits)

RSA encryption(java) read the string input

I do RSA encryption and having a problem. I want to encrypt a string.To convert the string, I already have the rsHex array to convert it.. I run the source code but it give me error say "the system cannot find the file specified" Here is my source code. How do I solve his? Thanks for helping me :)
import de.flexiprovider.api.keys.PrivateKey;
import de.flexiprovider.api.keys.PublicKey;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
public class RSA {
private String str, s;
private String chipertext;
private byte[] cipherData;
public RSA(String string) throws Exception {
try {
String input = string;
FileReader read = new FileReader(input);
BufferedReader reader = new BufferedReader(read);
while ((s = reader.readLine()) != null) {
byte[] theByteArray = s.getBytes();
setUserinput(string);
rsHex(theByteArray);
}
} catch (Exception ex) {
Logger.getLogger(RSA.class.getName()).log(Level.SEVERE, null, ex);
}
//Creating an RSA key pair in Java
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); //instance of KeyPairGenerator
kpg.initialize(1024);//bit length of the modulus that required
KeyPair kp = kpg.genKeyPair();//returns a KeyPair object
Key publicKey = kp.getPublic(); //pull out the public and private keys
Key privateKey = kp.getPrivate();
//Saving the public and private key
//private key will be placed on our server, and the public key distributed to clients.
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = (RSAPublicKeySpec) fact.getKeySpec(publicKey, RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = (RSAPrivateKeySpec) fact.getKeySpec(privateKey, RSAPrivateKeySpec.class);
// Save the file to local drive
saveToFile("c:\\public.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("c:\\private.key", priv.getModulus(),priv.getPrivateExponent());
}
private void rsHex(byte[] bytes) throws Exception {
StringBuilder hex = new StringBuilder();
for (byte b : bytes) {
String hexString = Integer.toHexString(0x00FF & b);
hex.append(hexString.length() == 1 ? "0" + hexString : hexString);
}
setChipertext(hex.toString());
}
//save the moduli and exponents to file, we can just use boring old serialisation
public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
FileOutputStream f = new FileOutputStream(fileName);
ObjectOutputStream oos = new ObjectOutputStream(f);
oos.writeObject(mod);
oos.writeObject(exp);
oos.close();
}
////Encryption
//initialise the cipher with the public key that we previously saved to file.
PublicKey readKeyFromFile(String keyFileName) throws IOException {
PublicKey key = null;
try {
FileInputStream fin = new FileInputStream(keyFileName);
ObjectInputStream ois = new ObjectInputStream(fin);
BigInteger m = (BigInteger) ois.readObject();
BigInteger e = (BigInteger) ois.readObject();
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
java.security.PublicKey pubKey = fact.generatePublic(keySpec);
ois.close();
}
catch (Exception e) {
e.printStackTrace();
}
return key;
}
public void rsaEncrypt(String str)throws Exception {
PublicKey pubKey = readKeyFromFile(str);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);//initialise the cipher
cipherData = cipher.doFinal(str.getBytes());//passing in the data to be encrypted
rsHex(cipherData);
}
public String getUserinput() {
return str;
}
public String getChipertext() {
return chipertext;
}
public void setUserinput(String input) {
this.str = input;
}
public void setChipertext(String chipertext) throws Exception {
this.chipertext = chipertext;
}
}
----main Program------
import java.util.Scanner;
public class TWO{
public static void main(String[] args) throws Exception{
Scanner scan = new Scanner(System.in);
System.out.println("Insert your string");
String str = scan.nextLine();
RSA two = new RSA(str);
System.out.println("Encrypted: "+ two.getChipertext());
}
}
The problem is that you're taking an input string from the user, but then your code is treating this as though it was a filename by constructing a FileReader with that string.
Instead of all that nonsense with the FileReader and BufferedReader, is there any reason why you don't just use string.getBytes()?
You also seem to be making life awfully complicated for yourself: you're taking a string, converting into a byte array, then converting that into a string again (with hex representation), then converting that into a byte array again. That's an awful lot of messing about when you could really just take the byte representation of the original string (as given to you by getBytes()) and pass that directly to the RSA encryption.

RSA Encryption problem

I'm using RSA (With Java) to cipher a text. I need to send that text via email.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.math.BigInteger;
import java.nio.Buffer;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAPrivateKeySpec;
import java.security.spec.RSAPublicKeySpec;
import javax.crypto.Cipher;
public class importarLlaves {
/**
* #param args
*/
public static void main(String[] args) {
File archivo = new File("C:/llaves/Publica 2.txt");
File archivo2 = new File("C:/llaves/Privada 2.txt");
try {
BufferedReader lector = new BufferedReader(new FileReader(archivo));
String[] linea = lector.readLine().split(":");
String moduloPublico = linea[1];
linea = lector.readLine().split(":");
String exponentePublico = linea[1];
lector.close();
lector = new BufferedReader(new FileReader(archivo2));
lector.readLine();
linea = lector.readLine().split(":");
String exponentePrivado = linea[1];
lector.close();
String algorithm = "RSA";
KeyFactory factory = KeyFactory.getInstance(algorithm);
RSAPublicKeySpec publicKeySpec = new RSAPublicKeySpec(new BigInteger(moduloPublico), new BigInteger(exponentePublico));
PublicKey llavePublica = factory.generatePublic(publicKeySpec);
RSAPrivateKeySpec privateKeySpec = new RSAPrivateKeySpec(new BigInteger(moduloPublico), new BigInteger(exponentePrivado));
PrivateKey llavePrivada = factory.generatePrivate(privateKeySpec);
System.out.println(llavePublica.toString());
System.out.println(llavePrivada.toString());
// Iniciar un objeto para la encr / desencr
Cipher desCipher = Cipher.getInstance("RSA");
// Leer, escribir y encriptar un dato
BufferedReader stdIn = new BufferedReader(new InputStreamReader(System.in));
String pwd = stdIn.readLine();
byte [ ] cleartext = pwd.getBytes();
String s1 = new String (cleartext);
System.out.println ("password original:" + s1 );desCipher.init (Cipher.ENCRYPT_MODE, llavePublica);
byte [ ] ciphertext = desCipher.doFinal(cleartext);
String s2 = new String (ciphertext);
System.out.println ("password encriptado:" + s2 );
// Ahora desencriptar
desCipher.init(Cipher.DECRYPT_MODE, llavePrivada);
byte [ ] cleartext1 = desCipher.doFinal(ciphertext);
String s3 = new String (cleartext1);
System.out.println("password desencriptado:"+ s3 );
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
This code works great but when I try to decrypt it only works if I pass the original ciphertext byte.
byte [ ] cleartext1 = desCipher.doFinal(ciphertext);
I need to safely convert that encrypt from byte[] to an string (to send it vía email). But if I try like:
s2.getBytes();
It returns the bytes from the s2 string (where the encrypted text is stored). But if I try to use that string to pass to the desCipher (desencrypt) it fails and says that: DATA MUST NOT START WITH 0.
It's my understanding that not all bytes can clearly be encoded into characters (in a String). Encode it to base64 before sending, and then decode the base64 string before decryption.
The Apache Commons Codec project can encode/decode base64.
http://commons.apache.org/codec/

Categories

Resources