1 /* 2 * Copyright (c) 2006, 2013, 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.util; 27 28 import java.io.IOException; 29 30 import java.math.BigInteger; 31 32 import java.security.*; 33 34 import java.security.interfaces.*; 35 36 import java.security.spec.*; 37 38 import java.util.Arrays; 39 40 import sun.security.x509.X509Key; 41 42 public class ECUtil { 43 44 // Used by SunPKCS11 and SunJSSE. 45 public static ECPoint decodePoint(byte[] data, EllipticCurve curve) 46 throws IOException { 47 if ((data.length == 0) || (data[0] != 4)) { 48 throw new IOException("Only uncompressed point format supported"); 49 } 50 // Per ANSI X9.62, an encoded point is a 1 byte type followed by 51 // ceiling(log base 2 field-size / 8) bytes of x and the same of y. 52 int n = (data.length - 1) / 2; 53 if (n != ((curve.getField().getFieldSize() + 7 ) >> 3)) { 54 throw new IOException("Point does not match field size"); 55 } 56 57 byte[] xb = Arrays.copyOfRange(data, 1, 1 + n); 58 byte[] yb = Arrays.copyOfRange(data, n + 1, n + 1 + n); 59 60 return new ECPoint(new BigInteger(1, xb), new BigInteger(1, yb)); 61 } 62 63 // Used by SunPKCS11 and SunJSSE. 64 public static byte[] encodePoint(ECPoint point, EllipticCurve curve) { 65 // get field size in bytes (rounding up) 66 int n = (curve.getField().getFieldSize() + 7) >> 3; 67 byte[] xb = trimZeroes(point.getAffineX().toByteArray()); 68 byte[] yb = trimZeroes(point.getAffineY().toByteArray()); 69 if ((xb.length > n) || (yb.length > n)) { 70 throw new RuntimeException 71 ("Point coordinates do not match field size"); 72 } 73 byte[] b = new byte[1 + (n << 1)]; 74 b[0] = 4; // uncompressed 75 System.arraycopy(xb, 0, b, n - xb.length + 1, xb.length); 76 System.arraycopy(yb, 0, b, b.length - yb.length, yb.length); 77 return b; 78 } 79 80 public static byte[] trimZeroes(byte[] b) { 81 int i = 0; 82 while ((i < b.length - 1) && (b[i] == 0)) { 83 i++; 84 } 85 if (i == 0) { 86 return b; 87 } 88 89 return Arrays.copyOfRange(b, i, b.length); 90 } 91 92 private static KeyFactory getKeyFactory() { 93 try { 94 return KeyFactory.getInstance("EC", "SunEC"); 95 } catch (NoSuchAlgorithmException | NoSuchProviderException e) { 96 throw new RuntimeException(e); 97 } 98 } 99 100 public static ECPublicKey decodeX509ECPublicKey(byte[] encoded) 101 throws InvalidKeySpecException { 102 KeyFactory keyFactory = getKeyFactory(); 103 X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); 104 105 return (ECPublicKey)keyFactory.generatePublic(keySpec); 106 } 107 108 public static byte[] x509EncodeECPublicKey(ECPoint w, 109 ECParameterSpec params) throws InvalidKeySpecException { 110 KeyFactory keyFactory = getKeyFactory(); 111 ECPublicKeySpec keySpec = new ECPublicKeySpec(w, params); 112 X509Key key = (X509Key)keyFactory.generatePublic(keySpec); 113 114 return key.getEncoded(); 115 } 116 117 public static ECPrivateKey decodePKCS8ECPrivateKey(byte[] encoded) 118 throws InvalidKeySpecException { 119 KeyFactory keyFactory = getKeyFactory(); 120 PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded); 121 122 return (ECPrivateKey)keyFactory.generatePrivate(keySpec); 123 } 124 125 public static ECPrivateKey generateECPrivateKey(BigInteger s, 126 ECParameterSpec params) throws InvalidKeySpecException { 127 KeyFactory keyFactory = getKeyFactory(); 128 ECPrivateKeySpec keySpec = new ECPrivateKeySpec(s, params); 129 130 return (ECPrivateKey)keyFactory.generatePrivate(keySpec); 131 } 132 133 private static AlgorithmParameters getECParameters(Provider p) { 134 try { 135 if (p != null) { 136 return AlgorithmParameters.getInstance("EC", p); 137 } 138 139 return AlgorithmParameters.getInstance("EC"); 140 } catch (NoSuchAlgorithmException nsae) { 141 throw new RuntimeException(nsae); 142 } 143 } 144 145 public static byte[] encodeECParameterSpec(Provider p, 146 ECParameterSpec spec) { 147 AlgorithmParameters parameters = getECParameters(p); 148 149 try { 150 parameters.init(spec); 151 } catch (InvalidParameterSpecException ipse) { 152 throw new RuntimeException("Not a known named curve: " + spec); 153 } 154 155 try { 156 return parameters.getEncoded(); 157 } catch (IOException ioe) { 158 // it is a bug if this should happen 159 throw new RuntimeException(ioe); 160 } 161 } 162 163 public static ECParameterSpec getECParameterSpec(Provider p, 164 ECParameterSpec spec) { 165 AlgorithmParameters parameters = getECParameters(p); 166 167 try { 168 parameters.init(spec); 169 return parameters.getParameterSpec(ECParameterSpec.class); 170 } catch (InvalidParameterSpecException ipse) { 171 return null; 172 } 173 } 174 175 public static ECParameterSpec getECParameterSpec(Provider p, 176 byte[] params) 177 throws IOException { 178 AlgorithmParameters parameters = getECParameters(p); 179 180 parameters.init(params); 181 182 try { 183 return parameters.getParameterSpec(ECParameterSpec.class); 184 } catch (InvalidParameterSpecException ipse) { 185 return null; 186 } 187 } 188 189 public static ECParameterSpec getECParameterSpec(Provider p, String name) { 190 AlgorithmParameters parameters = getECParameters(p); 191 192 try { 193 parameters.init(new ECGenParameterSpec(name)); 194 return parameters.getParameterSpec(ECParameterSpec.class); 195 } catch (InvalidParameterSpecException ipse) { 196 return null; 197 } 198 } 199 200 public static ECParameterSpec getECParameterSpec(Provider p, int keySize) { 201 AlgorithmParameters parameters = getECParameters(p); 202 203 try { 204 parameters.init(new ECKeySizeParameterSpec(keySize)); 205 return parameters.getParameterSpec(ECParameterSpec.class); 206 } catch (InvalidParameterSpecException ipse) { 207 return null; 208 } 209 210 } 211 212 public static String getCurveName(Provider p, ECParameterSpec spec) { 213 ECGenParameterSpec nameSpec; 214 AlgorithmParameters parameters = getECParameters(p); 215 216 try { 217 parameters.init(spec); 218 nameSpec = parameters.getParameterSpec(ECGenParameterSpec.class); 219 } catch (InvalidParameterSpecException ipse) { 220 return null; 221 } 222 223 if (nameSpec == null) { 224 return null; 225 } 226 227 return nameSpec.getName(); 228 } 229 230 private ECUtil() {} 231 }