4

我想实现一个OutputStream可以产生MessageDigests. 同样,我已经在这里InputStream实现了它,它可以正常工作并且可以扩展。FilterInputStream

问题是这样的:如果我正在扩展FilterOutputStream,校验和不匹配。如果我使用FileOutputStream它可以正常工作(尽管这不是我想要使用的流,因为我希望它比这更通用一些)。

public class MultipleDigestOutputStream extends FilterOutputStream
{

    public static final String[] DEFAULT_ALGORITHMS = { EncryptionConstants.ALGORITHM_MD5,
                                                        EncryptionConstants.ALGORITHM_SHA1 };

    private Map<String, MessageDigest> digests = new LinkedHashMap<>();

    private File file;


    public MultipleDigestOutputStream(File file, OutputStream os)
            throws NoSuchAlgorithmException, FileNotFoundException
    {
        this(file, os, DEFAULT_ALGORITHMS);
    }

    public MultipleDigestOutputStream(File file, OutputStream os, String[] algorithms)
            throws NoSuchAlgorithmException, FileNotFoundException
    {
        // super(file); // If extending FileOutputStream
        super(os);

        this.file = file;

        for (String algorithm : algorithms)
        {
            addAlgorithm(algorithm);
        }
    }

    public void addAlgorithm(String algorithm)
            throws NoSuchAlgorithmException
    {
        MessageDigest digest = MessageDigest.getInstance(algorithm);

        digests.put(algorithm, digest);
    }

    public MessageDigest getMessageDigest(String algorithm)
    {
        return digests.get(algorithm);
    }

    public Map<String, MessageDigest> getDigests()
    {
        return digests;
    }

    public String getMessageDigestAsHexadecimalString(String algorithm)
    {
        return MessageDigestUtils.convertToHexadecimalString(getMessageDigest(algorithm));
    }

    public void setDigests(Map<String, MessageDigest> digests)
    {
        this.digests = digests;
    }


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

        System.out.println("write(int b)");

        for (Map.Entry entry : digests.entrySet())
        {
            int p = b & 0xFF;
            byte b1 = (byte) p;

            MessageDigest digest = (MessageDigest) entry.getValue();
            digest.update(b1);
        }
    }

    @Override
    public void write(byte[] b)
            throws IOException
    {
        super.write(b);

        for (Map.Entry entry : digests.entrySet())
        {
            MessageDigest digest = (MessageDigest) entry.getValue();
            digest.update(b);
        }
    }

    @Override
    public void write(byte[] b, int off, int len)
            throws IOException
    {
        super.write(b, off, len);

        for (Map.Entry entry : digests.entrySet())
        {
            MessageDigest digest = (MessageDigest) entry.getValue();
            digest.update(b, off, len);
        }
    }

    @Override
    public void close()
            throws IOException
    {
        super.close();
    }

}

我的测试用例(断言的校验和已经用md5sumand进行了检查sha1sum):

public class MultipleDigestOutputStreamTest
{


    @Before
    public void setUp()
            throws Exception
    {
        File dir = new File("target/test-resources");
        if (!dir.exists())
        {
            //noinspection ResultOfMethodCallIgnored
            dir.mkdirs();
        }
    }

    @Test
    public void testWrite()
            throws IOException,
                   NoSuchAlgorithmException
    {
        String s = "This is a test.";

        File file = new File("target/test-resources/metadata.xml");

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        MultipleDigestOutputStream mdos = new MultipleDigestOutputStream(file, baos);

        mdos.write(s.getBytes());
        mdos.flush();

        final String md5 = mdos.getMessageDigestAsHexadecimalString("MD5");
        final String sha1 = mdos.getMessageDigestAsHexadecimalString("SHA-1");

        Assert.assertEquals("Incorrect MD5 sum!", "120ea8a25e5d487bf68b5f7096440019", md5);
        Assert.assertEquals("Incorrect SHA-1 sum!", "afa6c8b3a2fae95785dc7d9685a57835d703ac88", sha1);

        System.out.println("MD5:  " + md5);
        System.out.println("SHA1: " + sha1);
    }

}

您能否告知可能是什么问题以及如何解决?提前谢谢了!

4

2 回答 2

3

如果您使用的是 java 7 或更高版本,则可以使用DigestOutputstream

更新

您可以实现抽象MessageDigest类来包装多个MessageDigest实例。

一些代码

    import java.security.DigestException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;


    public class DigestWrapper extends MessageDigest
    {
        private final MessageDigest md5;
        private final MessageDigest sha1;

        // some methods missing.
        // I just implemeted them throwing a RuntimeException.

        public DigestWrapper() throws NoSuchAlgorithmException
        {
            super(null);
            sha1 = MessageDigest.getInstance("sha-1");
            md5 = MessageDigest.getInstance("md5");
        }

        public byte[] getMD5Digest()
        {
            return md5.digest();
        }

        public byte[] getSHA1Digest()
        {
            return sha1.digest();
        }

        @Override
        public int digest(byte[] buf, int offset, int len) throws DigestException
        {
            md5.digest(buf, offset, len);
            sha1.digest(buf, offset, len);
            return 0;
        }

        @Override
        public byte[] digest(byte[] input)
        {
            md5.digest(input);
            sha1.digest(input);
            return input;
        }

        @Override
        public void reset()
        {
            md5.reset();
            sha1.reset();
        }

        @Override
        public void update(byte input)
        {
            md5.update(input);
            sha1.update(input);
        }

        @Override
        public void update(byte[] input, int offset, int len)
        {
            md5.update(input, offset, len);
            sha1.update(input, offset, len);
        }

        @Override
        public void update(byte[] input)
        {
            md5.update(input);
            sha1.update(input);
        }

    }
于 2015-04-07T17:01:01.340 回答
1

我在 Github 上创建了一个项目,其中包含我对MultipleDigestInputStreamand实现。MultipleDigestOutputStream

要检查如何使用代码,请查看以下测试:

让我知道,如果有足够的兴趣,我可以将其发布并发布到 Maven Central。

于 2016-10-14T11:15:26.687 回答