有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java无法从密码输入流反序列化密封对象

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

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

文件->;解码流->;反序列化->;反对

运行时错误为:

java.io.StreamCorruptedException: invalid stream header: 73720019

下面列出的示例程序中的write方法使用普通FileOutputStream作为CipherOutputStream写入文件,因此我们有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

其中“aced0005”对应于ObjectStream和版本(即头部):https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

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

在我看来,CipherInputStream正确地解密了流,但使用或跳过了报头本身,并从字节5开始传递数据

这是错误的输出:

    run:
    Read Object (plain): Test
    Exception in readTest: 
    java.io.StreamCorruptedException: invalid stream header: 73720019
    BUILD SUCCESSFUL (total time: 0 seconds)

代码如下:


    package encryptedobjectstreamexample;

    import java.io.*;
    import java.security.*;
    import javax.crypto.*;
    import static javax.crypto.Cipher.*;
    import javax.crypto.spec.*;

    public class EncryptedObjectStreamExample {
        static boolean cipherOn = true;
        static final String fn = "C:/Temp/object.";
        static final byte[] keyBytes = "MySecretPass1234".getBytes();
        static final byte[] iv = "initialialvector".getBytes();
        static String testObject = "Test";
        Cipher c;
        AlgorithmParameters ap;
        IvParameterSpec ivp;
        Key k;

        public EncryptedObjectStreamExample() {
            try {
                c = Cipher.getInstance("AES/CBC/PKCS5Padding");
                ap = AlgorithmParameters.getInstance("AES");
                ivp = new IvParameterSpec(iv);
                ap.init(ivp);
                k = new SecretKeySpec(keyBytes, "AES");
            } catch (Exception ex) {
                System.err.println("Failed Constructor:\n" + ex);
                System.exit(1);
            }
        }

        public void writeTest() {
            // Object -> Serialize -> Cipher Stream -> File
            try {
                c.init(ENCRYPT_MODE, k, ap);
                OutputStream ostrp = new FileOutputStream(fn+"p");
                OutputStream ostrx = new CipherOutputStream(new FileOutputStream(fn+"x"),c);
                try (ObjectOutputStream oos = new ObjectOutputStream(ostrp)) {
                    oos.writeObject(new SealedObject(testObject, c));
                }
                try (ObjectOutputStream oos = new ObjectOutputStream(ostrx)) {
                    oos.writeObject(new SealedObject(testObject, c));
                }
            } catch (Exception e) {
                System.err.println("Exception in writeTest: \n" + e);
            }
        }

        private void readTest() {
            // File -> DeCipher Stream -> DeSerialize -> Object
            try {
                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);
                try (ObjectInputStream ois = new ObjectInputStream(istrp)) {
                    String result = (String) (((SealedObject) ois.readObject()).getObject(c));
                    System.out.println("Read Object (plain): " + result);
                }
                try (ObjectInputStream ois = new ObjectInputStream(istrx)) {
                    String result = (String) (((SealedObject) ois.readObject()).getObject(c));
                    System.out.println("Read Object (encrypt): " + result);
                }
            } catch (Exception e) {
                System.err.println("Exception in readTest: \n" + e);
            }
        }

        public static void main(String[] args) {
            EncryptedObjectStreamExample eos = new EncryptedObjectStreamExample();
            eos.writeTest();
            eos.readTest();
        }
    }

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

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

这是新的(良好的)输出:

    run:
    Read Object (plain): Test
    Read Object (encrypt): Test
    BUILD SUCCESSFUL (total time: 0 seconds)

以下是更新后的代码(有效):


    package encryptedobjectstreamexample;

    import java.io.*;
    import java.security.*;
    import java.security.spec.InvalidParameterSpecException;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    import javax.crypto.*;
    import static javax.crypto.Cipher.*;
    import javax.crypto.spec.*;

    public class EncryptedObjectStreamCipherX {

    static boolean cipherOn = true;
    static final String FN = "C:/Temp/object.";
    static final byte[] keyBytes = "MySecretPass1234".getBytes();
    static final byte[] IV = "initialialvector".getBytes();
    static String testObject = "Test";
    Xipher x;
    Key k;

    private class Xipher {

        AlgorithmParameters ap;
        Cipher iostream, sealedob;
        static final String ALG = "AES";

        Xipher() {
            try {
                iostream = Cipher.getInstance(ALG + "/CBC/PKCS5Padding");
                sealedob = Cipher.getInstance(ALG + "/CBC/PKCS5Padding");
                ap = AlgorithmParameters.getInstance(ALG);
                ap.init(new IvParameterSpec(IV));
                k = new SecretKeySpec(keyBytes, "AES");
            } catch (NoSuchPaddingException | InvalidParameterSpecException | NoSuchAlgorithmException ex) {
                Logger.getLogger(EncryptedObjectStreamCipherX.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        void encryptMode() {
            try {
                iostream.init(ENCRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
                sealedob.init(ENCRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
            } catch (InvalidKeyException | InvalidAlgorithmParameterException ex) {
                Logger.getLogger(EncryptedObjectStreamCipherX.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

        void decryptMode() {
            try {
                iostream.init(DECRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
                sealedob.init(DECRYPT_MODE, new SecretKeySpec(keyBytes, ALG), ap);
            } catch (InvalidKeyException | InvalidAlgorithmParameterException ex) {
                Logger.getLogger(EncryptedObjectStreamCipherX.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public EncryptedObjectStreamCipherX() {
        try {
            x = new Xipher();

        } catch (Exception ex) {
            System.err.println("Failed Constructor:\n" + ex);
            System.exit(1);
        }
    }

    public void writeTest() {
        // Object -> Serialize -> Cipher Stream -> File
        try {
            x.encryptMode();
            OutputStream ostrp = new FileOutputStream(FN + "p");
            OutputStream ostrx = new CipherOutputStream(new FileOutputStream(FN + "x"), x.iostream);
            try (ObjectOutputStream oos = new ObjectOutputStream(ostrp)) {
                oos.writeObject(new SealedObject(testObject, x.sealedob));
            }
            try (ObjectOutputStream oos = new ObjectOutputStream(ostrx)) {
                oos.writeObject(new SealedObject(testObject, x.sealedob));
            }
        } catch (Exception e) {
            System.err.println("Exception in writeTest: \n" + e);
        }
    }

    private void readTest() {
        // File -> DeCipher Stream -> DeSerialize -> Object
        try {
            x.decryptMode();
            InputStream istrp = new FileInputStream("C:/Temp/object.p");
            InputStream istrx = new CipherInputStream(new FileInputStream("C:/Temp/object.x"), x.iostream);
            try (ObjectInputStream ois = new ObjectInputStream(istrp)) {
                String result = (String) (((SealedObject) ois.readObject()).getObject(x.sealedob));
                System.out.println("Read Object (plain): " + result);
            }
            try (ObjectInputStream ois = new ObjectInputStream(istrx)) {
                String result = (String) (((SealedObject) ois.readObject()).getObject(x.sealedob));
                System.out.println("Read Object (encrypt): " + result);
            }
        } catch (Exception e) {
            System.err.println("Exception in readTest: \n" + e);
        }
    }

    public static void main(String[] args) {
        EncryptedObjectStreamCipherX eos = new EncryptedObjectStreamCipherX();
        eos.writeTest();
        eos.readTest();
    }
    }


共 (1) 个答案

  1. # 1 楼答案

    这没有道理。你不需要^ {CD1> }流 ^ {< CD2> },如果你考虑所有这些关于^ {CD1}}的实际执行顺序,你会发现它在写和读之间是不对称的。

    丢失SealedObject,或丢失Cipher