Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ec/ECPrivateKeyImpl.java
38830 views
/*1* Copyright (c) 2006, 2018, 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.ec;2627import java.io.IOException;28import java.math.BigInteger;2930import java.security.*;31import java.security.interfaces.*;32import java.security.spec.*;3334import sun.security.util.ArrayUtil;35import sun.security.util.DerInputStream;36import sun.security.util.DerOutputStream;37import sun.security.util.DerValue;38import sun.security.util.ECParameters;39import sun.security.util.ECUtil;40import sun.security.x509.AlgorithmId;41import sun.security.pkcs.PKCS8Key;4243/**44* Key implementation for EC private keys.45*46* ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft):47*48* <pre>49* EXPLICIT TAGS50*51* ECPrivateKey ::= SEQUENCE {52* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),53* privateKey OCTET STRING,54* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,55* publicKey [1] BIT STRING OPTIONAL56* }57* </pre>58*59* We currently ignore the optional parameters and publicKey fields. We60* require that the parameters are encoded as part of the AlgorithmIdentifier,61* not in the private key structure.62*63* @since 1.664* @author Andreas Sterbenz65*/66public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {6768private static final long serialVersionUID = 88695385615075129L;6970private BigInteger s; // private value71private byte[] arrayS; // private value as a little-endian array72private ECParameterSpec params;7374/**75* Construct a key from its encoding. Called by the ECKeyFactory.76*/77public ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {78decode(encoded);79}8081/**82* Construct a key from its components. Used by the83* KeyFactory.84*/85public ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)86throws InvalidKeyException {87this.s = s;88this.params = params;89makeEncoding(s);9091}9293ECPrivateKeyImpl(byte[] s, ECParameterSpec params)94throws InvalidKeyException {95this.arrayS = s.clone();96this.params = params;97makeEncoding(s);98}99100private void makeEncoding(byte[] s) throws InvalidKeyException {101algid = new AlgorithmId102(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));103try {104DerOutputStream out = new DerOutputStream();105out.putInteger(1); // version 1106byte[] privBytes = s.clone();107ArrayUtil.reverse(privBytes);108out.putOctetString(privBytes);109DerValue val =110new DerValue(DerValue.tag_Sequence, out.toByteArray());111key = val.toByteArray();112} catch (IOException exc) {113// should never occur114throw new InvalidKeyException(exc);115}116}117118private void makeEncoding(BigInteger s) throws InvalidKeyException {119algid = new AlgorithmId120(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));121try {122byte[] sArr = s.toByteArray();123// convert to fixed-length array124int numOctets = (params.getOrder().bitLength() + 7) / 8;125byte[] sOctets = new byte[numOctets];126int inPos = Math.max(sArr.length - sOctets.length, 0);127int outPos = Math.max(sOctets.length - sArr.length, 0);128int length = Math.min(sArr.length, sOctets.length);129System.arraycopy(sArr, inPos, sOctets, outPos, length);130131DerOutputStream out = new DerOutputStream();132out.putInteger(1); // version 1133out.putOctetString(sOctets);134DerValue val =135new DerValue(DerValue.tag_Sequence, out.toByteArray());136key = val.toByteArray();137} catch (IOException exc) {138// should never occur139throw new InvalidKeyException(exc);140}141}142143// see JCA doc144public String getAlgorithm() {145return "EC";146}147148// see JCA doc149public BigInteger getS() {150if (s == null) {151byte[] arrCopy = arrayS.clone();152ArrayUtil.reverse(arrCopy);153s = new BigInteger(1, arrCopy);154}155return s;156}157158public byte[] getArrayS() {159if (arrayS == null) {160byte[] arr = getS().toByteArray();161ArrayUtil.reverse(arr);162int byteLength = (params.getOrder().bitLength() + 7) / 8;163arrayS = new byte[byteLength];164int length = Math.min(byteLength, arr.length);165System.arraycopy(arr, 0, arrayS, 0, length);166}167return arrayS.clone();168}169170// see JCA doc171public ECParameterSpec getParams() {172return params;173}174175/**176* Parse the key. Called by PKCS8Key.177*/178protected void parseKeyBits() throws InvalidKeyException {179try {180DerInputStream in = new DerInputStream(key);181DerValue derValue = in.getDerValue();182if (derValue.tag != DerValue.tag_Sequence) {183throw new IOException("Not a SEQUENCE");184}185DerInputStream data = derValue.data;186int version = data.getInteger();187if (version != 1) {188throw new IOException("Version must be 1");189}190byte[] privData = data.getOctetString();191ArrayUtil.reverse(privData);192arrayS = privData;193while (data.available() != 0) {194DerValue value = data.getDerValue();195if (value.isContextSpecific((byte) 0)) {196// ignore for now197} else if (value.isContextSpecific((byte) 1)) {198// ignore for now199} else {200throw new InvalidKeyException("Unexpected value: " + value);201}202}203AlgorithmParameters algParams = this.algid.getParameters();204if (algParams == null) {205throw new InvalidKeyException("EC domain parameters must be "206+ "encoded in the algorithm identifier");207}208params = algParams.getParameterSpec(ECParameterSpec.class);209} catch (IOException e) {210throw new InvalidKeyException("Invalid EC private key", e);211} catch (InvalidParameterSpecException e) {212throw new InvalidKeyException("Invalid EC private key", e);213}214}215}216217218