Path: blob/master/src/java.base/share/classes/sun/security/rsa/RSAKeyPairGenerator.java
41159 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.rsa;2627import java.math.BigInteger;2829import java.security.*;30import java.security.spec.AlgorithmParameterSpec;31import java.security.spec.RSAKeyGenParameterSpec;3233import static java.math.BigInteger.*;34import sun.security.jca.JCAUtil;35import sun.security.rsa.RSAUtil.KeyType;3637import static sun.security.util.SecurityProviderConstants.DEF_RSA_KEY_SIZE;38import static sun.security.util.SecurityProviderConstants.DEF_RSASSA_PSS_KEY_SIZE;3940/**41* RSA keypair generation. Standard algorithm, minimum key length 512 bit.42* We generate two random primes until we find two where phi is relative43* prime to the public exponent. Default exponent is 65537. It has only bit 044* and bit 4 set, which makes it particularly efficient.45*46* @since 1.547* @author Andreas Sterbenz48*/49public abstract class RSAKeyPairGenerator extends KeyPairGeneratorSpi {5051private static final BigInteger SQRT_2048;52private static final BigInteger SQRT_3072;53private static final BigInteger SQRT_4096;5455static {56SQRT_2048 = TWO.pow(2047).sqrt();57SQRT_3072 = TWO.pow(3071).sqrt();58SQRT_4096 = TWO.pow(4095).sqrt();59}6061// public exponent to use62private BigInteger publicExponent;6364// size of the key to generate, >= RSAKeyFactory.MIN_MODLEN65private int keySize;6667private final KeyType type;68private AlgorithmParameterSpec keyParams;6970// PRNG to use71private SecureRandom random;7273// whether to generate key pairs following the new guidelines from74// FIPS 186-4 and later75private boolean useNew;7677RSAKeyPairGenerator(KeyType type, int defKeySize) {78this.type = type;79// initialize to default in case the app does not call initialize()80initialize(defKeySize, null);81}8283// initialize the generator. See JCA doc84public void initialize(int keySize, SecureRandom random) {85try {86initialize(new RSAKeyGenParameterSpec(keySize,87RSAKeyGenParameterSpec.F4), random);88} catch (InvalidAlgorithmParameterException iape) {89throw new InvalidParameterException(iape.getMessage());90}91}9293// second initialize method. See JCA doc.94public void initialize(AlgorithmParameterSpec params, SecureRandom random)95throws InvalidAlgorithmParameterException {96if (params instanceof RSAKeyGenParameterSpec == false) {97throw new InvalidAlgorithmParameterException98("Params must be instance of RSAKeyGenParameterSpec");99}100101RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec)params;102int tmpKeySize = rsaSpec.getKeysize();103BigInteger tmpPubExp = rsaSpec.getPublicExponent();104AlgorithmParameterSpec tmpParams = rsaSpec.getKeyParams();105106// use the new approach for even key sizes >= 2048 AND when the107// public exponent is within FIPS valid range108boolean useNew = (tmpKeySize >= 2048 && ((tmpKeySize & 1) == 0));109110if (tmpPubExp == null) {111tmpPubExp = RSAKeyGenParameterSpec.F4;112} else {113if (!tmpPubExp.testBit(0)) {114throw new InvalidAlgorithmParameterException115("Public exponent must be an odd number");116}117// current impl checks that F0 <= e < 2^keysize118// vs FIPS 186-4 checks that F4 <= e < 2^256119// for backward compatibility, we keep the same checks120BigInteger minValue = RSAKeyGenParameterSpec.F0;121int maxBitLength = tmpKeySize;122if (tmpPubExp.compareTo(RSAKeyGenParameterSpec.F0) < 0) {123throw new InvalidAlgorithmParameterException124("Public exponent must be " + minValue + " or larger");125}126if (tmpPubExp.bitLength() > maxBitLength) {127throw new InvalidAlgorithmParameterException128("Public exponent must be no longer than " +129maxBitLength + " bits");130}131useNew &= ((tmpPubExp.compareTo(RSAKeyGenParameterSpec.F4) >= 0) &&132(tmpPubExp.bitLength() < 256));133}134135// do not allow unreasonably large key sizes, probably user error136try {137RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPubExp, 512,13864 * 1024);139} catch (InvalidKeyException e) {140throw new InvalidAlgorithmParameterException(141"Invalid key sizes", e);142}143144try {145this.keyParams = RSAUtil.checkParamsAgainstType(type, tmpParams);146} catch (ProviderException e) {147throw new InvalidAlgorithmParameterException(148"Invalid key parameters", e);149}150151this.keySize = tmpKeySize;152this.publicExponent = tmpPubExp;153this.random = (random == null? JCAUtil.getSecureRandom() : random);154this.useNew = useNew;155}156157// FIPS 186-4 B.3.3 / FIPS 186-5 A.1.3158// Generation of Random Primes that are Probably Prime159public KeyPair generateKeyPair() {160BigInteger e = publicExponent;161BigInteger minValue = (useNew? getSqrt(keySize) : ZERO);162int lp = (keySize + 1) >> 1;;163int lq = keySize - lp;164int pqDiffSize = lp - 100;165166while (true) {167BigInteger p = null;168BigInteger q = null;169170int i = 0;171while (i++ < 10*lp) {172BigInteger tmpP = BigInteger.probablePrime(lp, random);173if ((!useNew || tmpP.compareTo(minValue) == 1) &&174isRelativePrime(e, tmpP.subtract(ONE))) {175p = tmpP;176break;177}178}179if (p == null) {180throw new ProviderException("Cannot find prime P");181}182183i = 0;184185while (i++ < 20*lq) {186BigInteger tmpQ = BigInteger.probablePrime(lq, random);187188if ((!useNew || tmpQ.compareTo(minValue) == 1) &&189(p.subtract(tmpQ).abs().compareTo190(TWO.pow(pqDiffSize)) == 1) &&191isRelativePrime(e, tmpQ.subtract(ONE))) {192q = tmpQ;193break;194}195}196if (q == null) {197throw new ProviderException("Cannot find prime Q");198}199200BigInteger n = p.multiply(q);201if (n.bitLength() != keySize) {202// regenerate P, Q if n is not the right length; should203// never happen for the new case but check it anyway204continue;205}206207KeyPair kp = createKeyPair(type, keyParams, n, e, p, q);208// done, return the generated keypair;209if (kp != null) return kp;210}211}212213private static BigInteger getSqrt(int keySize) {214BigInteger sqrt = null;215switch (keySize) {216case 2048:217sqrt = SQRT_2048;218break;219case 3072:220sqrt = SQRT_3072;221break;222case 4096:223sqrt = SQRT_4096;224break;225default:226sqrt = TWO.pow(keySize-1).sqrt();227}228return sqrt;229}230231private static boolean isRelativePrime(BigInteger e, BigInteger bi) {232// optimize for common known public exponent prime values233if (e.compareTo(RSAKeyGenParameterSpec.F4) == 0 ||234e.compareTo(RSAKeyGenParameterSpec.F0) == 0) {235return !bi.mod(e).equals(ZERO);236} else {237return e.gcd(bi).equals(ONE);238}239}240241private static KeyPair createKeyPair(KeyType type,242AlgorithmParameterSpec keyParams,243BigInteger n, BigInteger e, BigInteger p, BigInteger q) {244// phi = (p - 1) * (q - 1) must be relative prime to e245// otherwise RSA just won't work ;-)246BigInteger p1 = p.subtract(ONE);247BigInteger q1 = q.subtract(ONE);248BigInteger phi = p1.multiply(q1);249250BigInteger gcd = p1.gcd(q1);251BigInteger lcm = (gcd.equals(ONE)? phi : phi.divide(gcd));252253BigInteger d = e.modInverse(lcm);254255if (d.compareTo(TWO.pow(p.bitLength())) != 1) {256return null;257}258259// 1st prime exponent pe = d mod (p - 1)260BigInteger pe = d.mod(p1);261// 2nd prime exponent qe = d mod (q - 1)262BigInteger qe = d.mod(q1);263// crt coefficient coeff is the inverse of q mod p264BigInteger coeff = q.modInverse(p);265266try {267PublicKey publicKey = new RSAPublicKeyImpl(type, keyParams, n, e);268PrivateKey privateKey = new RSAPrivateCrtKeyImpl(269type, keyParams, n, e, d, p, q, pe, qe, coeff);270return new KeyPair(publicKey, privateKey);271} catch (InvalidKeyException exc) {272// invalid key exception only thrown for keys < 512 bit,273// will not happen here274throw new RuntimeException(exc);275}276}277278public static final class Legacy extends RSAKeyPairGenerator {279public Legacy() {280super(KeyType.RSA, DEF_RSA_KEY_SIZE);281}282}283284public static final class PSS extends RSAKeyPairGenerator {285public PSS() {286super(KeyType.PSS, DEF_RSASSA_PSS_KEY_SIZE);287}288}289}290291292