5690N/A/*
5690N/A * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
5690N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5690N/A *
5690N/A * This code is free software; you can redistribute it and/or modify it
5690N/A * under the terms of the GNU General Public License version 2 only, as
5690N/A * published by the Free Software Foundation. Oracle designates this
5690N/A * particular file as subject to the "Classpath" exception as provided
5690N/A * by Oracle in the LICENSE file that accompanied this code.
5690N/A *
5690N/A * This code is distributed in the hope that it will be useful, but WITHOUT
5690N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
5690N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
5690N/A * version 2 for more details (a copy is included in the LICENSE file that
5690N/A * accompanied this code).
5690N/A *
5690N/A * You should have received a copy of the GNU General Public License version
5690N/A * 2 along with this work; if not, write to the Free Software Foundation,
5690N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
5690N/A *
5690N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
5690N/A * or visit www.oracle.com if you need additional information or have any
5690N/A * questions.
5690N/A */
5690N/A
5690N/Apackage sun.security.util;
5690N/A
5690N/Aimport java.security.Key;
5690N/Aimport java.security.PrivilegedAction;
5690N/Aimport java.security.AccessController;
5690N/Aimport java.security.InvalidKeyException;
5690N/Aimport java.security.interfaces.ECKey;
5690N/Aimport java.security.interfaces.RSAKey;
5690N/Aimport java.security.interfaces.DSAKey;
5690N/Aimport java.security.spec.KeySpec;
5690N/Aimport javax.crypto.SecretKey;
5690N/Aimport javax.crypto.interfaces.DHKey;
5690N/Aimport javax.crypto.interfaces.DHPublicKey;
5690N/Aimport javax.crypto.spec.DHParameterSpec;
5690N/Aimport javax.crypto.spec.DHPublicKeySpec;
5690N/Aimport java.math.BigInteger;
5690N/A
5690N/A/**
5690N/A * A utility class to get key length, valiate keys, etc.
5690N/A */
5690N/Apublic final class KeyUtil {
5690N/A
5690N/A /**
5690N/A * Returns the key size of the given key object in bits.
5690N/A *
5690N/A * @param key the key object, cannot be null
5690N/A * @return the key size of the given key object in bits, or -1 if the
5690N/A * key size is not accessible
5690N/A */
5690N/A public static final int getKeySize(Key key) {
5690N/A int size = -1;
5690N/A
5690N/A if (key instanceof Length) {
5690N/A try {
5690N/A Length ruler = (Length)key;
5690N/A size = ruler.length();
5690N/A } catch (UnsupportedOperationException usoe) {
5690N/A // ignore the exception
5690N/A }
5690N/A
5690N/A if (size >= 0) {
5690N/A return size;
5690N/A }
5690N/A }
5690N/A
5690N/A // try to parse the length from key specification
5690N/A if (key instanceof SecretKey) {
5690N/A SecretKey sk = (SecretKey)key;
5690N/A String format = sk.getFormat();
5690N/A if ("RAW".equals(format) && sk.getEncoded() != null) {
5690N/A size = (sk.getEncoded().length * 8);
5690N/A } // Otherwise, it may be a unextractable key of PKCS#11, or
5690N/A // a key we are not able to handle.
5690N/A } else if (key instanceof RSAKey) {
5690N/A RSAKey pubk = (RSAKey)key;
5690N/A size = pubk.getModulus().bitLength();
5690N/A } else if (key instanceof ECKey) {
5690N/A ECKey pubk = (ECKey)key;
5690N/A size = pubk.getParams().getOrder().bitLength();
5690N/A } else if (key instanceof DSAKey) {
5690N/A DSAKey pubk = (DSAKey)key;
5690N/A size = pubk.getParams().getP().bitLength();
5690N/A } else if (key instanceof DHKey) {
5690N/A DHKey pubk = (DHKey)key;
5690N/A size = pubk.getParams().getP().bitLength();
5690N/A } // Otherwise, it may be a unextractable key of PKCS#11, or
5690N/A // a key we are not able to handle.
5690N/A
5690N/A return size;
5690N/A }
5690N/A
5690N/A /**
5690N/A * Returns whether the key is valid or not.
5690N/A * <P>
5690N/A * Note that this method is only apply to DHPublicKey at present.
5690N/A *
5690N/A * @param publicKey
5690N/A * the key object, cannot be null
5690N/A *
5690N/A * @throws NullPointerException if {@code publicKey} is null
5690N/A * @throws InvalidKeyException if {@code publicKey} is invalid
5690N/A */
5690N/A public static final void validate(Key key)
5690N/A throws InvalidKeyException {
5690N/A if (key == null) {
5690N/A throw new NullPointerException(
5690N/A "The key to be validated cannot be null");
5690N/A }
5690N/A
5690N/A if (key instanceof DHPublicKey) {
5690N/A validateDHPublicKey((DHPublicKey)key);
5690N/A }
5690N/A }
5690N/A
5690N/A
5690N/A /**
5690N/A * Returns whether the key spec is valid or not.
5690N/A * <P>
5690N/A * Note that this method is only apply to DHPublicKeySpec at present.
5690N/A *
5690N/A * @param keySpec
5690N/A * the key spec object, cannot be null
5690N/A *
5690N/A * @throws NullPointerException if {@code keySpec} is null
5690N/A * @throws InvalidKeyException if {@code keySpec} is invalid
5690N/A */
5690N/A public static final void validate(KeySpec keySpec)
5690N/A throws InvalidKeyException {
5690N/A if (keySpec == null) {
5690N/A throw new NullPointerException(
5690N/A "The key spec to be validated cannot be null");
5690N/A }
5690N/A
5690N/A if (keySpec instanceof DHPublicKeySpec) {
5690N/A validateDHPublicKey((DHPublicKeySpec)keySpec);
5690N/A }
5690N/A }
5690N/A
5690N/A /**
5690N/A * Returns whether the specified provider is Oracle provider or not.
5690N/A * <P>
5690N/A * Note that this method is only apply to SunJCE and SunPKCS11 at present.
5690N/A *
5690N/A * @param providerName
5690N/A * the provider name
5690N/A * @return true if, and only if, the provider of the specified
5690N/A * {@code providerName} is Oracle provider
5690N/A */
5690N/A public static final boolean isOracleJCEProvider(String providerName) {
5690N/A return providerName != null && (providerName.equals("SunJCE") ||
5690N/A providerName.startsWith("SunPKCS11"));
5690N/A }
5690N/A
5690N/A /**
5690N/A * Returns whether the Diffie-Hellman public key is valid or not.
5690N/A *
5690N/A * Per RFC 2631 and NIST SP800-56A, the following algorithm is used to
5690N/A * validate Diffie-Hellman public keys:
5690N/A * 1. Verify that y lies within the interval [2,p-1]. If it does not,
5690N/A * the key is invalid.
5690N/A * 2. Compute y^q mod p. If the result == 1, the key is valid.
5690N/A * Otherwise the key is invalid.
5690N/A */
5690N/A private static void validateDHPublicKey(DHPublicKey publicKey)
5690N/A throws InvalidKeyException {
5690N/A DHParameterSpec paramSpec = publicKey.getParams();
5690N/A
5690N/A BigInteger p = paramSpec.getP();
5690N/A BigInteger g = paramSpec.getG();
5690N/A BigInteger y = publicKey.getY();
5690N/A
5690N/A validateDHPublicKey(p, g, y);
5690N/A }
5690N/A
5690N/A private static void validateDHPublicKey(DHPublicKeySpec publicKeySpec)
5690N/A throws InvalidKeyException {
5690N/A validateDHPublicKey(publicKeySpec.getP(),
5690N/A publicKeySpec.getG(), publicKeySpec.getY());
5690N/A }
5690N/A
5690N/A private static void validateDHPublicKey(BigInteger p,
5690N/A BigInteger g, BigInteger y) throws InvalidKeyException {
5690N/A
5690N/A // For better interoperability, the interval is limited to [2, p-2].
5690N/A BigInteger leftOpen = BigInteger.ONE;
5690N/A BigInteger rightOpen = p.subtract(BigInteger.ONE);
5690N/A if (y.compareTo(leftOpen) <= 0) {
5690N/A throw new InvalidKeyException(
5690N/A "Diffie-Hellman public key is too small");
5690N/A }
5690N/A if (y.compareTo(rightOpen) >= 0) {
5690N/A throw new InvalidKeyException(
5690N/A "Diffie-Hellman public key is too large");
5690N/A }
5690N/A
5690N/A // Don't bother to check against the y^q mod p if safe primes are used.
5690N/A }
5690N/A}
5690N/A