/** * Check the length of an RSA key modulus/exponent to make sure it is not too short or long. Some * impls have their own min and max key sizes that may or may not match with a system defined * value. * * @param modulusLen the bit length of the RSA modulus. * @param exponent the RSA exponent * @param minModulusLen if > 0, check to see if modulusLen is at least this long, otherwise * unused. * @param maxModulusLen caller will allow this max number of bits. Allow the smaller of the * system-defined maximum and this param. * @throws InvalidKeyException if any of the values are unacceptable. */ public static void checkKeyLengths( int modulusLen, BigInteger exponent, int minModulusLen, int maxModulusLen) throws InvalidKeyException { if ((minModulusLen > 0) && (modulusLen < (minModulusLen))) { throw new InvalidKeyException("RSA keys must be at least " + minModulusLen + " bits long"); } // Even though our policy file may allow this, we don't want // either value (mod/exp) to be too big. int maxLen = Math.min(maxModulusLen, MAX_MODLEN); // If a RSAPrivateKey/RSAPublicKey, make sure the // modulus len isn't too big. if (modulusLen > maxLen) { throw new InvalidKeyException("RSA keys must be no longer than " + maxLen + " bits"); } // If a RSAPublicKey, make sure the exponent isn't too big. if (restrictExpLen && (exponent != null) && (modulusLen > MAX_MODLEN_RESTRICT_EXP) && (exponent.bitLength() > MAX_RESTRICTED_EXPLEN)) { throw new InvalidKeyException( "RSA exponents can be no longer than " + MAX_RESTRICTED_EXPLEN + " bits " + " if modulus is greater than " + MAX_MODLEN_RESTRICT_EXP + " bits"); } }
// Uses supplied hash algorithm static byte[] derive( char[] chars, byte[] salt, int ic, int n, int type, String hashAlgo, int blockLength) { // Add in trailing NULL terminator. Special case: // no terminator if password is "\0". int length = chars.length * 2; if (length == 2 && chars[0] == 0) { chars = new char[0]; length = 0; } else { length += 2; } byte[] passwd = new byte[length]; for (int i = 0, j = 0; i < chars.length; i++, j += 2) { passwd[j] = (byte) ((chars[i] >>> 8) & 0xFF); passwd[j + 1] = (byte) (chars[i] & 0xFF); } byte[] key = new byte[n]; try { MessageDigest sha = MessageDigest.getInstance(hashAlgo); int v = blockLength; int u = sha.getDigestLength(); int c = roundup(n, u) / u; byte[] D = new byte[v]; int s = roundup(salt.length, v); int p = roundup(passwd.length, v); byte[] I = new byte[s + p]; Arrays.fill(D, (byte) type); concat(salt, I, 0, s); concat(passwd, I, s, p); byte[] Ai; byte[] B = new byte[v]; byte[] tmp = new byte[v]; int i = 0; for (; ; i++, n -= u) { sha.update(D); sha.update(I); Ai = sha.digest(); for (int r = 1; r < ic; r++) Ai = sha.digest(Ai); System.arraycopy(Ai, 0, key, u * i, Math.min(n, u)); if (i + 1 == c) break; concat(Ai, B, 0, B.length); BigInteger B1; B1 = new BigInteger(1, B).add(BigInteger.ONE); for (int j = 0; j < I.length; j += v) { BigInteger Ij; int trunc; if (tmp.length != v) tmp = new byte[v]; System.arraycopy(I, j, tmp, 0, v); Ij = new BigInteger(1, tmp); Ij = Ij.add(B1); tmp = Ij.toByteArray(); trunc = tmp.length - v; if (trunc >= 0) { System.arraycopy(tmp, trunc, I, j, v); } else if (trunc < 0) { Arrays.fill(I, j, j + (-trunc), (byte) 0); System.arraycopy(tmp, 0, I, j + (-trunc), tmp.length); } } } } catch (Exception e) { throw new RuntimeException("internal error: " + e); } return key; }