I'm trying to encrypt and decrypt text files using ElGamal for my study but it seems that I could not make it work correctly. I have a group of text files ranging from 1kb - 1mb, and I'm using 512bit for my key size. I already know that just like RSA, ELGamal can't encrypt values more than its modulus so as my initial solution, I've decided to divide each file into chunks(which is smaller than its modulus) for me to be able to encrypt it and luckily these solution works for encryption. My problem is this,when I tried to decrypt it, outputs that has been generated is not the actual output I'm expecting to see. I don't know what's the cause of my problem and I really need to find a solution within few days.
I'll be showing you some of my code snippets just to make it clear.
I had generated my keypair with the following
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "BC";
keyGen.initialize(512);
I encrypt by calling
public static void encryptFile(String srcFileName, String destFileName, PublicKey key) throws Exception
{
encryptDecryptFile(srcFileName,destFileName, key, Cipher.ENCRYPT_MODE);
}
and I decrypt by calling
public static void decryptFile(String srcFileName, String destFileName, PrivateKey key) throws Exception
{
encryptDecryptFile(srcFileName,destFileName, key, Cipher.DECRYPT_MODE);
}
Here's the definition of encryptDecryptFile(..) method
public static void encryptDecryptFile(String srcFileName, String destFileName, Key key, int cipherMode) throws Exception
{
OutputStream outputWriter = null;
InputStream inputReader = null;
try
{
Cipher cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC"");
String textLine = null;
//buffer(my chunks) depends wether it is encyption or decryption
byte[] buf = (cipherMode == Cipher.ENCRYPT_MODE? new byte[50] : new byte[64]);
int bufl;
// init the Cipher object for Encryption...
cipher.init(cipherMode, key);
// start FileIO
outputWriter = new FileOutputStream(destFileName);
inputReader = new FileInputStream(srcFileName);
while ( (bufl = inputReader.read(buf)) != -1)
{
byte[] encText = null;
if (cipherMode == Cipher.ENCRYPT_MODE)
{
encText = encrypt(copyBytes(buf,bufl),(PublicKey)key);
}
else
{
if (_log.isDebugEnabled())
{
System.out.println("buf = " + new String(buf));
}
encText = decrypt(copyBytes(buf,bufl),(PrivateKey)key);
}
outputWriter.write(encText);
if (_log.isDebugEnabled())
{
System.out.println("encText = " + new String(encText));
}
}
outputWriter.flush();
}
catch (Exception e)
{
_log.error(e,e);
throw e;
}
finally
{
try
{
if (outputWriter != null)
{
outputWriter.close();
}
if (inputReader != null)
{
inputReader.close();
}
}
catch (Exception e)
{
// do nothing...
} // end of inner try, catch (Exception)...
}
}
For copyBytes:
public static byte[] copyBytes(byte[] arr, int length)
{
byte[] newArr = null;
if (arr.length == length)
{
newArr = arr;
}
else
{
newArr = new byte[length];
for (int i = 0; i < length; i++)
{
newArr[i] = (byte) arr[i];
}
}
return newArr;
}
For encypt(...)
public static byte[] encrypt(byte[] text, PublicKey key) throws Exception
{
byte[] cipherText = null;
try
{
Cipher cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC"");
if (_log.isDebugEnabled())
{
_log.debug("\nProvider is: " + cipher.getProvider().getInfo());
_log.debug("\nStart encryption with public key");
}
// encrypt the plaintext using the public key
cipher.init(Cipher.ENCRYPT_MODE, key);
cipherText = cipher.doFinal(text);
}
catch (Exception e)
{
_log.error(e, e);
throw e;
}
return cipherText;
}
and decrypt(..)
public static byte[] decrypt(byte[] text, PrivateKey key) throws Exception
{
byte[] dectyptedText = null;
try
{
// decrypt the text using the private key
Cipher cipher = Cipher.getInstance("ElGamal/None/NoPadding", "BC"");
cipher.init(Cipher.DECRYPT_MODE, key);
dectyptedText = cipher.doFinal(text);
}
catch (Exception e)
{
_log.error(e, e);
throw e;
}
return dectyptedText;
}
Original code by Aviran Mondo
I thinks that's all what you need, just tell me if you want to see the full source code. Thanks,
I finally have the solution, anyway I'll just put it here just in case someone also got the same problem with me. All you have to do is to replace
byte[] buf = (cipherMode == Cipher.ENCRYPT_MODE? new byte[50] : new byte[64]);
in encryptDecryptFile(..) method with
byte[] buf = (cipherMode == Cipher.ENCRYPT_MODE? new byte[50] : new byte[128]);
since ElGamal with 512 key size produces 128b when encrypting 50b. I hope this is clear enough.