java 如何使用 ElGamal 加密/解密文本文件
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4894882/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to encrypt/decrypt text files using ElGamal
提问by celax
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.
我正在尝试使用 ElGamal 加密和解密文本文件以进行研究,但似乎无法使其正常工作。我有一组 1kb - 1mb 的文本文件,我的密钥大小使用 512 位。我已经知道,就像 RSA 一样,ELGamal 无法加密超过其模数的值,因此作为我的初始解决方案,我决定将每个文件分成块(小于其模数)以便我能够对其进行加密幸运的是,这些解决方案适用于加密。我的问题是,当我尝试解密它时,生成的输出不是我期望看到的实际输出。我不知道我的问题的原因是什么,我真的需要在几天内找到解决方案。
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
这是 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)...
}
}
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(...)
对于 enpt(...)
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
Aviran Mondo 的原始代码
I thinks that's all what you need, just tell me if you want to see the full source code. Thanks,
我认为这就是您所需要的,如果您想查看完整的源代码,请告诉我。谢谢,
采纳答案by celax
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
在 encryptDecryptFile(..) 方法中
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.
因为密钥大小为 512 的 ElGamal 在加密 50b 时会产生 128b。我希望这已经足够清楚了。
回答by templatetypedef
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 encryptionand see how it encrypts Tux the Linux Penguin. The encrypted image immediately allows you to see the structure of the input.
这与您的代码不太相关,但是尝试将具有固定宽度块大小的块密码转换为可以通过将输入分成块并加密来处理流的块密码在密码学上是不安全的他们每个人。如果你这样做,你实际上是在做一个美化的单字母替换密码,其中每个“字符”都是一个块宽。这允许攻击者恢复您输入的部分结构,这破坏了您通常从这些加密原语中获得的保证。例如,请参阅此 Wikipedia 对这种特殊加密模式的讨论,并了解它如何加密 Tux the Linux Penguin。加密的图像立即允许您查看输入的结构。
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.
如果你想使用像 ElGamal 这样的分组密码来加密文本流,你应该使用更复杂的结构,如密码分组链接 (CBC)或计数器模式 (CTR),它们在合理大小的输入上可证明是加密安全的。如果您使用其中一种模式,攻击者将很难尝试破坏您的安全。
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.
我很抱歉没有对您的代码发表任何更实质性的内容,但老实说,我认为在尝试调试该系统之前,值得备份并选择一个强大的加密系统。否则,您最终会得到一个聪明的攻击者可以挫败的系统。