Почему RC4 не может обрабатывать большое количество зашифрованных данных? - PullRequest
0 голосов
/ 17 июня 2011

У меня есть следующий код, который расшифровывает файл.

package encryption;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;

import org.bouncycastle.jce.provider.BouncyCastleProvider;

public class Decrypter {

    private static final String PASSWORD = "t_9Y#i@eT[h3}-7!";
    private static final String KEY_ALGORITHM = "PBEWithMD5AndDES";
    private static final String CIPHER_ALGORITHM = "RC4"; //Using Salsa20 or HC256 solves the problem
    private static final String PROVIDER = "BC";

    public static void main(String[] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        File inputFile = new File(args[0]);
        File outputFile = new File(args[1]);

        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(KEY_ALGORITHM);
        SecretKey key = keyFactory.generateSecret(new PBEKeySpec(PASSWORD.toCharArray()));

        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, key);

        InputStream inputStream = new FileInputStream(inputFile);
        OutputStream outputStream = new FileOutputStream(outputFile);

        CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);

        byte []byteBuffer = new byte[(int)inputFile.length()]; 
        cipherInputStream.read(byteBuffer);
        outputStream.write(byteBuffer); //Only 512bytes of decrypted data is written to file, the rest becomes null
        outputStream.close();
    }

}

Мой вопрос: что я делаю не так?Почему RC4 не расшифровывает блок размером более 512 байт.

Ответы [ 3 ]

7 голосов
/ 17 июня 2011

RC4 - потоковый шифр, поэтому он может декодировать любой объем данных. Ваша проблема заключается в том, что InputStreams не читаются большими массивами. Обычно вы зацикливаетесь на вызове чтения до тех пор, пока не останется больше данных для чтения и используете небольшой буфер. См. документацию read () .

Это может быть реализовано как

while(true) {
    int numRead = cipherInputStream.read(byteBuffer);
    if(numRead == -1)
        break;
    outputStream.write(byteBuffer, 0, numRead);
}
2 голосов
/ 18 июня 2011

@ У Майкла Лоумана правильный ответ, но я подумал, что покажу другой способ, просто рекламируя функцию класса DataInputStream.

Вы можете прочитать все в одном-go поведение, как придирка perl, с помощью метода DataInputStream.readFully().В вашем примере вы можете прочитать байты с помощью этого метода, затем записать их и расшифровать, используя в качестве CipherOutputStream вместо CipherInputStream.

Рассмотрите следующий фрагмент в качестве примера:

    byte[] byteBuffer = new byte[(int) inputFile.length()];
    DataInputStream dis = new DataInputStream(inputStream);
    dis.readFully(byteBuffer);
    dis.close();
    CipherOutputStream cos = new CipherOutputStream(outputStream, cipher);
    cos.write(byteBuffer);
    cos.close();
0 голосов
/ 17 июня 2011

InputStream.read возвращает только определенное количество данных, которые вы должны зациклить, пока поток не станет пустым. Однако я советую вам использовать commons-io org.apache.commons.io.FileUtils.copyInputStreamToFile(InputStream, File) для копирования потоков, а не для прокрутки собственного ...

...