DES Шифрование: данный конечный блок неправильно заполнен

Я получил этот кусок кода:

static ReadableByteChannel readChannel = null;
static WritableByteChannel writeChannel = null;
static SecretKey key = makeKeyFromPassword("chuj".getBytes());

public static SecretKey makeKeyFromPassword(byte[] password) {

 try {
 key = KeyGenerator.getInstance("DES").generateKey();
 byte[] encoded = key.getEncoded();
 return new SecretKeySpec(encoded, "DES");
 } catch (Exception e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }

 return null;
}

public static void run(int mode) throws Exception {
 ByteBuffer readBuffer = ByteBuffer.allocate(1024);
 ByteBuffer writeBuffer = ByteBuffer.allocate(1024);

 //initializing cipher...
 Cipher cipher = javax.crypto.Cipher.getInstance("DES"); 
 cipher.init(mode, key); 

 int read = -1;
 while((read = readChannel.read(readBuffer)) != -1){
 readBuffer.flip();
 cipher.doFinal(readBuffer, writeBuffer);
 writeChannel.write(writeBuffer);
 readBuffer.clear();
 writeBuffer.clear();
 }
}

public static void main(String[] args) {
 // TODO Auto-generated method stub\
 FileOutputStream fos = null;
 String inFileString = "C:\\test.txt"; // Valid file pathname
 String fileString = "C:\\des.txt"; // Valid file pathname
 int mode = Cipher.ENCRYPT_MODE;
 FileSystem fs = FileSystems.getDefault();
 Path fp = fs.getPath(inFileString);

 try {
 readChannel = FileChannel.open(fp, EnumSet.of(StandardOpenOption.READ));
 fos = new FileOutputStream(fileString);
 writeChannel = Channels.newChannel(fos);
 run(mode);
 } catch (Exception e) {
 // TODO Auto-generated catch block
 e.printStackTrace();
 }

}

Шифрование работает без исключений. Но когда я пытаюсь расшифровать данные (режим == DECRYPT_MODE и коммутируемые имена файлов)

javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.DESCipher.engineDoFinal(DESCipher.java:357)
at javax.crypto.CipherSpi.bufferCrypt(CipherSpi.java:767)
at javax.crypto.CipherSpi.engineDoFinal(CipherSpi.java:721)
at javax.crypto.Cipher.doFinal(Cipher.java:2382)
at Test.run(Test.java:57)
at Test.main(Test.java:77)

выскакивает.

Я пробовал с разными ключами, но безуспешно. Любая помощь будет оценена. [Я должен использовать каналы, этот код является только тестом для части большего класса]

2 ответа

Две вещи:

  1. Прежде всего, нет никакой корреляции с переменной password в методе makeKeyFromPassword. SecretKey является случайным, поэтому невозможно будет декодировать данные в двух разделительных прогонах программы.
  2. Во-вторых, должен быть writeBuffer.flip() после cipher.doFinal(readBuffer, writeBuffer) ;-)

Рабочий код (обратите внимание, что пароль, который используется для генерации ключа DES, должен быть не менее 8 символов):

public class Test {

 static ReadableByteChannel readChannel = null;
 static WritableByteChannel writeChannel = null;
 static SecretKey key = makeKeyFromPassword("abcdefghi".getBytes()); 
 static byte b[];

 public static SecretKey makeKeyFromPassword(byte[] password) {
 try {
 DESKeySpec dks = new DESKeySpec(password);
 SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
 return skf.generateSecret(dks);
 } catch (Exception e) {
 e.printStackTrace();
 }
 return null;
 }

 public static void run(int mode) throws Exception {
 ByteBuffer readBuffer = ByteBuffer.allocate(1024);
 ByteBuffer writeBuffer = ByteBuffer.allocate(1024);

 // initializing cipher...
 Cipher cipher = Cipher.getInstance("DES");
 cipher.init(mode, key);

 while (readChannel.read(readBuffer) != -1) {
 readBuffer.flip();
 cipher.doFinal(readBuffer, writeBuffer);
 writeBuffer.flip();
 writeChannel.write(writeBuffer);
 readBuffer.clear();
 writeBuffer.clear();
 }
 }

 static void f(String inFileString, String fileString, int mode) {
 FileOutputStream fos = null;
 FileSystem fs = FileSystems.getDefault();
 Path fp = fs.getPath(inFileString);

 try {
 readChannel = FileChannel.open(fp,
 EnumSet.of(StandardOpenOption.READ));
 fos = new FileOutputStream(fileString);
 writeChannel = Channels.newChannel(fos);
 run(mode);
 } catch (Exception e) {
 e.printStackTrace();
 }
 }

 public static void main(String[] args) {
 f("C:\\test.txt", "C:\\des.txt", Cipher.ENCRYPT_MODE);
 System.out.println("Encrypted.");
 f("C:\\des.txt", "C:\\undes.txt", Cipher.DECRYPT_MODE);
 System.out.println("Decrypted.");
 }

}


У меня была аналогичная проблема, но она была решена после того, как я сделал поля -passin и -passout разными (в моей команде pkcs12 -export),

licensed under cc by-sa 3.0 with attribution.