blob: 2958e00817cf0b276e7c499f40322bb8dfe0e9af [file] [log] [blame]
The Android Open Source Projectadc854b2009-03-03 19:28:47 -08001/*
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 org.apache.harmony.security.provider.crypto;
19
20import java.math.BigInteger;
Jesse Wilson7365de12010-08-11 15:21:19 -070021import java.security.InvalidKeyException;
22import java.security.InvalidParameterException;
23import java.security.MessageDigest;
24import java.security.NoSuchAlgorithmException;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080025import java.security.PrivateKey;
26import java.security.PublicKey;
27import java.security.SecureRandom;
28import java.security.Signature;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080029import java.security.SignatureException;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080030import java.security.interfaces.DSAKey;
Jesse Wilson7365de12010-08-11 15:21:19 -070031import java.security.interfaces.DSAParams;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080032import java.security.interfaces.DSAPrivateKey;
33import java.security.interfaces.DSAPublicKey;
34
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080035public class SHA1withDSA_SignatureImpl extends Signature {
36
37 private MessageDigest msgDigest;
38
39 private DSAKey dsaKey;
40
41 /**
42 * The solo constructor.
43 */
44 public SHA1withDSA_SignatureImpl() throws NoSuchAlgorithmException {
45
Elliott Hughesf33eae72010-05-13 12:36:25 -070046 super("SHA1withDSA");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080047
Elliott Hughesf33eae72010-05-13 12:36:25 -070048 msgDigest = MessageDigest.getInstance("SHA1");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080049 }
50
51 /**
52 * Deprecated method.
53 *
54 * @return
55 * null
56 */
57 protected Object engineGetParameter(String param)
58 throws InvalidParameterException {
59 if (param == null) {
Kenny Root86acc042012-09-12 10:32:58 -070060 throw new NullPointerException("param == null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080061 }
62 return null;
63 }
64
65 /**
Elliott Hughesf33eae72010-05-13 12:36:25 -070066 * Initializes this signature object with PrivateKey object
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080067 * passed as argument to the method.
68 *
69 * @params
70 * privateKey DSAPrivateKey object
71 * @throws
72 * InvalidKeyException if privateKey is not DSAPrivateKey object
73 */
74 protected void engineInitSign(PrivateKey privateKey)
75 throws InvalidKeyException {
76
77 DSAParams params;
78
79 // parameters and private key
Elliott Hughes2f9e4682009-10-09 17:21:46 -070080 BigInteger p, q, x;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080081
82 int n;
83
84 if (privateKey == null || !(privateKey instanceof DSAPrivateKey)) {
Elliott Hughes897538a2010-05-28 20:00:47 -070085 throw new InvalidKeyException();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080086 }
87
88 params = ((DSAPrivateKey) privateKey).getParams();
89 p = params.getP();
90 q = params.getQ();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080091 x = ((DSAPrivateKey) privateKey).getX();
92
93 // checks described in DSA standard
94 n = p.bitLength();
Elliott Hughes897538a2010-05-28 20:00:47 -070095 if (p.compareTo(BigInteger.valueOf(1)) != 1 || n < 512 || n > 1024 || (n & 077) != 0) {
96 throw new InvalidKeyException("bad p");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -080097 }
98 if (q.signum() != 1 && q.bitLength() != 160) {
Elliott Hughes897538a2010-05-28 20:00:47 -070099 throw new InvalidKeyException("bad q");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800100 }
101 if (x.signum() != 1 || x.compareTo(q) != -1) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700102 throw new InvalidKeyException("x <= 0 || x >= q");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800103 }
104
105 dsaKey = (DSAKey) privateKey;
106
107 msgDigest.reset();
108 }
109
110 /**
Elliott Hughesf33eae72010-05-13 12:36:25 -0700111 * Initializes this signature object with PublicKey object
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800112 * passed as argument to the method.
113 *
114 * @params
115 * publicKey DSAPublicKey object
116 * @throws
117 * InvalidKeyException if publicKey is not DSAPublicKey object
118 */
119 protected void engineInitVerify(PublicKey publicKey)
120 throws InvalidKeyException {
121
122 // parameters and public key
Elliott Hughes2f9e4682009-10-09 17:21:46 -0700123 BigInteger p, q, y;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800124
125 int n1;
126
127 if (publicKey == null || !(publicKey instanceof DSAPublicKey)) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700128 throw new InvalidKeyException("publicKey is not an instance of DSAPublicKey");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800129 }
130
131 DSAParams params = ((DSAPublicKey) publicKey).getParams();
132 p = params.getP();
133 q = params.getQ();
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800134 y = ((DSAPublicKey) publicKey).getY();
135
136 // checks described in DSA standard
137 n1 = p.bitLength();
Elliott Hughes897538a2010-05-28 20:00:47 -0700138 if (p.compareTo(BigInteger.valueOf(1)) != 1 || n1 < 512 || n1 > 1024 || (n1 & 077) != 0) {
139 throw new InvalidKeyException("bad p");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800140 }
141 if (q.signum() != 1 || q.bitLength() != 160) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700142 throw new InvalidKeyException("bad q");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800143 }
144 if (y.signum() != 1) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700145 throw new InvalidKeyException("y <= 0");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800146 }
147
148 dsaKey = (DSAKey) publicKey;
149
150 msgDigest.reset();
151 }
152
153 /*
154 * Deprecated method.
155 *
156 * @throws
157 * InvalidParameterException
158 */
Elliott Hughes897538a2010-05-28 20:00:47 -0700159 protected void engineSetParameter(String param, Object value) throws InvalidParameterException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800160 if (param == null) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700161 throw new NullPointerException("param == null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800162 }
Elliott Hughes897538a2010-05-28 20:00:47 -0700163 throw new InvalidParameterException("invalid parameter for this engine");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800164 }
165
166 /**
Elliott Hughesf33eae72010-05-13 12:36:25 -0700167 * Returns signature bytes as byte array containing
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800168 * ASN1 representation for two BigInteger objects
169 * which is SEQUENCE of two INTEGERS.
170 * Length of sequence varies from less than 46 to 48.
171 *
Elliott Hughesf33eae72010-05-13 12:36:25 -0700172 * Resets object to the state it was in
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800173 * when previous call to either "initSign" method was called.
174 *
175 * @return
176 * byte array containing signature in ASN1 representation
177 * @throws
Elliott Hughesf33eae72010-05-13 12:36:25 -0700178 * SignatureException if object's state is not SIGN or
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800179 * signature algorithm cannot process data
180 */
181
182 protected byte[] engineSign() throws SignatureException {
183
184 // names of below BigIntegers are the same as they are defined in DSA standard
185 BigInteger r = null;
186 BigInteger s = null;
187 BigInteger k = null;
188
189 // parameters and private key
190 BigInteger p, q, g, x;
191
Elliott Hughesf33eae72010-05-13 12:36:25 -0700192 // BigInteger for message digest
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800193 BigInteger digestBI;
194
195 // various byte array being used in computing signature
Elliott Hughes171dc202010-09-02 11:06:55 -0700196 byte[] randomBytes;
197 byte[] rBytes;
198 byte[] sBytes;
199 byte[] signature;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800200
201 int n, n1, n2;
202
203 DSAParams params;
204
205 if (appRandom == null) {
206 appRandom = new SecureRandom();
207 }
208
209 params = dsaKey.getParams();
210 p = params.getP();
211 q = params.getQ();
212 g = params.getG();
213 x = ((DSAPrivateKey) dsaKey).getX();
214
215 // forming signature according algorithm described in chapter 5 of DSA standard
216
217 digestBI = new BigInteger(1, msgDigest.digest());
218
219 randomBytes = new byte[20];
220
221 for (;;) {
222
223 appRandom.nextBytes(randomBytes);
224
225 k = new BigInteger(1, randomBytes);
226 if (k.compareTo(q) != -1) {
227 continue;
228 }
229 r = g.modPow(k, p).mod(q);
230 if (r.signum() == 0) {
231 continue;
232 }
233
234 s = k.modInverse(q).multiply(digestBI.add(x.multiply(r)).mod(q))
235 .mod(q);
236
237 if (s.signum() != 0) {
238 break;
239 }
240 }
241
242 // forming signature's ASN1 representation which is SEQUENCE of two INTEGERs
Elliott Hughesf33eae72010-05-13 12:36:25 -0700243 //
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800244 rBytes = r.toByteArray();
245 n1 = rBytes.length;
246 if ((rBytes[0] & 0x80) != 0) {
247 n1++;
248 }
249 sBytes = s.toByteArray();
250 n2 = sBytes.length;
251 if ((sBytes[0] & 0x80) != 0) {
252 n2++;
253 }
254
255 signature = new byte[6 + n1 + n2]; // 48 is max. possible length of signature
256 signature[0] = (byte) 0x30; // ASN1 SEQUENCE tag
257 signature[1] = (byte) (4 + n1 + n2); // total length of two INTEGERs
258 signature[2] = (byte) 0x02; // ASN1 INTEGER tag
259 signature[3] = (byte) n1; // length of r
260 signature[4 + n1] = (byte) 0x02; // ASN1 INTEGER tag
261 signature[5 + n1] = (byte) n2; // length of s
262
263 if (n1 == rBytes.length) {
264 n = 4;
265 } else {
266 n = 5;
267 }
268 System.arraycopy(rBytes, 0, signature, n, rBytes.length);
269
270 if (n2 == sBytes.length) {
271 n = 6 + n1;
272 } else {
273 n = 7 + n1;
274 }
275 System.arraycopy(sBytes, 0, signature, n, sBytes.length);
276
277 return signature;
278 }
279
280 /**
281 * Updates data to sign or to verify.
282 *
283 * @params
284 * b byte to update
285 * @throws
286 * SignatureException if object was not initialized for signing or verifying
287 */
288 protected void engineUpdate(byte b) throws SignatureException {
289
290 msgDigest.update(b);
291 }
292
293 /**
294 * Updates data to sign or to verify.
295 *
296 * @params
297 * b byte array containing bytes to update
298 * @params
299 * off offset in byte array to start from
300 * @params
301 * len number of bytes to use for updating
302 * @throws
303 * SignatureException if object was not initialized for signing or verifying
304 */
305 protected void engineUpdate(byte[] b, int off, int len)
306 throws SignatureException {
307
308 msgDigest.update(b, off, len);
309 }
310
311 private boolean checkSignature(byte[] sigBytes, int offset, int length)
312 throws SignatureException {
313
314 // names of below BigIntegers are the same as they are defined in DSA standard
315 BigInteger r, s, w;
316 BigInteger u1, u2, v;
317
318 // parameters and public key
319 BigInteger p, q, g, y;
320
321 DSAParams params;
322
323 int n1, n2;
324
Elliott Hughes171dc202010-09-02 11:06:55 -0700325 byte[] bytes;
326 byte[] digest;
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800327
328 // checking up on signature's ASN1
329 try {
330 byte dummy;
331 n1 = sigBytes[offset + 3];
332 n2 = sigBytes[offset + n1 + 5];
333
334 if (sigBytes[offset + 0] != 0x30 || sigBytes[offset + 2] != 2
335 || sigBytes[offset + n1 + 4] != 2
336 || sigBytes[offset + 1] != (n1 + n2 + 4) || n1 > 21
337 || n2 > 21
338 || (length != 0 && (sigBytes[offset + 1] + 2) > length)) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700339 throw new SignatureException("signature bytes have invalid encoding");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800340 }
341
342 dummy = sigBytes[5 + n1 + n2]; // to check length of sigBytes
343 } catch (ArrayIndexOutOfBoundsException e) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700344 throw new SignatureException("bad argument: byte[] is too small");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800345 }
346
347 digest = msgDigest.digest();
348
349 bytes = new byte[n1];
350 System.arraycopy(sigBytes, offset + 4, bytes, 0, n1);
351 r = new BigInteger(bytes);
352
353 bytes = new byte[n2];
354 System.arraycopy(sigBytes, offset + 6 + n1, bytes, 0, n2);
355 s = new BigInteger(bytes);
356
357 params = dsaKey.getParams();
358 p = params.getP();
359 q = params.getQ();
360 g = params.getG();
361 y = ((DSAPublicKey) dsaKey).getY();
362
363 // forming signature according algorithm described in chapter 6 of DSA standard
364
365 if (r.signum() != 1 || r.compareTo(q) != -1 || s.signum() != 1
366 || s.compareTo(q) != -1) {
367 return false;
368 }
369
370 w = s.modInverse(q);
371
372 u1 = (new BigInteger(1, digest)).multiply(w).mod(q);
373 u2 = r.multiply(w).mod(q);
374
375 v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q);
376
377 if (v.compareTo(r) != 0) {
378 return false;
379 }
380 return true;
381 }
382
383 /**
384 * Verifies the signature bytes.
385 *
386 * @params
387 * sigBytes byte array with signature bytes to verify.
388 * @return
389 * true if signature bytes were verified, false otherwise
390 * @throws
391 * SignatureException if object's state is not VERIFY or
392 * signature format is not ASN1 representation or
393 * signature algorithm cannot process data
394 */
395 protected boolean engineVerify(byte[] sigBytes) throws SignatureException {
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800396 if (sigBytes == null) {
Elliott Hughes897538a2010-05-28 20:00:47 -0700397 throw new NullPointerException("sigBytes == null");
The Android Open Source Projectadc854b2009-03-03 19:28:47 -0800398 }
399
400 return checkSignature(sigBytes, 0, 0);
401 }
402
403 /**
404 * Verifies the signature bytes.
405 *
406 * @params
407 * sigBytes byte array with signature bytes to verify.
408 * @params
409 * offset index in sigBytes to start from
410 * @params
411 * length number of bytes allotted for signature
412 * @return
413 * true if signature bytes were verified, false otherwise
414 * @throws
415 * SignatureException if object's state is not VERIFY or
416 * signature format is not ASN1 representation or
417 * signature algorithm cannot process data
418 */
419 protected boolean engineVerify(byte[] sigBytes, int offset, int length)
420 throws SignatureException {
421 return checkSignature(sigBytes, offset, length);
422 }
423}