-1

当我从 CipherInputStream 读取对象时,为什么会收到无效的流标头错误?(编辑:可能是由于重复使用 Cipher 对象?,下面包含的示例代码的新版本已经解决了这个问题。)

我的程序正在尝试从使用 CipherInputStream 作为源(来自文件)的 ObjectInputStream 中读取,即:

文件 -> 解密流 -> 反序列化 -> 对象

运行时错误是:

java.io.StreamCorruptedException: invalid stream header: 73720019

下面列出的示例程序中的 write 方法使用普通 FileOutputStreamCipherOutputStream 写入文件,因此我们有 2 个文件要检查。read 方法同样尝试读取这两个文件。纯文件的写入和读取没有问题,但是加密文件会引发异常。如果您查看纯文件的前 8 个字节,您可以看到它们是:

 0000000 254 355  \0 005   s   r  \0 031   j   a   v   a   x   .   c   r

          ac  ed  00  05  73  72  00  19  6a  61  76  61  78  2e  63  72

其中“ac ed 00 05”对应于 ObjectStream Magic 和版本(即标题):https ://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

但是异常报告的“损坏”标头对应于标头之后的四个字节:73 72 00 19!

在我看来,CipherInputStream 正在正确解密流,但消耗或跳过标头本身并从字节 5 开始传送数据。

这是错误的输出:

    跑:
    读取对象(普通):测试
    readTest 中的异常:
    java.io.StreamCorruptedException:无效的流标头:73720019
    构建成功(总时间:0 秒)

这是代码:

    包加密对象流示例;

    导入java.io.*;
    导入java.security.*;
    导入 javax.crypto.*;
    导入静态 javax.crypto.Cipher.*;
    导入 javax.crypto.spec.*;

    公共类 EncryptedObjectStreamExample {
        静态布尔密码=真;
        static final String fn = "C:/Temp/object.";
        静态最终字节[] keyBytes = "MySecretPass1234".getBytes();
        static final byte[] iv = "initialvector".getBytes();
        静态字符串 testObject = "测试";
        密码 c;
        算法参数 ap;
        IvParameterSpec ivp;
        键 k;

        公共 EncryptedObjectStreamExample() {
            尝试 {
                c = Cipher.getInstance("AES/CBC/PKCS5Padding");
                ap = 算法参数.getInstance("AES");
                ivp = new IvParameterSpec(iv);
                ap.init(ivp);
                k = new SecretKeySpec(keyBytes, "AES");
            } 捕捉(异常前){
                System.err.println("构造函数失败:\n" + ex);
                System.exit(1);
            }
        }

        公共无效写测试(){
            // 对象 -> 序列化 -> 密码流 -> 文件
            尝试 {
                c.init(ENCRYPT_MODE, k, ap);
                输出流 ostrp = new FileOutputStream(fn+"p");
                OutputStream ostrx = new CipherOutputStream(new FileOutputStream(fn+"x"),c);
                尝试(ObjectOutputStream oos = new ObjectOutputStream(ostrp)){
                    oos.writeObject(new SealedObject(testObject, c));
                }
                尝试 (ObjectOutputStream oos = new ObjectOutputStream(ostrx)) {
                    oos.writeObject(new SealedObject(testObject, c));
                }
            } 捕捉(异常 e){
                System.err.println("writeTest 异常:\n" + e);
            }
        }

        私人无效读取测试(){
            // 文件 -> 解密流 -> 反序列化 -> 对象
            尝试 {
                c.init(DECRYPT_MODE, k, ap);
                InputStream istrp = new FileInputStream("C:/Temp/object.p");
                InputStream istrx = new CipherInputStream(new FileInputStream("C:/Temp/object.x"),c);
                尝试 (ObjectInputStream ois = new ObjectInputStream(istrp)) {
                    字符串结果 = (String) (((SealedObject) ois.readObject()).getObject(c));
                    System.out.println("读取对象(普通):" + result);
                }
                尝试 (ObjectInputStream ois = new ObjectInputStream(istrx)) {
                    字符串结果 = (String) (((SealedObject) ois.readObject()).getObject(c));
                    System.out.println("读取对象(加密):" + result);
                }
            } 捕捉(异常 e){
                System.err.println("readTest 中的异常:\n" + e);
            }
        }

        公共静态无效主要(字符串[]参数){
            EncryptedObjectStreamExample eos = new EncryptedObjectStreamExample();
            eos.writeTest();
            eos.readTest();
        }
    }

编辑:我重新调整了代码,以便我对流和 Seal 操作使用不同的 Cipher 对象:x.sealdob 和 x.iostream

