Java中是否有SignatureOutputStream(或等效的)?

时间:2011-03-23 22:03:07

标签: java cryptography

我注意到Java中有一个CipherOutputStream,但显然没有SignatureOutputStream。这是真的?我在哪里可以找到SignatureOutputStream?

1 个答案:

答案 0 :(得分:6)

以下是一个示例实现,仅供您使用。它带有测试功能(见下文)。

package de.fencing_game.paul.examples;

import java.io.*;
import java.security.*;

/**
 * This class provides an outputstream which writes everything
 * to a Signature as well as to an underlying stream.
 */
public class SignatureOutputStream
    extends OutputStream
{

    private OutputStream target;
    private Signature sig;

    /**
     * creates a new SignatureOutputStream which writes to
     * a target OutputStream and updates the Signature object.
     */
    public SignatureOutputStream(OutputStream target, Signature sig) {
        this.target = target;
        this.sig = sig;
    }

    public void write(int b)
        throws IOException
    {
        write(new byte[]{(byte)b});
    }

    public void write(byte[] b)
        throws IOException
    {
        write(b, 0, b.length);
    }

    public void write(byte[] b, int offset, int len)
        throws IOException
    {
        target.write(b, offset, len);
        try {
            sig.update(b, offset, len);
        }
        catch(SignatureException ex) {
            throw new IOException(ex);
        }
    }

    public void flush() 
        throws IOException
    {
        target.flush();
    }

    public void close() 
        throws IOException
    {
        target.close();
    }
}

以下是一些测试方法,用于说明如何使用它:

private static byte[] signData(OutputStream target,
                               PrivateKey key, String[] data)
    throws IOException, GeneralSecurityException
{
    Signature sig = Signature.getInstance("SHA1withRSA");
    sig.initSign(key);
    DataOutputStream dOut =
        new DataOutputStream(new SignatureOutputStream(target, sig));


    for(String s : data) {
        dOut.writeUTF(s);
    }
    byte[] signature = sig.sign();
    return signature;
}


private static void verify(PublicKey key, byte[] signature,
                              byte[] data)
    throws IOException, GeneralSecurityException
{
    Signature sig = Signature.getInstance("SHA1withRSA");
    sig.initVerify(key);

    ByteArrayOutputStream collector =
        new ByteArrayOutputStream(data.length);
    OutputStream checker = new SignatureOutputStream(collector, sig);
    checker.write(data);
    if(sig.verify(signature)) {
        System.err.println("Signature okay");
    }
    else {
        System.err.println("Signature falsed!");
    }
}


/**
 * a test method.
 */
public static void main(String[] params) 
    throws IOException, GeneralSecurityException
{
    if(params.length < 1) {
        params = new String[] {"Hello", "World!"};
    }

    KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA");
    KeyPair pair = gen.generateKeyPair();


    ByteArrayOutputStream arrayStream = new ByteArrayOutputStream();

    byte[] signature = signData(arrayStream, pair.getPrivate(), params);
    byte[] data = arrayStream.toByteArray();

    verify(pair.getPublic(), signature, data);

    // change one byte by one
    data[3]++;

    verify(pair.getPublic(), signature, data);

    data = arrayStream.toByteArray();

    verify(pair.getPublic(), signature, data);

    // change signature
    signature[4]++;

    verify(pair.getPublic(), signature, data);

}

main方法使用新的(随机)私钥对其命令行参数进行签名,然后使用相应的公钥对其进行检查。它再次用一点改变的数据和签名来检查它。

当然,为了检查签名,SignatureInputStream会更有用 - 你可以用同样的方式创建它。