1 /* 2 * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.security.rsa; 27 28 import java.math.BigInteger; 29 30 import java.security.*; 31 import java.security.spec.AlgorithmParameterSpec; 32 import java.security.spec.RSAKeyGenParameterSpec; 33 34 import sun.security.jca.JCAUtil; 35 import static sun.security.util.SecurityProviderConstants.DEF_RSA_KEY_SIZE; 36 37 /** 38 * RSA keypair generation. Standard algorithm, minimum key length 512 bit. 39 * We generate two random primes until we find two where phi is relative 40 * prime to the public exponent. Default exponent is 65537. It has only bit 0 41 * and bit 4 set, which makes it particularly efficient. 42 * 43 * @since 1.5 44 * @author Andreas Sterbenz 45 */ 46 public final class RSAKeyPairGenerator extends KeyPairGeneratorSpi { 47 48 // public exponent to use 49 private BigInteger publicExponent; 50 51 // size of the key to generate, >= RSAKeyFactory.MIN_MODLEN 52 private int keySize; 53 54 // PRNG to use 55 private SecureRandom random; 56 57 public RSAKeyPairGenerator() { 58 // initialize to default in case the app does not call initialize() 59 initialize(DEF_RSA_KEY_SIZE, null); 60 } 61 62 // initialize the generator. See JCA doc 63 public void initialize(int keySize, SecureRandom random) { 64 65 // do not allow unreasonably small or large key sizes, 66 // probably user error 67 try { 68 RSAKeyFactory.checkKeyLengths(keySize, RSAKeyGenParameterSpec.F4, 69 512, 64 * 1024); 70 } catch (InvalidKeyException e) { 71 throw new InvalidParameterException(e.getMessage()); 72 } 73 74 this.keySize = keySize; 75 this.random = random; 76 this.publicExponent = RSAKeyGenParameterSpec.F4; 77 } 78 79 // second initialize method. See JCA doc. 80 public void initialize(AlgorithmParameterSpec params, SecureRandom random) 81 throws InvalidAlgorithmParameterException { 82 83 if (params instanceof RSAKeyGenParameterSpec == false) { 84 throw new InvalidAlgorithmParameterException 85 ("Params must be instance of RSAKeyGenParameterSpec"); 86 } 87 88 RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec)params; 89 int tmpKeySize = rsaSpec.getKeysize(); 90 BigInteger tmpPublicExponent = rsaSpec.getPublicExponent(); 91 92 if (tmpPublicExponent == null) { 93 tmpPublicExponent = RSAKeyGenParameterSpec.F4; 94 } else { 95 if (tmpPublicExponent.compareTo(RSAKeyGenParameterSpec.F0) < 0) { 96 throw new InvalidAlgorithmParameterException 97 ("Public exponent must be 3 or larger"); 98 } 99 if (tmpPublicExponent.bitLength() > tmpKeySize) { 100 throw new InvalidAlgorithmParameterException 101 ("Public exponent must be smaller than key size"); 102 } 103 } 104 105 // do not allow unreasonably large key sizes, probably user error 106 try { 107 RSAKeyFactory.checkKeyLengths(tmpKeySize, tmpPublicExponent, 108 512, 64 * 1024); 109 } catch (InvalidKeyException e) { 110 throw new InvalidAlgorithmParameterException( 111 "Invalid key sizes", e); 112 } 113 114 this.keySize = tmpKeySize; 115 this.publicExponent = tmpPublicExponent; 116 this.random = random; 117 } 118 119 // generate the keypair. See JCA doc 120 public KeyPair generateKeyPair() { 121 // accommodate odd key sizes in case anybody wants to use them 122 int lp = (keySize + 1) >> 1; 123 int lq = keySize - lp; 124 if (random == null) { 125 random = JCAUtil.getSecureRandom(); 126 } 127 BigInteger e = publicExponent; 128 while (true) { 129 // generate two random primes of size lp/lq 130 BigInteger p = BigInteger.probablePrime(lp, random); 131 BigInteger q, n; 132 do { 133 q = BigInteger.probablePrime(lq, random); 134 // convention is for p > q 135 if (p.compareTo(q) < 0) { 136 BigInteger tmp = p; 137 p = q; 138 q = tmp; 139 } 140 // modulus n = p * q 141 n = p.multiply(q); 142 // even with correctly sized p and q, there is a chance that 143 // n will be one bit short. re-generate the smaller prime if so 144 } while (n.bitLength() < keySize); 145 146 // phi = (p - 1) * (q - 1) must be relative prime to e 147 // otherwise RSA just won't work ;-) 148 BigInteger p1 = p.subtract(BigInteger.ONE); 149 BigInteger q1 = q.subtract(BigInteger.ONE); 150 BigInteger phi = p1.multiply(q1); 151 // generate new p and q until they work. typically 152 // the first try will succeed when using F4 153 if (e.gcd(phi).equals(BigInteger.ONE) == false) { 154 continue; 155 } 156 157 // private exponent d is the inverse of e mod phi 158 BigInteger d = e.modInverse(phi); 159 160 // 1st prime exponent pe = d mod (p - 1) 161 BigInteger pe = d.mod(p1); 162 // 2nd prime exponent qe = d mod (q - 1) 163 BigInteger qe = d.mod(q1); 164 165 // crt coefficient coeff is the inverse of q mod p 166 BigInteger coeff = q.modInverse(p); 167 168 try { 169 PublicKey publicKey = new RSAPublicKeyImpl(n, e); 170 PrivateKey privateKey = 171 new RSAPrivateCrtKeyImpl(n, e, d, p, q, pe, qe, coeff); 172 return new KeyPair(publicKey, privateKey); 173 } catch (InvalidKeyException exc) { 174 // invalid key exception only thrown for keys < 512 bit, 175 // will not happen here 176 throw new RuntimeException(exc); 177 } 178 } 179 } 180 181 }