2012-10-09 30 views
13

Thực ra, tôi đã tìm kiếm rất nhiều từ internet và trong stackoverflow quá cho điều này,khối cuối cùng đầy đủ với CipherInputStream/CipherOutputStream, ngay cả với đệm AES/CBC/PKCS5Padding

Ban đầu tôi không sử dụng padding trong mã hóa và giải mã của tôi,

Nhưng Cuối cùng tôi có giải pháp từ đây

https://stackoverflow.com/a/10775577/1115788

và tôi cập nhật mã của tôi với đệm như AES/CBC/PKCS5Padding và lỗi tương tự là Comi ng, và khối cuối cùng không được giải mã ...

Tôi đang làm việc về vấn đề này cho hai ngày cuối cùng, nhưng không có giải pháp tìm thấy

Mã Crypter tôi:

package mani.droid.browsedropbox; 

import java.io.FileInputStream; 
import java.io.IOException; 
import java.io.InputStream; 
import java.io.OutputStream; 
import java.math.BigInteger; 
import java.security.InvalidAlgorithmParameterException; 
import java.security.InvalidKeyException; 
import java.security.NoSuchAlgorithmException; 
import javax.crypto.Cipher; 
import javax.crypto.CipherInputStream; 
import javax.crypto.CipherOutputStream; 
import javax.crypto.NoSuchPaddingException; 
import javax.crypto.SecretKey; 
import javax.crypto.spec.IvParameterSpec; 
import javax.crypto.spec.SecretKeySpec; 

public class Crypter { 