修改后的代码现在可以正常运行,两个文件都被写入和读取,没有错误:

这是新的(好的)输出:

    跑:
    读取对象(普通):测试
    读取对象(加密):测试
    构建成功(总时间:0 秒)

这是更新的代码(有效):

    包加密对象流示例;

    导入java.io.*;
    导入java.security.*;
    导入 java.security.spec.InvalidParameterSpecException;
    导入 java.util.logging.Level;
    导入 java.util.logging.Logger;
    导入 javax.crypto.*;
    导入静态 javax.crypto.Cipher.*;
    导入 javax.crypto.spec.*;

    公共类 EncryptedObjectStreamCipherX {

    静态布尔密码=真;
    静态最终字符串 FN = "C:/Temp/object.";
    静态最终字节[] keyBytes = "MySecretPass1234".getBytes();
    static final byte[] IV = "initialvector".getBytes();
    静态字符串 testObject = "测试";
    西弗X;
    键 k;

    私人类西弗{

        算法参数 ap;
        密码iostream,sealedob;
        静态最终字符串 ALG = "AES";

        西弗(){
            尝试 {
                iostream = Cipher.getInstance(ALG + "/CBC/PKCS5Padding");
                sealob = Cipher.getInstance(ALG + "/CBC/PKCS5Padding");
                ap = 算法参数.getInstance(ALG);
                ap.init(new IvParameterSpec(IV));
                k = new SecretKeySpec(keyBytes, "AES");
            } 捕捉(NoSuchPaddingException | InvalidParameterSpecException | NoSuchAlgorithmException ex){
                Logger.getLogger(EncryptedObjectStreamCipherX.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        无效加密模式(){
            尝试 {
                iostream.init(ENCRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
                sealob.init(ENCRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
            } 捕捉(InvalidKeyException | InvalidAlgorithmParameterException ex){
                Logger.getLogger(EncryptedObjectStreamCipherX.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        无效解密模式(){
            尝试 {
                iostream.init(DECRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
                sealob.init(DECRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
            } 捕捉(InvalidKeyException | InvalidAlgorithmParameterException ex){
                Logger.getLogger(EncryptedObjectStreamCipherX.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    公共 EncryptedObjectStreamCipherX() {
        尝试 {
            x = 新 Xipher();

        } 捕捉(异常前){
            System.err.println("构造函数失败:\n" + ex);
            System.exit(1);
        }
    }

    公共无效写测试(){
        // 对象 -> 序列化 -> 密码流 -> 文件
        尝试 {
            x.encryptMode();
            输出流 ostrp = new FileOutputStream(FN + "p");
            OutputStream ostrx = new CipherOutputStream(new FileOutputStream(FN + "x"), x.iostream);
            尝试(ObjectOutputStream oos = new ObjectOutputStream(ostrp)){
                oos.writeObject(new SealedObject(testObject, x.sealedob));
            }
            尝试 (ObjectOutputStream oos = new ObjectOutputStream(ostrx)) {
                oos.writeObject(new SealedObject(testObject, x.sealedob));
            }
        } 捕捉(异常 e){
            System.err.println("writeTest 异常:\n" + e);
        }
    }

    私人无效读取测试(){
        // 文件 -> 解密流 -> 反序列化 -> 对象
        尝试 {
            x.decryptMode();
            InputStream istrp = new FileInputStream("C:/Temp/object.p");
            InputStream istrx = new CipherInputStream(new FileInputStream("C:/Temp/object.x"), x.iostream);
            尝试 (ObjectInputStream ois = new ObjectInputStream(istrp)) {
                字符串结果 = (String) (((SealedObject) ois.readObject()).getObject(x.sealedob));
                System.out.println("读取对象(普通):" + result);
            }
            尝试 (ObjectInputStream ois = new ObjectInputStream(istrx)) {
                字符串结果 = (String) (((SealedObject) ois.readObject()).getObject(x.sealedob));
                System.out.println("读取对象(加密):" + result);
            }
        } 捕捉(异常 e){
            System.err.println("readTest 中的异常:\n" + e);
        }
    }

    公共静态无效主要(字符串[]参数){
        EncryptedObjectStreamCipherX eos = new EncryptedObjectStreamCipherX();
        eos.writeTest();
        eos.readTest();
    }
    }

4

1 回答 1

0

这没有意义。您不需要CipherSealedObject如果您考虑所有这些相对于 的实际执行顺序,Cipher您会发现它在写入和读取之间是不对称的。

丢失 SealedObject,或丢失Cipher流。

于 2018-03-20T11:13:33.340 回答