Path: blob/master/src/java.base/share/classes/sun/security/util/ECUtil.java
41159 views
/*1* Copyright (c) 2006, 2021, 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.util;2627import jdk.internal.access.SharedSecrets;2829import java.io.IOException;30import java.math.BigInteger;31import java.security.*;32import java.security.interfaces.*;33import java.security.spec.*;34import java.util.Arrays;3536public final class ECUtil {3738// Used by SunEC39public static byte[] sArray(BigInteger s, ECParameterSpec params) {40byte[] arr = s.toByteArray();41ArrayUtil.reverse(arr);42int byteLength = (params.getOrder().bitLength() + 7) / 8;43byte[] arrayS = new byte[byteLength];44int length = Math.min(byteLength, arr.length);45System.arraycopy(arr, 0, arrayS, 0, length);46return arrayS;47}4849// Used by SunPKCS11 and SunJSSE.50public static ECPoint decodePoint(byte[] data, EllipticCurve curve)51throws IOException {52if ((data.length == 0) || (data[0] != 4)) {53throw new IOException("Only uncompressed point format supported");54}55// Per ANSI X9.62, an encoded point is a 1 byte type followed by56// ceiling(log base 2 field-size / 8) bytes of x and the same of y.57int n = (data.length - 1) / 2;58if (n != ((curve.getField().getFieldSize() + 7 ) >> 3)) {59throw new IOException("Point does not match field size");60}6162byte[] xb = Arrays.copyOfRange(data, 1, 1 + n);63byte[] yb = Arrays.copyOfRange(data, n + 1, n + 1 + n);6465return new ECPoint(new BigInteger(1, xb), new BigInteger(1, yb));66}6768// Used by SunPKCS11 and SunJSSE.69public static byte[] encodePoint(ECPoint point, EllipticCurve curve) {70// get field size in bytes (rounding up)71int n = (curve.getField().getFieldSize() + 7) >> 3;72byte[] xb = trimZeroes(point.getAffineX().toByteArray());73byte[] yb = trimZeroes(point.getAffineY().toByteArray());74if ((xb.length > n) || (yb.length > n)) {75throw new RuntimeException76("Point coordinates do not match field size");77}78byte[] b = new byte[1 + (n << 1)];79b[0] = 4; // uncompressed80System.arraycopy(xb, 0, b, n - xb.length + 1, xb.length);81System.arraycopy(yb, 0, b, b.length - yb.length, yb.length);82return b;83}8485public static byte[] trimZeroes(byte[] b) {86int i = 0;87while ((i < b.length - 1) && (b[i] == 0)) {88i++;89}90if (i == 0) {91return b;92}9394return Arrays.copyOfRange(b, i, b.length);95}9697private static KeyFactory getKeyFactory() {98try {99return KeyFactory.getInstance("EC", "SunEC");100} catch (NoSuchAlgorithmException | NoSuchProviderException e) {101throw new RuntimeException(e);102}103}104105public static ECPublicKey decodeX509ECPublicKey(byte[] encoded)106throws InvalidKeySpecException {107KeyFactory keyFactory = getKeyFactory();108X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);109110return (ECPublicKey)keyFactory.generatePublic(keySpec);111}112113public static byte[] x509EncodeECPublicKey(ECPoint w,114ECParameterSpec params) throws InvalidKeySpecException {115KeyFactory keyFactory = getKeyFactory();116ECPublicKeySpec keySpec = new ECPublicKeySpec(w, params);117Key key = keyFactory.generatePublic(keySpec);118119return key.getEncoded();120}121122public static ECPrivateKey decodePKCS8ECPrivateKey(byte[] encoded)123throws InvalidKeySpecException {124KeyFactory keyFactory = getKeyFactory();125PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);126try {127return (ECPrivateKey) keyFactory.generatePrivate(keySpec);128} finally {129SharedSecrets.getJavaSecuritySpecAccess().clearEncodedKeySpec(keySpec);130}131}132133public static ECPrivateKey generateECPrivateKey(BigInteger s,134ECParameterSpec params) throws InvalidKeySpecException {135KeyFactory keyFactory = getKeyFactory();136ECPrivateKeySpec keySpec = new ECPrivateKeySpec(s, params);137138return (ECPrivateKey)keyFactory.generatePrivate(keySpec);139}140141public static AlgorithmParameters getECParameters(Provider p) {142try {143if (p != null) {144return AlgorithmParameters.getInstance("EC", p);145}146147return AlgorithmParameters.getInstance("EC");148} catch (NoSuchAlgorithmException nsae) {149throw new RuntimeException(nsae);150}151}152153public static byte[] encodeECParameterSpec(Provider p,154ECParameterSpec spec) {155AlgorithmParameters parameters = getECParameters(p);156157try {158parameters.init(spec);159} catch (InvalidParameterSpecException ipse) {160throw new RuntimeException("Not a known named curve: " + spec);161}162163try {164return parameters.getEncoded();165} catch (IOException ioe) {166// it is a bug if this should happen167throw new RuntimeException(ioe);168}169}170171public static ECParameterSpec getECParameterSpec(Provider p,172ECParameterSpec spec) {173AlgorithmParameters parameters = getECParameters(p);174175try {176parameters.init(spec);177return parameters.getParameterSpec(ECParameterSpec.class);178} catch (InvalidParameterSpecException ipse) {179return null;180}181}182183public static ECParameterSpec getECParameterSpec(Provider p,184byte[] params)185throws IOException {186AlgorithmParameters parameters = getECParameters(p);187188parameters.init(params);189190try {191return parameters.getParameterSpec(ECParameterSpec.class);192} catch (InvalidParameterSpecException ipse) {193return null;194}195}196197public static ECParameterSpec getECParameterSpec(Provider p, String name) {198AlgorithmParameters parameters = getECParameters(p);199200try {201parameters.init(new ECGenParameterSpec(name));202return parameters.getParameterSpec(ECParameterSpec.class);203} catch (InvalidParameterSpecException ipse) {204return null;205}206}207208public static ECParameterSpec getECParameterSpec(Provider p, int keySize) {209AlgorithmParameters parameters = getECParameters(p);210211try {212parameters.init(new ECKeySizeParameterSpec(keySize));213return parameters.getParameterSpec(ECParameterSpec.class);214} catch (InvalidParameterSpecException ipse) {215return null;216}217218}219220public static String getCurveName(Provider p, ECParameterSpec spec) {221ECGenParameterSpec nameSpec;222AlgorithmParameters parameters = getECParameters(p);223224try {225parameters.init(spec);226nameSpec = parameters.getParameterSpec(ECGenParameterSpec.class);227} catch (InvalidParameterSpecException ipse) {228return null;229}230231if (nameSpec == null) {232return null;233}234235return nameSpec.getName();236}237238public static boolean equals(ECParameterSpec spec1, ECParameterSpec spec2) {239if (spec1 == spec2) {240return true;241}242243if (spec1 == null || spec2 == null) {244return false;245}246return (spec1.getCofactor() == spec2.getCofactor() &&247spec1.getOrder().equals(spec2.getOrder()) &&248spec1.getCurve().equals(spec2.getCurve()) &&249spec1.getGenerator().equals(spec2.getGenerator()));250}251252253// Convert the concatenation R and S in into their DER encoding254public static byte[] encodeSignature(byte[] signature) throws SignatureException {255256try {257258int n = signature.length >> 1;259byte[] bytes = new byte[n];260System.arraycopy(signature, 0, bytes, 0, n);261BigInteger r = new BigInteger(1, bytes);262System.arraycopy(signature, n, bytes, 0, n);263BigInteger s = new BigInteger(1, bytes);264265DerOutputStream out = new DerOutputStream(signature.length + 10);266out.putInteger(r);267out.putInteger(s);268DerValue result =269new DerValue(DerValue.tag_Sequence, out.toByteArray());270271return result.toByteArray();272273} catch (Exception e) {274throw new SignatureException("Could not encode signature", e);275}276}277278// Convert the DER encoding of R and S into a concatenation of R and S279public static byte[] decodeSignature(byte[] sig) throws SignatureException {280281try {282// Enforce strict DER checking for signatures283DerInputStream in = new DerInputStream(sig, 0, sig.length, false);284DerValue[] values = in.getSequence(2);285286// check number of components in the read sequence287// and trailing data288if ((values.length != 2) || (in.available() != 0)) {289throw new IOException("Invalid encoding for signature");290}291292BigInteger r = values[0].getPositiveBigInteger();293BigInteger s = values[1].getPositiveBigInteger();294295// trim leading zeroes296byte[] rBytes = trimZeroes(r.toByteArray());297byte[] sBytes = trimZeroes(s.toByteArray());298int k = Math.max(rBytes.length, sBytes.length);299// r and s each occupy half the array300byte[] result = new byte[k << 1];301System.arraycopy(rBytes, 0, result, k - rBytes.length,302rBytes.length);303System.arraycopy(sBytes, 0, result, result.length - sBytes.length,304sBytes.length);305return result;306307} catch (Exception e) {308throw new SignatureException("Invalid encoding for signature", e);309}310}311312private ECUtil() {}313}314315316