首页 文章

无法从密码输入流反序列化密封对象[重复]

提问于
浏览
-1

这个问题与以下内容完全相同:

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

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

文件 - > DeCipher Stream - > DeSerialize - > Object

运行时错误是:

java.io.StreamCorruptedException: invalid stream header: 73720019

下面列出的示例程序中的write方法使用普通的FileOutputStream and 将文件写为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

"ac ed 00 05"对应于ObjectStream Magic和Version(即 Headers ):https://docs.oracle.com/javase/8/docs/platform/serialization/spec/protocol.html

但是Exception报告的'corrupt' Headers 对应于 Headers 后面的四个字节: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操作使用不同的Cipher对象: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 回答

  • 0

    这不需要 Cipher 流和 SealedObject ,如果你考虑所有这些相对于 Cipher 的实际执行顺序,你会发现它在写和读之间不对称 .

    丢失 SealedObject ,或丢失 Cipher 流 .

相关问题