Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ec/ECDSAOperations.java
38830 views
/*1* Copyright (c) 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 sun.security.ec.point.*;28import sun.security.util.ArrayUtil;29import sun.security.util.math.*;30import static sun.security.ec.ECOperations.IntermediateValueException;3132import java.security.ProviderException;33import java.security.spec.*;34import java.util.Optional;3536public class ECDSAOperations {3738public static class Seed {39private final byte[] seedValue;4041public Seed(byte[] seedValue) {42this.seedValue = seedValue;43}4445public byte[] getSeedValue() {46return seedValue;47}48}4950public static class Nonce {51private final byte[] nonceValue;5253public Nonce(byte[] nonceValue) {54this.nonceValue = nonceValue;55}5657public byte[] getNonceValue() {58return nonceValue;59}60}6162private final ECOperations ecOps;63private final AffinePoint basePoint;6465public ECDSAOperations(ECOperations ecOps, ECPoint basePoint) {66this.ecOps = ecOps;67this.basePoint = toAffinePoint(basePoint, ecOps.getField());68}6970public ECOperations getEcOperations() {71return ecOps;72}7374public AffinePoint basePointMultiply(byte[] scalar) {75return ecOps.multiply(basePoint, scalar).asAffine();76}7778public static AffinePoint toAffinePoint(ECPoint point,79IntegerFieldModuloP field) {8081ImmutableIntegerModuloP affineX = field.getElement(point.getAffineX());82ImmutableIntegerModuloP affineY = field.getElement(point.getAffineY());83return new AffinePoint(affineX, affineY);84}8586public static87Optional<ECDSAOperations> forParameters(ECParameterSpec ecParams) {88Optional<ECOperations> curveOps =89ECOperations.forParameters(ecParams);90return curveOps.map(91ops -> new ECDSAOperations(ops, ecParams.getGenerator())92);93}9495/**96*97* Sign a digest using the provided private key and seed.98* IMPORTANT: The private key is a scalar represented using a99* little-endian byte array. This is backwards from the conventional100* representation in ECDSA. The routines that produce and consume this101* value uses little-endian, so this deviation from convention removes102* the requirement to swap the byte order. The returned signature is in103* the conventional byte order.104*105* @param privateKey the private key scalar as a little-endian byte array106* @param digest the digest to be signed107* @param seed the seed that will be used to produce the nonce. This object108* should contain an array that is at least 64 bits longer than109* the number of bits required to represent the group order.110* @return the ECDSA signature value111* @throws IntermediateValueException if the signature cannot be produced112* due to an unacceptable intermediate or final value. If this113* exception is thrown, then the caller should discard the nonnce and114* try again with an entirely new nonce value.115*/116public byte[] signDigest(byte[] privateKey, byte[] digest, Seed seed)117throws IntermediateValueException {118119byte[] nonceArr = ecOps.seedToScalar(seed.getSeedValue());120121Nonce nonce = new Nonce(nonceArr);122return signDigest(privateKey, digest, nonce);123}124125/**126*127* Sign a digest using the provided private key and nonce.128* IMPORTANT: The private key and nonce are scalars represented by a129* little-endian byte array. This is backwards from the conventional130* representation in ECDSA. The routines that produce and consume these131* values use little-endian, so this deviation from convention removes132* the requirement to swap the byte order. The returned signature is in133* the conventional byte order.134*135* @param privateKey the private key scalar as a little-endian byte array136* @param digest the digest to be signed137* @param nonce the nonce object containing a little-endian scalar value.138* @return the ECDSA signature value139* @throws IntermediateValueException if the signature cannot be produced140* due to an unacceptable intermediate or final value. If this141* exception is thrown, then the caller should discard the nonnce and142* try again with an entirely new nonce value.143*/144public byte[] signDigest(byte[] privateKey, byte[] digest, Nonce nonce)145throws IntermediateValueException {146147IntegerFieldModuloP orderField = ecOps.getOrderField();148int orderBits = orderField.getSize().bitLength();149if (orderBits % 8 != 0 && orderBits < digest.length * 8) {150// This implementation does not support truncating digests to151// a length that is not a multiple of 8.152throw new ProviderException("Invalid digest length");153}154155byte[] k = nonce.getNonceValue();156// check nonce length157int length = (orderField.getSize().bitLength() + 7) / 8;158if (k.length != length) {159throw new ProviderException("Incorrect nonce length");160}161162MutablePoint R = ecOps.multiply(basePoint, k);163IntegerModuloP r = R.asAffine().getX();164// put r into the correct field by fully reducing to an array165byte[] temp = new byte[length];166r.asByteArray(temp);167r = orderField.getElement(temp);168// store r in result169r.asByteArray(temp);170byte[] result = new byte[2 * length];171ArrayUtil.reverse(temp);172System.arraycopy(temp, 0, result, 0, length);173// compare r to 0174if (ECOperations.allZero(temp)) {175throw new IntermediateValueException();176}177178IntegerModuloP dU = orderField.getElement(privateKey);179int lengthE = Math.min(length, digest.length);180byte[] E = new byte[lengthE];181System.arraycopy(digest, 0, E, 0, lengthE);182ArrayUtil.reverse(E);183IntegerModuloP e = orderField.getElement(E);184IntegerModuloP kElem = orderField.getElement(k);185IntegerModuloP kInv = kElem.multiplicativeInverse();186MutableIntegerModuloP s = r.mutable();187s.setProduct(dU).setSum(e).setProduct(kInv);188// store s in result189s.asByteArray(temp);190ArrayUtil.reverse(temp);191System.arraycopy(temp, 0, result, length, length);192// compare s to 0193if (ECOperations.allZero(temp)) {194throw new IntermediateValueException();195}196197return result;198199}200201}202203204