1 /* 2 * Copyright (c) 2018, 2019, 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 */ XECParameters(int bits, BigInteger p, int a24, byte basePoint, int logCofactor, ObjectIdentifier oid, String name)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 getBits()84 public int getBits() { 85 return bits; 86 } getBytes()87 public int getBytes() { 88 return (bits + 7) / 8; 89 } getLogCofactor()90 public int getLogCofactor() { 91 return logCofactor; 92 } getP()93 public BigInteger getP() { 94 return p; 95 } getA24()96 public int getA24() { 97 return a24; 98 } getBasePoint()99 public byte getBasePoint() { 100 return basePoint; 101 } getOid()102 public ObjectIdentifier getOid() { 103 return oid; 104 } getName()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 addParameters(int bits, BigInteger p, int a24, byte basePoint, int logCofactor, int[] oidBytes, String name, Map<Integer, XECParameters> bySize, Map<ObjectIdentifier, XECParameters> byOid, Map<String, XECParameters> byName)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.toLowerCase(), params); 160 } 161 getByOid(ObjectIdentifier id)162 public static Optional<XECParameters> getByOid(ObjectIdentifier id) { 163 return Optional.ofNullable(OID_MAP.get(id)); 164 } getBySize(int size)165 public static Optional<XECParameters> getBySize(int size) { 166 return Optional.ofNullable(SIZE_MAP.get(size)); 167 } getByName(String name)168 public static Optional<XECParameters> getByName(String name) { 169 return Optional.ofNullable(NAME_MAP.get(name.toLowerCase())); 170 } 171 oidEquals(XECParameters other)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 apply(final Function<A, B> func, final A a)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 264