1package org.bouncycastle.operator.jcajce;
2
3import java.io.IOException;
4import java.io.OutputStream;
5import java.security.GeneralSecurityException;
6import java.security.PrivateKey;
7import java.security.Provider;
8import java.security.SecureRandom;
9import java.security.Signature;
10import java.security.SignatureException;
11
12import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
13import org.bouncycastle.jcajce.util.DefaultJcaJceHelper;
14import org.bouncycastle.jcajce.util.NamedJcaJceHelper;
15import org.bouncycastle.jcajce.util.ProviderJcaJceHelper;
16import org.bouncycastle.operator.ContentSigner;
17import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
18import org.bouncycastle.operator.OperatorCreationException;
19import org.bouncycastle.operator.OperatorStreamException;
20import org.bouncycastle.operator.RuntimeOperatorException;
21
22public class JcaContentSignerBuilder
23{
24    private OperatorHelper helper = new OperatorHelper(new DefaultJcaJceHelper());
25    private SecureRandom random;
26    private String signatureAlgorithm;
27    private AlgorithmIdentifier sigAlgId;
28
29    public JcaContentSignerBuilder(String signatureAlgorithm)
30    {
31        this.signatureAlgorithm = signatureAlgorithm;
32        this.sigAlgId = new DefaultSignatureAlgorithmIdentifierFinder().find(signatureAlgorithm);
33    }
34
35    public JcaContentSignerBuilder setProvider(Provider provider)
36    {
37        this.helper = new OperatorHelper(new ProviderJcaJceHelper(provider));
38
39        return this;
40    }
41
42    public JcaContentSignerBuilder setProvider(String providerName)
43    {
44        this.helper = new OperatorHelper(new NamedJcaJceHelper(providerName));
45
46        return this;
47    }
48
49    public JcaContentSignerBuilder setSecureRandom(SecureRandom random)
50    {
51        this.random = random;
52
53        return this;
54    }
55
56    public ContentSigner build(PrivateKey privateKey)
57        throws OperatorCreationException
58    {
59        try
60        {
61            final Signature sig = helper.createSignature(sigAlgId);
62            final AlgorithmIdentifier signatureAlgId = sigAlgId;
63
64            if (random != null)
65            {
66                sig.initSign(privateKey, random);
67            }
68            else
69            {
70                sig.initSign(privateKey);
71            }
72
73            return new ContentSigner()
74            {
75                private SignatureOutputStream stream = new SignatureOutputStream(sig);
76
77                public AlgorithmIdentifier getAlgorithmIdentifier()
78                {
79                    return signatureAlgId;
80                }
81
82                public OutputStream getOutputStream()
83                {
84                    return stream;
85                }
86
87                public byte[] getSignature()
88                {
89                    try
90                    {
91                        return stream.getSignature();
92                    }
93                    catch (SignatureException e)
94                    {
95                        throw new RuntimeOperatorException("exception obtaining signature: " + e.getMessage(), e);
96                    }
97                }
98            };
99        }
100        catch (GeneralSecurityException e)
101        {
102            throw new OperatorCreationException("cannot create signer: " + e.getMessage(), e);
103        }
104    }
105
106    private class SignatureOutputStream
107        extends OutputStream
108    {
109        private Signature sig;
110
111        SignatureOutputStream(Signature sig)
112        {
113            this.sig = sig;
114        }
115
116        public void write(byte[] bytes, int off, int len)
117            throws IOException
118        {
119            try
120            {
121                sig.update(bytes, off, len);
122            }
123            catch (SignatureException e)
124            {
125                throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
126            }
127        }
128
129        public void write(byte[] bytes)
130            throws IOException
131        {
132            try
133            {
134                sig.update(bytes);
135            }
136            catch (SignatureException e)
137            {
138                throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
139            }
140        }
141
142        public void write(int b)
143            throws IOException
144        {
145            try
146            {
147                sig.update((byte)b);
148            }
149            catch (SignatureException e)
150            {
151                throw new OperatorStreamException("exception in content signer: " + e.getMessage(), e);
152            }
153        }
154
155        byte[] getSignature()
156            throws SignatureException
157        {
158            return sig.sign();
159        }
160    }
161}
162