1 /* 2 * Copyright (c) 2018, 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.ec; 27 28 import java.io.IOException; 29 import java.math.BigInteger; 30 import java.security.spec.AlgorithmParameterSpec; 31 import java.security.spec.NamedParameterSpec; 32 import java.util.Collections; 33 import java.util.Map; 34 import java.util.HashMap; 35 import java.util.Optional; 36 import java.util.function.Function; 37 import java.util.function.Supplier; 38 39 import sun.security.util.ObjectIdentifier; 40 import sun.security.x509.AlgorithmId; 41 42 public class XECParameters { 43 44 // Naming/identification parameters 45 private final ObjectIdentifier oid; 46 private final String name; 47 48 // Curve/field parameters 49 private final int bits; 50 private final BigInteger p; 51 private final int logCofactor; 52 private final int a24; 53 private final byte basePoint; 54 55 /** 56 * 57 * Construct an object holding the supplied parameters. No parameters are 58 * checked, so this method always succeeds. This method supports 59 * Montgomery curves of the form y^2 = x^3 + ax^2 + x. 60 * 61 * @param bits The number of relevant bits in a public/private key. 62 * @param p The prime that defines the finite field. 63 * @param a24 The value of (a - 2) / 4, where a is the second-degree curve 64 * coefficient. 65 * @param basePoint The point that generates the desired group 66 * @param logCofactor The base-2 logarithm of the cofactor of the curve 67 * @param oid 68 * @param name 69 */ 70 public XECParameters(int bits, BigInteger p, int a24, 71 byte basePoint, int logCofactor, 72 ObjectIdentifier oid, String name) { 73 74 this.bits = bits; 75 this.logCofactor = logCofactor; 76 this.p = p; 77 this.a24 = a24; 78 this.basePoint = basePoint; 79 this.oid = oid; 80 this.name = name; 81 82 } 83 84 public int getBits() { 85 return bits; 86 } 87 public int getBytes() { 88 return (bits + 7) / 8; 89 } 90 public int getLogCofactor() { 91 return logCofactor; 92 } 93 public BigInteger getP() { 94 return p; 95 } 96 public int getA24() { 97 return a24; 98 } 99 public byte getBasePoint() { 100 return basePoint; 101 } 102 public ObjectIdentifier getOid() { 103 return oid; 104 } 105 public String getName() { 106 return name; 107 } 108 109 private static final Map<Integer, XECParameters> SIZE_MAP; 110 private static final Map<ObjectIdentifier, XECParameters> OID_MAP; 111 private static final Map<String, XECParameters> NAME_MAP; 112 113 static { 114 final BigInteger TWO = BigInteger.valueOf(2); 115 116 Map<Integer, XECParameters> bySize = new HashMap<>(); 117 Map<ObjectIdentifier, XECParameters> byOid = new HashMap<>(); 118 Map<String, XECParameters> byName = new HashMap<>(); 119 120 // set up X25519 121 try { 122 BigInteger p = TWO.pow(255).subtract(BigInteger.valueOf(19)); 123 addParameters(255, p, 121665, (byte) 0x09, 3, 124 new int[]{1, 3, 101, 110}, NamedParameterSpec.X25519.getName(), 125 bySize, byOid, byName); 126 127 } catch (IOException ex) { 128 // Unable to set X25519 parameters---it will be disabled 129 } 130 131 // set up X448 132 try { 133 BigInteger p = TWO.pow(448).subtract(TWO.pow(224)) 134 .subtract(BigInteger.ONE); 135 addParameters(448, p, 39081, (byte) 0x05, 2, 136 new int[]{1, 3, 101, 111}, NamedParameterSpec.X448.getName(), 137 bySize, byOid, byName); 138 139 } catch (IOException ex) { 140 // Unable to set X448 parameters---it will be disabled 141 } 142 143 SIZE_MAP = Collections.unmodifiableMap(bySize); 144 OID_MAP = Collections.unmodifiableMap(byOid); 145 NAME_MAP = Collections.unmodifiableMap(byName); 146 } 147 148 private static void addParameters(int bits, BigInteger p, int a24, 149 byte basePoint, int logCofactor, int[] oidBytes, String name, 150 Map<Integer, XECParameters> bySize, 151 Map<ObjectIdentifier, XECParameters> byOid, 152 Map<String, XECParameters> byName) throws IOException { 153 154 ObjectIdentifier oid = new ObjectIdentifier(oidBytes); 155 XECParameters params = 156 new XECParameters(bits, p, a24, basePoint, logCofactor, oid, name); 157 bySize.put(bits, params); 158 byOid.put(oid, params); 159 byName.put(name, params); 160 } 161 162 public static Optional<XECParameters> getByOid(ObjectIdentifier id) { 163 return Optional.ofNullable(OID_MAP.get(id)); 164 } 165 public static Optional<XECParameters> getBySize(int size) { 166 return Optional.ofNullable(SIZE_MAP.get(size)); 167 } 168 public static Optional<XECParameters> getByName(String name) { 169 return Optional.ofNullable(NAME_MAP.get(name)); 170 } 171 172 boolean oidEquals(XECParameters other) { 173 return oid.equals(other.getOid()); 174 } 175 176 // Utility method that is used by the methods below to handle exception 177 // suppliers 178 private static 179 <A, B> Supplier<B> apply(final Function<A, B> func, final A a) { 180 return new Supplier<B>() { 181 @Override 182 public B get() { 183 return func.apply(a); 184 } 185 }; 186 } 187 188 /** 189 * Get parameters by key size, or throw an exception if no parameters are 190 * defined for the specified key size. This method is used in several 191 * contexts that should throw different exceptions when the parameters 192 * are not found. The first argument is a function that produces the 193 * desired exception. 194 * 195 * @param exception a function that produces an exception from a string 196 * @param size the desired key size 197 * @param <T> the type of exception that is thrown 198 * @return the parameters for the specified key size 199 * @throws T when suitable parameters do not exist 200 */ 201 public static 202 <T extends Throwable> 203 XECParameters getBySize(Function<String, T> exception, 204 int size) throws T { 205 206 Optional<XECParameters> xecParams = getBySize(size); 207 return xecParams.orElseThrow( 208 apply(exception, "Unsupported size: " + size)); 209 } 210 211 /** 212 * Get parameters by algorithm ID, or throw an exception if no 213 * parameters are defined for the specified ID. This method is used in 214 * several contexts that should throw different exceptions when the 215 * parameters are not found. The first argument is a function that produces 216 * the desired exception. 217 * 218 * @param exception a function that produces an exception from a string 219 * @param algId the algorithm ID 220 * @param <T> the type of exception that is thrown 221 * @return the parameters for the specified algorithm ID 222 * @throws T when suitable parameters do not exist 223 */ 224 public static 225 <T extends Throwable> 226 XECParameters get(Function<String, T> exception, 227 AlgorithmId algId) throws T { 228 229 Optional<XECParameters> xecParams = getByOid(algId.getOID()); 230 return xecParams.orElseThrow( 231 apply(exception, "Unsupported OID: " + algId.getOID())); 232 } 233 234 /** 235 * Get parameters by algorithm parameter spec, or throw an exception if no 236 * parameters are defined for the spec. This method is used in 237 * several contexts that should throw different exceptions when the 238 * parameters are not found. The first argument is a function that produces 239 * the desired exception. 240 * 241 * @param exception a function that produces an exception from a string 242 * @param params the algorithm parameters spec 243 * @param <T> the type of exception that is thrown 244 * @return the parameters for the spec 245 * @throws T when suitable parameters do not exist 246 */ 247 public static 248 <T extends Throwable> 249 XECParameters get(Function<String, T> exception, 250 AlgorithmParameterSpec params) throws T { 251 252 if (params instanceof NamedParameterSpec) { 253 NamedParameterSpec namedParams = (NamedParameterSpec) params; 254 Optional<XECParameters> xecParams = 255 getByName(namedParams.getName()); 256 return xecParams.orElseThrow( 257 apply(exception, "Unsupported name: " + namedParams.getName())); 258 } else { 259 throw exception.apply("Only NamedParameterSpec is supported."); 260 } 261 } 262 } 263