如何使用 ElGamal 加密/解密文本文件
我正在尝试使用 ElGamal 来加密和解密文本文件以进行我的研究,但似乎我无法使其正常工作。 我有一组大小从 1kb - 1mb 不等的文本文件,我使用 512 位作为密钥大小。我已经知道,就像 RSA 一样,ELGamal 无法加密超过其模数的值,因此作为我的初始解决方案,我决定将每个文件分成块(小于其模数),以便我能够对其进行加密幸运的是,这些解决方案适用于加密。我的问题是这样的,当我尝试解密它时,生成的输出不是我期望看到的实际输出。我不知道问题的原因是什么,我真的需要在几天内找到解决方案。
我将向您展示一些我的代码片段,以便让您清楚地了解。
我使用以下内容生成了密钥对
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "BC";
keyGen.initialize(512);
我通过调用进行加密
public static void encryptFile(String srcFileName, String destFileName, PublicKey key) throws Exception
{
encryptDecryptFile(srcFileName,destFileName, key, Cipher.ENCRYPT_MODE);
}
并通过调用进行解密
public static void decryptFile(String srcFileName, String destFileName, PrivateKey key) throws Exception
{
encryptDecryptFile(srcFileName,destFileName, key, Cipher.DECRYPT_MODE);
}
以下是 encryptDecryptFile(..) 方法的定义
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)...
}
}
对于 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;
}
对于 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;
}
和解密(..)
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;
}
原始代码由 Aviran Mondo 编写
我认为这就是您所需要的,如果您想查看完整的源代码,请告诉我。 谢谢,
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,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这与您的代码不太相关,但是尝试将具有固定宽度块大小的块密码转换为可以通过将输入分成块并加密来在流上工作的块密码在加密上并不安全他们每个人。如果你这样做,你本质上是在做一个美化的单字母替换密码,其中每个“字符”都是一个块宽。这使得攻击者能够恢复您输入的部分结构,从而破坏您通常从这些加密原语获得的保证。作为示例,请参阅维基百科对这种特定加密模式的讨论和看看它是如何加密 Linux Penguin 的 Tux 的。加密的图像可以立即让您看到输入的结构。
如果您想使用像 ElGamal 这样的分组密码来加密文本流,则应该使用更复杂的结构,例如 密码块链接 (CBC) 或 计数器模式(CTR),可证明在合理大小的输入上加密是安全的。如果您使用其中一种模式,攻击者将很难尝试破坏您的安全性。
我很抱歉没有对您的代码提供任何更实质性的内容,但老实说,我认为在尝试调试此系统之前值得备份并选择一个强大的加密系统。否则,您最终会得到一个聪明的攻击者可以挫败的系统。
This isn't quite related to your code, but it is not cryptographically secure to try to turn a block cipher with a fixed-width block size into a block cipher that can work on a stream by just splitting the input up into blocks and encrypting each of them. If you do this, you essentially are doing a glorified monoalphabetic substitution cipher where each "character" is one block wide. This allows an attacker to recover parts of the structure of your input, which ruins the guarantee you normally get from these cryptographic primitives. As an example, see this Wikipedia discussion of this particular mode of encryption and see how it encrypts Tux the Linux Penguin. The encrypted image immediately allows you to see the structure of the input.
If you want to use a block cipher like ElGamal to encrypt a stream of text, you should use a more complex construction like cipher block chaining (CBC) or counter mode (CTR), which are provably cryptographically secure over inputs of reasonable size. An attacker would have a an extremely hard time trying to break your security if you used one of these modes.
I apologize for not having anything more substantial to say about your code, but I honestly think that it's worth backing up and picking a strong crypto system before trying to debug this one. Otherwise you'll end up with a system that a clever attacker could foil.
我终于找到了解决方案,无论如何我都会把它放在这里,以防有人也跟我遇到同样的问题。您所要做的就是将
encryptDecryptFile(..) 方法替换为 ,
因为密钥大小为 512 的 ElGamal 在加密 50b 时会生成 128b。我希望这已经足够清楚了。
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
in encryptDecryptFile(..) method with
since ElGamal with 512 key size produces 128b when encrypting 50b. I hope this is clear enough.