    Cipher encipher; 
    Cipher decipher; 
CipherInputStream cis; 
CipherOutputStream cos; 
FileInputStream fis; 
byte[] ivbytes = new byte[]{(byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e',                       (byte)'f', (byte)'g', (byte)'h', (byte)'i', (byte)'j', (byte)'k', (byte)'l', (byte)'m',  (byte)'n', (byte)'o', (byte)'p'}; 
    IvParameterSpec iv = new IvParameterSpec(ivbytes); 

public boolean enCrypt(String key, InputStream is, OutputStream os) 
{ 
    try { 
     byte[] encoded = new BigInteger(key, 16).toByteArray(); 
     SecretKey seckey = new SecretKeySpec(encoded, "AES"); 
     encipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); 
     encipher.init(Cipher.ENCRYPT_MODE, seckey, iv); 
     cis = new CipherInputStream(is, encipher); 
     copyByte(cis, os); 
     return true; 
    } 
    catch (InvalidKeyException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (InvalidAlgorithmParameterException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return false; 
} 

public boolean deCrypt(String key, InputStream is, OutputStream os) 
{ 
    try { 
     byte[] encoded = new BigInteger(key, 16).toByteArray(); 
     SecretKey seckey = new SecretKeySpec(encoded, "AES"); 
     encipher = Cipher.getInstance("AES/CBC/PKCS7Padding"); 
     encipher.init(Cipher.DECRYPT_MODE, seckey, iv); 
     cos = new CipherOutputStream(os, encipher); 
     copyByte(is, cos); 
     //cos.close(); 
     return true; 
    } 
    catch (InvalidKeyException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchAlgorithmException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (NoSuchPaddingException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } catch (InvalidAlgorithmParameterException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    return false; 
} 

public void copyByte(InputStream is, OutputStream os) throws IOException 
{ 
    byte[] buf = new byte[8192]; 
    int numbytes; 
    while((numbytes = is.read(buf)) != -1) 
    { 
     os.write(buf, 0, numbytes); 
     os.flush(); 
    } 
    os.close(); 
    is.close(); 
} 
} 
+0

là phần còn lại của văn bản mật mã ok? Các dòng đầu vào mã hóa có thói quen đáng ghét là xáo trộn các ngoại lệ bên dưới thảm, bao gồm cả các trường hợp của 'BadPaddingException'. –

+0

Kiểm tra kích thước của tệp (?) Bạn đang viết và đảm bảo rằng bạn đang viết mọi thứ đúng cách. –

+0

@owlstead phần còn lại của mật mã là giải mã hoàn hảo, nhưng khối cuối cùng bị thiếu, để kiểm tra mã tôi đã in 'numbytes' trong' copyByte', kết quả là khi mã hóa, tất cả các khối được đọc, 16 bit ngay cả lần cuối cùng chưa hoàn thành khối, nhưng để giải mã giá trị khối cuối cùng không phải là 16, nhỏ hơn 16 ..., Vì vậy, tôi đoán là, đệm của nó với null hoặc 0, do đó, khối đọc đầy đủ tại thời điểm mã hóa, vì vậy kích thước tệp được mã hóa giống như kích thước tệp gốc của tôi không nhiều trong 16byte ... – Mani

Trả lời

7

Cuối cùng tôi đã trả lời cho câu hỏi của riêng tôi, với thử và sai trên thực tế đây xung đột là tôi đặt Padding trong encipher = Cipher.getInstance("AES/CBC/PKCS7Padding");

và Set IV với một số giá trị .....,

Cuối cùng tôi nhận được trả lời chỉ mới thay thế các thuật toán

Từ:

AES/CBC/PKCS7Paddinng

Để:

AES/CFB8/NoPadding

và nó hoạt động như quyến rũ ...., Vì vậy, Tôi đề nghị câu trả lời này cho những người khác đấu tranh với vấn đề này, nếu bạn giải quyết được vấn đề, hãy đề cập đến đây cho những người khác ...

+0

Bạn có hiểu tại sao không? Hoặc có một liên kết đến một lời giải thích ?? –

+0

Tôi cũng phải đối mặt với vấn đề này, tôi cần liên kết để hiểu, cách vấn đề này được giải quyết. Bạn có thể cho tôi liên kết không? – Karthick

+0

Một số thuật toán như DESeade hoặc AES yêu cầu dữ liệu đầu vào có kích thước tốt, thường là bội số của Cipher.getBlockSize(). Bạn có thể lựa chọn giữa việc sử dụng một phần đệm trong algortihm ("PKCS7Paddinng") hoặc không sử dụng một padding, và tùy thuộc vào bạn để chắc chắn rằng dữ liệu đầu vào có kích thước tốt. Nếu không, bạn sẽ nhận được ngoại lệ đó. –

11

Tôi đã có cùng một vấn đề. Giải pháp được chấp nhận hoạt động vì bạn đã sử dụng chế độ mã hóa không yêu cầu đệm, nhưng đây không phải là cách các vấn đề liên quan đến mật mã được cố định.

Theo CipherOutputStream documentation, bạn phải gọi phương thức close() để hoàn tất mã hóa đúng (tức là, khối đệm được thêm).

Phương pháp này gọi là phương pháp doFinal của gói gọn đối tượng mật mã, gây ra bất kỳ byte đệm bằng mật mã đóng gói để được xử lý. Kết quả được viết ra bằng cách gọi phương thức tuôn ra của luồng đầu ra này.

Phương pháp này đặt lại đối tượng mật mã đóng gói về trạng thái ban đầu và gọi phương thức đóng của luồng đầu ra cơ bản.

Nếu bạn muốn bảo toàn OutputStream mở ngay cả sau khi gọi phương thức CipherOutputStream.close(), bạn có thể bọc OutputStream vào luồng không đóng nó.Ví dụ:

public class NotClosingOutputStream extends OutputStream { 
    private final OutputStream os; 

    public NotClosingOutputStream(OutputStream os) { 
    this.os = os; 
    } 

    @Override 
    public void write(int b) throws IOException { 
    os.write(b); 
    } 

    @Override 
    public void close() throws IOException { 
    // not closing the stream. 
    } 

    @Override 
    public void flush() throws IOException { 
    os.flush(); 
    } 

    @Override 
    public void write(byte[] buffer, int offset, int count) throws IOException { 
    os.write(buffer, offset, count); 
    } 

    @Override 
    public void write(byte[] buffer) throws IOException { 
    os.write(buffer); 
    } 
} 

Sau đó, bạn có thể sử dụng:

... 
cos = new CipherOutputStream(new NotClosingOutputStream(os), encipher); 
copyByte(is, cos); 
cos.close(); 
... 

Lưu ý dòng os không nhận được khép kín, bạn cần phải làm điều đó một mình khi thích hợp.

+1

Đây phải là câu trả lời được chấp nhận cho câu hỏi cho độc giả trong tương lai. – Robert

0

Tôi đã thấy CipherInputStream không thành công với các vấn đề về đệm. Hành vi này thay đổi trên các phiên bản khác nhau của JVM. Ví dụ 7u55 32 bit mã của tôi làm việc tốt, 7u55 64 bit cùng một mã không thành công ... và tôi cũng thấy thất bại trên các JVM 32 bit sau này. Cách giải quyết là sử dụng các phương thức mảng byte và tránh CipherInputStream.

0

Không chắc chắn nếu điều này có liên quan đến vấn đề của OP, nhưng điều này có thể giúp một ai đó.

Khi bạn nhiều lần nhận được rằng java.io.IOException: last block incomplete in decryptionbất kể những gì bạn thay đổi, kiểm tra nếu bạn vẫn đang sử dụng các tập tin từ một số chạy trước. Nếu mã kiểm tra đọc/ghi của bạn gắn thêm vào tệp đó, bạn sẽ luôn nhận được ngoại lệ đó - trừ khi bạn xóa tệp hỏng mà bạn ghi vào.

0

Sử dụng CipherInputStream với đệm là có thể, chuyển sang NoPadding là giải pháp thay thế nhưng không phải là giải pháp.

Đệm được áp dụng khi CipherInputStream đến cuối luồng. Điểm quan trọng là bạn phải gọi phương thức read() của CipherInputStream ít nhất hai lần để nhận được tất cả dữ liệu.

Ví dụ sau đây cho thấy đọc một CipherInputStream với padding:

public static void test() throws Exception { 
    Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 

    SecureRandom rnd = new SecureRandom(); 
    byte[] keyData = new byte[16]; 
    byte[] iv = new byte[16]; 
    rnd.nextBytes(keyData); 
    rnd.nextBytes(iv); 
    SecretKeySpec key = new SecretKeySpec(keyData, "AES"); 

    cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); 

    ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 
    CipherOutputStream out = new CipherOutputStream(buffer, cipher); 

    byte[] plain = "Test1234567890_ABCDEFG".getBytes(); 
    out.write(plain); 
    out.flush(); 
    out.close(); 
    byte[] encrypted = buffer.toByteArray(); 
    System.out.println("Plaintext length: " + plain.length); 
    System.out.println("Padding length : " + (cipher.getBlockSize() - (plain.length % cipher.getBlockSize()))); 
    System.out.println("Cipher length : " + encrypted.length); 

    cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); 
    CipherInputStream in = new CipherInputStream(new ByteArrayInputStream(encrypted), cipher); 
    buffer = new ByteArrayOutputStream(); 
    byte[] b = new byte[100]; 
    int read; 
    while ((read = in.read(b)) >= 0) { 
     buffer.write(b, 0, read); 
    } 
    in.close(); 

    // prints Test1234567890_ABCDEFG 
    System.out.println(new String(buffer.toByteArray())); 
} 
Các vấn đề liên quan