1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.security;
19
20import java.nio.ByteBuffer;
21import java.security.spec.AlgorithmParameterSpec;
22
23/**
24 * {@code SignatureSpi} is the <i>Service Provider Interface</i> (<b>SPI</b>)
25 * definition for {@link Signature}.
26 *
27 * @see Signature
28 */
29public abstract class SignatureSpi {
30
31    /**
32     * Implementation specific source of randomness.
33     */
34    protected SecureRandom appRandom;
35
36    /**
37     * Initializes this {@code SignatureSpi} instance for signature
38     * verification, using the public key of the identity whose signature is
39     * going to be verified.
40     *
41     * @param publicKey
42     *            the public key.
43     * @throws InvalidKeyException
44     *             if {@code publicKey} is not valid.
45     */
46    protected abstract void engineInitVerify(PublicKey publicKey)
47            throws InvalidKeyException;
48
49    /**
50     * Initializes this {@code SignatureSpi} instance for signing, using the
51     * private key of the identity whose signature is going to be generated.
52     *
53     * @param privateKey
54     *            the private key.
55     * @throws InvalidKeyException
56     *             if {@code privateKey} is not valid.
57     */
58    protected abstract void engineInitSign(PrivateKey privateKey)
59            throws InvalidKeyException;
60
61    /**
62     * Initializes this {@code SignatureSpi} instance for signing, using the
63     * private key of the identity whose signature is going to be generated and
64     * the specified source of randomness.
65     *
66     * @param privateKey
67     *            the private key.
68     * @param random
69     *            the {@code SecureRandom} to use.
70     * @throws InvalidKeyException
71     *             if {@code privateKey} is not valid.
72     */
73    protected void engineInitSign(PrivateKey privateKey, SecureRandom random)
74            throws InvalidKeyException {
75        appRandom = random;
76        engineInitSign(privateKey);
77    }
78
79    /**
80     * Updates the data to be verified or to be signed, using the specified
81     * {@code byte}.
82     *
83     * @param b
84     *            the byte to update with.
85     * @throws SignatureException
86     *             if this {@code SignatureSpi} instance is not initialized
87     *             properly.
88     */
89    protected abstract void engineUpdate(byte b) throws SignatureException;
90
91    /**
92     * Updates the data to be verified or to be signed, using the given {@code
93     * byte[]}, starting form the specified index for the specified length.
94     *
95     * @param b
96     *            the byte array to update with.
97     * @param off
98     *            the start index in {@code b} of the data.
99     * @param len
100     *            the number of bytes to use.
101     * @throws SignatureException
102     *             if this {@code SignatureSpi} instance is not initialized
103     *             properly.
104     */
105    protected abstract void engineUpdate(byte[] b, int off, int len)
106            throws SignatureException;
107
108    /**
109     * Updates the data to be verified or to be signed, using the specified
110     * {@code ByteBuffer}.
111     *
112     * @param input
113     *            the {@code ByteBuffer} to update with.
114     * @throws RuntimeException
115     *             since {@code SignatureException} is not specified for this
116     *             method it throws a {@code RuntimeException} if underlying
117     *             {@link #engineUpdate(byte[], int, int)} throws {@code
118     *             SignatureException}.
119     */
120    protected void engineUpdate(ByteBuffer input) {
121        if (!input.hasRemaining()) {
122            return;
123        }
124        byte[] tmp;
125        if (input.hasArray()) {
126            tmp = input.array();
127            int offset = input.arrayOffset();
128            int position = input.position();
129            int limit = input.limit();
130            try {
131                engineUpdate(tmp, offset + position, limit - position);
132            } catch (SignatureException e) {
133                throw new RuntimeException(e); //Wrap SignatureException
134            }
135            input.position(limit);
136        } else {
137            tmp = new byte[input.limit() - input.position()];
138            input.get(tmp);
139            try {
140                engineUpdate(tmp, 0, tmp.length);
141            } catch (SignatureException e) {
142                throw new RuntimeException(e); //Wrap SignatureException
143            }
144        }
145    }
146
147    /**
148     * Generates and returns the signature of all updated data.
149     * <p>
150     * This {@code SignatureSpi} instance is reset to the state of its last
151     * initialization for signing and thus can be used for another signature
152     * from the same identity.
153     *
154     * @return the signature of all updated data.
155     * @throws SignatureException
156     *             if this {@code SignatureSpi} instance is not initialized
157     *             properly.
158     */
159    protected abstract byte[] engineSign() throws SignatureException;
160
161    /**
162     * Generates and stores the signature of all updated data in the provided
163     * {@code byte[]} at the specified position with the specified length.
164     * <p>
165     * This {@code SignatureSpi} instance is reset to the state of its last
166     * initialization for signing and thus can be used for another signature
167     * from the same identity.
168     *
169     * @param outbuf
170     *            the buffer to store the signature.
171     * @param offset
172     *            the index of the first byte in {@code outbuf} to store.
173     * @param len
174     *            the number of bytes allocated for the signature.
175     * @return the number of bytes stored in {@code outbuf}.
176     * @throws SignatureException
177     *             if this {@code SignatureSpi} instance is not initialized
178     *             properly.
179     * @throws IllegalArgumentException
180     *             if {@code offset} or {@code len} are not valid in respect to
181     *             {@code outbuf}.
182     */
183    protected int engineSign(byte[] outbuf, int offset, int len) throws SignatureException {
184        byte[] tmp = engineSign();
185        if (tmp == null) {
186            return 0;
187        }
188        if (len < tmp.length) {
189            throw new SignatureException("The value of len parameter is less than the actual signature length");
190        }
191        if (offset < 0) {
192            throw new SignatureException("offset < 0");
193        }
194        if (offset + len > outbuf.length) {
195            throw new SignatureException("offset + len > outbuf.length");
196        }
197        System.arraycopy(tmp, 0, outbuf, offset, tmp.length);
198        return tmp.length;
199    }
200
201    /**
202     * Indicates whether the given {@code sigBytes} can be verified using the
203     * public key or a certificate of the signer.
204     * <p>
205     * This {@code SignatureSpi} instance is reset to the state of its last
206     * initialization for verifying and thus can be used to verify another
207     * signature of the same signer.
208     *
209     * @param sigBytes
210     *            the signature to verify.
211     * @return {@code true} if the signature was verified, {@code false}
212     *         otherwise.
213     * @throws SignatureException
214     *             if this {@code SignatureSpi} instance is not initialized
215     *             properly.
216     */
217    protected abstract boolean engineVerify(byte[] sigBytes)
218            throws SignatureException;
219
220    /**
221     * Indicates whether the given {@code sigBytes} starting at index {@code
222     * offset} with {@code length} bytes can be verified using the public key or
223     * a certificate of the signer.
224     * <p>
225     * This {@code SignatureSpi} instance is reset to the state of its last
226     * initialization for verifying and thus can be used to verify another
227     * signature of the same signer.
228     *
229     * @param sigBytes
230     *            the {@code byte[]} containing the signature to verify.
231     * @param offset
232     *            the start index in {@code sigBytes} of the signature
233     * @param length
234     *            the number of bytes allocated for the signature.
235     * @return {@code true} if the signature was verified, {@code false}
236     *         otherwise.
237     * @throws SignatureException
238     *             if this {@code SignatureSpi} instance is not initialized
239     *             properly.
240     * @throws IllegalArgumentException
241     *             if {@code offset} or {@code length} are not valid in respect
242     *             to {@code sigBytes}.
243     */
244    protected boolean engineVerify(byte[] sigBytes, int offset, int length)
245            throws SignatureException {
246        byte[] tmp = new byte[length];
247        System.arraycopy(sigBytes, offset, tmp, 0, length);
248        return engineVerify(tmp);
249    }
250
251    /**
252     * Sets the specified parameter to the given value.
253     *
254     * @param param
255     *            the name of the parameter.
256     * @param value
257     *            the parameter value.
258     * @throws InvalidParameterException
259     *             if the parameter is invalid, already set or is not allowed to
260     *             be changed.
261     * @deprecated Use {@link #engineSetParameter(AlgorithmParameterSpec)}
262     */
263    @Deprecated
264    protected abstract void engineSetParameter(String param, Object value)
265            throws InvalidParameterException;
266
267    /**
268     * Sets the specified {@code AlgorithmParameterSpec}.
269     *
270     * @param params
271     *            the parameter to set.
272     * @throws InvalidAlgorithmParameterException
273     *             if the parameter is invalid, already set or is not allowed to
274     *             be changed.
275     */
276    protected void engineSetParameter(AlgorithmParameterSpec params)
277            throws InvalidAlgorithmParameterException {
278        throw new UnsupportedOperationException();
279    }
280
281    /**
282     * Returns the {@code AlgorithmParameters} of this {@link SignatureSpi}
283     * instance.
284     *
285     * @return the {@code AlgorithmParameters} of this {@link SignatureSpi}
286     *         instance, maybe {@code null}.
287     */
288    protected AlgorithmParameters engineGetParameters() {
289        throw new UnsupportedOperationException();
290    }
291
292    /**
293     * Returns the value of the parameter with the specified name.
294     *
295     * @param param
296     *            the name of the requested parameter value.
297     * @return the value of the parameter with the specified name, maybe {@code
298     *         null}.
299     * @throws InvalidParameterException
300     *             if {@code param} is not a valid parameter for this {@code
301     *             SignatureSpi} or an other error occurs.
302     * @deprecated There is no generally accepted parameter naming convention.
303     */
304    @Deprecated
305    protected abstract Object engineGetParameter(String param)
306            throws InvalidParameterException;
307
308    @Override
309    public Object clone() throws CloneNotSupportedException {
310        if (this instanceof Cloneable) {
311            return super.clone();
312        }
313        throw new CloneNotSupportedException();
314    }
315}
316