1 19 20 package com.maverick.crypto.publickey; 21 22 import com.maverick.crypto.digests.SHA1Digest; 23 import java.math.BigInteger ; 24 import com.maverick.crypto.security.SecureRandom; 25 26 public final class Dsa { 27 28 public static byte[] sign(BigInteger x, 29 BigInteger p, BigInteger q, BigInteger g, 30 byte[] data) { 31 32 BigInteger hM = new BigInteger (1, data); 33 34 hM = hM.mod(q); 35 36 BigInteger r = g.modPow(x, p).mod(q); 37 BigInteger s = x.modInverse(q).multiply(hM.add(x.multiply(r))).mod(q); 38 39 int dataSz = data.length; 40 byte[] signature = new byte[dataSz * 2]; 41 byte[] tmp; 42 43 tmp = unsignedBigIntToBytes(r, dataSz); 44 System.arraycopy(tmp, 0, signature, 0, dataSz); 45 46 tmp = unsignedBigIntToBytes(s, dataSz); 47 System.arraycopy(tmp, 0, signature, dataSz, dataSz); 48 49 return signature; 50 } 51 52 public static boolean verify(BigInteger y, 53 BigInteger p, BigInteger q, BigInteger g, 54 byte[] signature, byte[] data) { 55 int dataSz = signature.length / 2; 56 byte[] ra = new byte[dataSz]; 57 byte[] sa = new byte[dataSz]; 58 59 System.arraycopy(signature, 0, ra, 0, dataSz); 60 System.arraycopy(signature, dataSz, sa, 0, dataSz); 61 62 BigInteger hM = new BigInteger (1, data); 63 BigInteger r = new BigInteger (1, ra); 64 BigInteger s = new BigInteger (1, sa); 65 66 hM = hM.mod(q); 67 68 BigInteger w = s.modInverse(q); 69 BigInteger u1 = hM.multiply(w).mod(q); 70 BigInteger u2 = r.multiply(w).mod(q); 71 BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); 72 73 return (v.compareTo(r) == 0); 74 } 75 76 private static byte[] unsignedBigIntToBytes(BigInteger bi, int size) { 77 byte[] tmp = bi.toByteArray(); 78 byte[] tmp2 = null; 79 if (tmp.length > size) { 80 tmp2 = new byte[size]; 81 System.arraycopy(tmp, tmp.length - size, tmp2, 0, size); 82 } 83 else if (tmp.length < size) { 84 tmp2 = new byte[size]; 85 System.arraycopy(tmp, 0, tmp2, size - tmp.length, tmp.length); 86 } 87 else { 88 tmp2 = tmp; 89 } 90 return tmp2; 91 } 92 93 public static BigInteger generatePublicKey(BigInteger g, BigInteger p, 94 BigInteger x) { 95 return g.modPow(x, p); 96 } 97 98 public static DsaPrivateKey generateKey(int bits, SecureRandom rnd) { 99 100 BigInteger p, q, g, x, y; 101 BigInteger ZERO = BigInteger.valueOf(0); 102 DSAParametersGenerator dsaParams = new DSAParametersGenerator(); 103 dsaParams.init(bits, 80, rnd); 104 105 DSAParameters dsa = dsaParams.generateParameters(); 106 107 q = dsa.getQ(); 108 p = dsa.getP(); 109 g = dsa.getG(); 110 111 do { 112 x = new BigInteger (160, rnd); 113 } 114 while (x.equals(ZERO) || x.compareTo(q) >= 0); 115 116 y = g.modPow(x, p); 120 121 return new DsaPrivateKey(p, q, g, x); 122 } 123 124 } 125 126 129 class DSAParametersGenerator { 130 private int size; 131 private int certainty; 132 private SecureRandom random; 133 134 private static BigInteger ONE = BigInteger.valueOf(1); 135 private static BigInteger TWO = BigInteger.valueOf(2); 136 137 144 public void init( 145 int size, 146 int certainty, 147 SecureRandom random) { 148 this.size = size; 149 this.certainty = certainty; 150 this.random = random; 151 } 152 153 158 private void add( 159 byte[] a, 160 byte[] b, 161 int value) { 162 int x = (b[b.length - 1] & 0xff) + value; 163 164 a[b.length - 1] = (byte) x; 165 x >>>= 8; 166 167 for (int i = b.length - 2; i >= 0; i--) { 168 x += (b[i] & 0xff); 169 a[i] = (byte) x; 170 x >>>= 8; 171 } 172 } 173 174 180 public DSAParameters generateParameters() { 181 byte[] seed = new byte[20]; 182 byte[] part1 = new byte[20]; 183 byte[] part2 = new byte[20]; 184 byte[] u = new byte[20]; 185 SHA1Digest sha1 = new SHA1Digest(); 186 int n = (size - 1) / 160; 187 byte[] w = new byte[size / 8]; 188 189 BigInteger q = null, p = null, g = null; 190 int counter = 0; 191 boolean primesFound = false; 192 193 while (!primesFound) { 194 do { 195 random.nextBytes(seed); 196 197 sha1.update(seed, 0, seed.length); 198 199 sha1.doFinal(part1, 0); 200 201 System.arraycopy(seed, 0, part2, 0, seed.length); 202 203 add(part2, seed, 1); 204 205 sha1.update(part2, 0, part2.length); 206 207 sha1.doFinal(part2, 0); 208 209 for (int i = 0; i != u.length; i++) { 210 u[i] = (byte) (part1[i] ^ part2[i]); 211 } 212 213 u[0] |= (byte) 0x80; 214 u[19] |= (byte) 0x01; 215 216 q = new BigInteger (1, u); 217 } 218 while (!q.isProbablePrime(certainty)); 219 220 counter = 0; 221 222 int offset = 2; 223 224 while (counter < 4096) { 225 for (int k = 0; k < n; k++) { 226 add(part1, seed, offset + k); 227 sha1.update(part1, 0, part1.length); 228 sha1.doFinal(part1, 0); 229 System.arraycopy(part1, 0, w, w.length - (k + 1) * part1.length, 230 part1.length); 231 } 232 233 add(part1, seed, offset + n); 234 sha1.update(part1, 0, part1.length); 235 sha1.doFinal(part1, 0); 236 System.arraycopy(part1, part1.length - ( (w.length - (n) * part1.length)), 237 w, 0, w.length - n * part1.length); 238 239 w[0] |= (byte) 0x80; 240 241 BigInteger x = new BigInteger (1, w); 242 243 BigInteger c = x.mod(q.multiply(TWO)); 244 245 p = x.subtract(c.subtract(ONE)); 246 247 if (p.testBit(size - 1)) { 248 if (p.isProbablePrime(certainty)) { 249 primesFound = true; 250 break; 251 } 252 } 253 254 counter += 1; 255 offset += n + 1; 256 } 257 } 258 259 BigInteger pMinusOneOverQ = p.subtract(ONE).divide(q); 263 264 for (; ; ) { 265 BigInteger h = new BigInteger (size, random); 266 if (h.compareTo(ONE) <= 0 || h.compareTo(p.subtract(ONE)) >= 0) { 267 continue; 268 } 269 270 g = h.modPow(pMinusOneOverQ, p); 271 if (g.compareTo(ONE) <= 0) { 272 continue; 273 } 274 275 break; 276 } 277 278 return new DSAParameters(p, q, g, new DSAValidationParameters(seed, counter)); 279 } 280 } 281 282 class DSAParameters 283 284 { 285 private BigInteger g; 286 private BigInteger q; 287 private BigInteger p; 288 private DSAValidationParameters validation; 289 290 public DSAParameters( 291 BigInteger p, 292 BigInteger q, 293 BigInteger g) { 294 this.g = g; 295 this.p = p; 296 this.q = q; 297 } 298 299 public DSAParameters( 300 BigInteger p, 301 BigInteger q, 302 BigInteger g, 303 DSAValidationParameters params) { 304 this.g = g; 305 this.p = p; 306 this.q = q; 307 this.validation = params; 308 } 309 310 public BigInteger getP() { 311 return p; 312 } 313 314 public BigInteger getQ() { 315 return q; 316 } 317 318 public BigInteger getG() { 319 return g; 320 } 321 322 public DSAValidationParameters getValidationParameters() { 323 return validation; 324 } 325 326 public boolean equals( 327 Object obj) { 328 if (! (obj instanceof DSAParameters)) { 329 return false; 330 } 331 332 DSAParameters pm = (DSAParameters) obj; 333 334 return (pm.getP().equals(p) && pm.getQ().equals(q) && pm.getG().equals(g)); 335 } 336 } 337 338 class DSAValidationParameters { 339 private byte[] seed; 340 private int counter; 341 342 public DSAValidationParameters( 343 byte[] seed, 344 int counter) { 345 this.seed = seed; 346 this.counter = counter; 347 } 348 349 public int getCounter() { 350 return counter; 351 } 352 353 public byte[] getSeed() { 354 return seed; 355 } 356 357 public boolean equals( 358 Object o) { 359 if (o == null || ! (o instanceof DSAValidationParameters)) { 360 return false; 361 } 362 363 DSAValidationParameters other = (DSAValidationParameters) o; 364 365 if (other.counter != this.counter) { 366 return false; 367 } 368 369 if (other.seed.length != this.seed.length) { 370 return false; 371 } 372 373 for (int i = 0; i != other.seed.length; i++) { 374 if (other.seed[i] != this.seed[i]) { 375 return false; 376 } 377 } 378 379 return true; 380 } 381 } 382 | Popular Tags |