Path: blob/master/src/jdk.crypto.ec/share/classes/sun/security/ec/ECPrivateKeyImpl.java
41161 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.ec;2627import java.io.IOException;28import java.math.BigInteger;2930import java.security.*;31import java.security.interfaces.*;32import java.security.spec.*;33import java.util.Arrays;3435import sun.security.util.*;36import sun.security.x509.AlgorithmId;37import sun.security.pkcs.PKCS8Key;3839/**40* Key implementation for EC private keys.41*42* ASN.1 syntax for EC private keys from SEC 1 v1.5 (draft):43*44* <pre>45* EXPLICIT TAGS46*47* ECPrivateKey ::= SEQUENCE {48* version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),49* privateKey OCTET STRING,50* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,51* publicKey [1] BIT STRING OPTIONAL52* }53* </pre>54*55* We currently ignore the optional parameters and publicKey fields. We56* require that the parameters are encoded as part of the AlgorithmIdentifier,57* not in the private key structure.58*59* @since 1.660* @author Andreas Sterbenz61*/62public final class ECPrivateKeyImpl extends PKCS8Key implements ECPrivateKey {6364private static final long serialVersionUID = 88695385615075129L;6566private BigInteger s; // private value67private byte[] arrayS; // private value as a little-endian array68private ECParameterSpec params;6970/**71* Construct a key from its encoding. Called by the ECKeyFactory.72*/73ECPrivateKeyImpl(byte[] encoded) throws InvalidKeyException {74super(encoded);75parseKeyBits();76}7778/**79* Construct a key from its components. Used by the80* KeyFactory.81*/82ECPrivateKeyImpl(BigInteger s, ECParameterSpec params)83throws InvalidKeyException {84this.s = s;85this.params = params;86makeEncoding(s);8788}8990ECPrivateKeyImpl(byte[] s, ECParameterSpec params)91throws InvalidKeyException {92this.arrayS = s.clone();93this.params = params;94makeEncoding(s);95}9697private void makeEncoding(byte[] s) throws InvalidKeyException {98algid = new AlgorithmId99(AlgorithmId.EC_oid, ECParameters.getAlgorithmParameters(params));100try {101DerOutputStream out = new DerOutputStream();102out.putInteger(1); // version 1103byte[] privBytes = s.clone();104ArrayUtil.reverse(privBytes);105out.putOctetString(privBytes);106Arrays.fill(privBytes, (byte)0);107DerValue val = DerValue.wrap(DerValue.tag_Sequence, out);108key = val.toByteArray();109val.clear();110} catch (IOException exc) {111// should never occur112throw new InvalidKeyException(exc);113}114}115116private void makeEncoding(BigInteger s) throws InvalidKeyException {117algid = new AlgorithmId(AlgorithmId.EC_oid,118ECParameters.getAlgorithmParameters(params));119try {120byte[] sArr = s.toByteArray();121// convert to fixed-length array122int numOctets = (params.getOrder().bitLength() + 7) / 8;123byte[] sOctets = new byte[numOctets];124int inPos = Math.max(sArr.length - sOctets.length, 0);125int outPos = Math.max(sOctets.length - sArr.length, 0);126int length = Math.min(sArr.length, sOctets.length);127System.arraycopy(sArr, inPos, sOctets, outPos, length);128Arrays.fill(sArr, (byte)0);129130DerOutputStream out = new DerOutputStream();131out.putInteger(1); // version 1132out.putOctetString(sOctets);133Arrays.fill(sOctets, (byte)0);134DerValue val = DerValue.wrap(DerValue.tag_Sequence, out);135key = val.toByteArray();136val.clear();137} catch (IOException exc) {138throw new AssertionError("Should not happen", exc);139}140}141142// see JCA doc143public String getAlgorithm() {144return "EC";145}146147// see JCA doc148public BigInteger getS() {149if (s == null) {150byte[] arrCopy = arrayS.clone();151ArrayUtil.reverse(arrCopy);152s = new BigInteger(1, arrCopy);153Arrays.fill(arrCopy, (byte)0);154}155return s;156}157158public byte[] getArrayS() {159if (arrayS == null) {160arrayS = ECUtil.sArray(getS(), params);161}162return arrayS.clone();163}164165// see JCA doc166public ECParameterSpec getParams() {167return params;168}169170private void parseKeyBits() throws InvalidKeyException {171try {172DerInputStream in = new DerInputStream(key);173DerValue derValue = in.getDerValue();174if (derValue.tag != DerValue.tag_Sequence) {175throw new IOException("Not a SEQUENCE");176}177DerInputStream data = derValue.data;178int version = data.getInteger();179if (version != 1) {180throw new IOException("Version must be 1");181}182byte[] privData = data.getOctetString();183ArrayUtil.reverse(privData);184arrayS = privData;185while (data.available() != 0) {186DerValue value = data.getDerValue();187if (value.isContextSpecific((byte) 0)) {188// ignore for now189} else if (value.isContextSpecific((byte) 1)) {190// ignore for now191} else {192throw new InvalidKeyException("Unexpected value: " + value);193}194}195AlgorithmParameters algParams = this.algid.getParameters();196if (algParams == null) {197throw new InvalidKeyException("EC domain parameters must be "198+ "encoded in the algorithm identifier");199}200params = algParams.getParameterSpec(ECParameterSpec.class);201} catch (IOException e) {202throw new InvalidKeyException("Invalid EC private key", e);203} catch (InvalidParameterSpecException e) {204throw new InvalidKeyException("Invalid EC private key", e);205}206}207}208209210