Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/security/ec/ECDHKeyAgreement.java
38830 views
/*1* Copyright (c) 2009, 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.math.*;28import java.security.*;29import java.security.interfaces.*;30import java.security.spec.*;31import java.util.Optional;3233import javax.crypto.*;34import javax.crypto.spec.*;3536import sun.security.util.ArrayUtil;37import sun.security.util.ECUtil;38import sun.security.util.math.*;39import sun.security.ec.point.*;4041/**42* KeyAgreement implementation for ECDH.43*44* @since 1.745*/46public final class ECDHKeyAgreement extends KeyAgreementSpi {4748// private key, if initialized49private ECPrivateKey privateKey;5051// public key, non-null between doPhase() & generateSecret() only52private ECPublicKey publicKey;5354// length of the secret to be derived55private int secretLen;5657/**58* Constructs a new ECDHKeyAgreement.59*/60public ECDHKeyAgreement() {61}6263// see JCE spec64@Override65protected void engineInit(Key key, SecureRandom random)66throws InvalidKeyException {67if (!(key instanceof PrivateKey)) {68throw new InvalidKeyException69("Key must be instance of PrivateKey");70}71privateKey = (ECPrivateKey) ECKeyFactory.toECKey(key);72publicKey = null;73}7475// see JCE spec76@Override77protected void engineInit(Key key, AlgorithmParameterSpec params,78SecureRandom random) throws InvalidKeyException,79InvalidAlgorithmParameterException {80if (params != null) {81throw new InvalidAlgorithmParameterException82("Parameters not supported");83}84engineInit(key, random);85}8687// see JCE spec88@Override89protected Key engineDoPhase(Key key, boolean lastPhase)90throws InvalidKeyException, IllegalStateException {91if (privateKey == null) {92throw new IllegalStateException("Not initialized");93}94if (publicKey != null) {95throw new IllegalStateException("Phase already executed");96}97if (!lastPhase) {98throw new IllegalStateException99("Only two party agreement supported, lastPhase must be true");100}101if (!(key instanceof ECPublicKey)) {102throw new InvalidKeyException103("Key must be a PublicKey with algorithm EC");104}105106this.publicKey = (ECPublicKey) key;107108ECParameterSpec params = publicKey.getParams();109int keyLenBits = params.getCurve().getField().getFieldSize();110secretLen = (keyLenBits + 7) >> 3;111112return null;113}114115private static void validateCoordinate(BigInteger c, BigInteger mod) {116if (c.compareTo(BigInteger.ZERO) < 0) {117throw new ProviderException("invalid coordinate");118}119120if (c.compareTo(mod) >= 0) {121throw new ProviderException("invalid coordinate");122}123}124125/*126* Check whether a public key is valid. Throw ProviderException127* if it is not valid or could not be validated.128*/129private static void validate(ECOperations ops, ECPublicKey key) {130131// ensure that integers are in proper range132BigInteger x = key.getW().getAffineX();133BigInteger y = key.getW().getAffineY();134135BigInteger p = ops.getField().getSize();136validateCoordinate(x, p);137validateCoordinate(y, p);138139// ensure the point is on the curve140EllipticCurve curve = key.getParams().getCurve();141BigInteger rhs = x.modPow(BigInteger.valueOf(3), p).add(curve.getA()142.multiply(x)).add(curve.getB()).mod(p);143BigInteger lhs = y.modPow(BigInteger.valueOf(2), p).mod(p);144if (!rhs.equals(lhs)) {145throw new ProviderException("point is not on curve");146}147148// check the order of the point149ImmutableIntegerModuloP xElem = ops.getField().getElement(x);150ImmutableIntegerModuloP yElem = ops.getField().getElement(y);151AffinePoint affP = new AffinePoint(xElem, yElem);152byte[] order = key.getParams().getOrder().toByteArray();153ArrayUtil.reverse(order);154Point product = ops.multiply(affP, order);155if (!ops.isNeutral(product)) {156throw new ProviderException("point has incorrect order");157}158159}160161// see JCE spec162@Override163protected byte[] engineGenerateSecret() throws IllegalStateException {164if ((privateKey == null) || (publicKey == null)) {165throw new IllegalStateException("Not initialized correctly");166}167168Optional<byte[]> resultOpt = deriveKeyImpl(privateKey, publicKey);169return resultOpt.orElseGet(170() -> deriveKeyNative(privateKey, publicKey)171);172}173174// see JCE spec175@Override176protected int engineGenerateSecret(byte[] sharedSecret, int177offset) throws IllegalStateException, ShortBufferException {178if (offset + secretLen > sharedSecret.length) {179throw new ShortBufferException("Need " + secretLen180+ " bytes, only " + (sharedSecret.length - offset)181+ " available");182}183byte[] secret = engineGenerateSecret();184System.arraycopy(secret, 0, sharedSecret, offset, secret.length);185return secret.length;186}187188// see JCE spec189@Override190protected SecretKey engineGenerateSecret(String algorithm)191throws IllegalStateException, NoSuchAlgorithmException,192InvalidKeyException {193if (algorithm == null) {194throw new NoSuchAlgorithmException("Algorithm must not be null");195}196if (!(algorithm.equals("TlsPremasterSecret"))) {197throw new NoSuchAlgorithmException198("Only supported for algorithm TlsPremasterSecret");199}200return new SecretKeySpec(engineGenerateSecret(), "TlsPremasterSecret");201}202203private static204Optional<byte[]> deriveKeyImpl(ECPrivateKey priv, ECPublicKey pubKey) {205206ECParameterSpec ecSpec = priv.getParams();207EllipticCurve curve = ecSpec.getCurve();208Optional<ECOperations> opsOpt = ECOperations.forParameters(ecSpec);209if (!opsOpt.isPresent()) {210return Optional.empty();211}212ECOperations ops = opsOpt.get();213if (! (priv instanceof ECPrivateKeyImpl)) {214return Optional.empty();215}216ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) priv;217byte[] sArr = privImpl.getArrayS();218219// to match the native implementation, validate the public key here220// and throw ProviderException if it is invalid221validate(ops, pubKey);222223IntegerFieldModuloP field = ops.getField();224// convert s array into field element and multiply by the cofactor225MutableIntegerModuloP scalar = field.getElement(sArr).mutable();226SmallValue cofactor =227field.getSmallValue(priv.getParams().getCofactor());228scalar.setProduct(cofactor);229int keySize = (curve.getField().getFieldSize() + 7) / 8;230byte[] privArr = scalar.asByteArray(keySize);231232ImmutableIntegerModuloP x =233field.getElement(pubKey.getW().getAffineX());234ImmutableIntegerModuloP y =235field.getElement(pubKey.getW().getAffineY());236AffinePoint affPub = new AffinePoint(x, y);237Point product = ops.multiply(affPub, privArr);238if (ops.isNeutral(product)) {239throw new ProviderException("Product is zero");240}241AffinePoint affProduct = product.asAffine();242243byte[] result = affProduct.getX().asByteArray(keySize);244ArrayUtil.reverse(result);245246return Optional.of(result);247}248249private static250byte[] deriveKeyNative(ECPrivateKey privateKey, ECPublicKey publicKey) {251252ECParameterSpec params = privateKey.getParams();253byte[] s = privateKey.getS().toByteArray();254byte[] encodedParams = // DER OID255ECUtil.encodeECParameterSpec(null, params);256257byte[] publicValue;258if (publicKey instanceof ECPublicKeyImpl) {259ECPublicKeyImpl ecPub = (ECPublicKeyImpl) publicKey;260publicValue = ecPub.getEncodedPublicValue();261} else { // instanceof ECPublicKey262publicValue =263ECUtil.encodePoint(publicKey.getW(), params.getCurve());264}265266try {267return deriveKey(s, publicValue, encodedParams);268269} catch (GeneralSecurityException e) {270throw new ProviderException("Could not derive key", e);271}272}273274275/**276* Generates a secret key using the public and private keys.277*278* @param s the private key's S value.279* @param w the public key's W point (in uncompressed form).280* @param encodedParams the curve's DER encoded object identifier.281*282* @return byte[] the secret key.283*/284private static native byte[] deriveKey(byte[] s, byte[] w,285byte[] encodedParams) throws GeneralSecurityException;286}287288289