Path: blob/master/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java
41161 views
/*1* Copyright (c) 2018, 2019, 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.security.InvalidAlgorithmParameterException;28import java.security.InvalidKeyException;29import java.security.NoSuchAlgorithmException;30import java.security.Key;31import java.security.SecureRandom;32import java.security.ProviderException;33import java.security.interfaces.XECPrivateKey;34import java.security.interfaces.XECPublicKey;35import java.security.spec.AlgorithmParameterSpec;36import java.security.spec.NamedParameterSpec;37import javax.crypto.KeyAgreementSpi;38import javax.crypto.SecretKey;39import javax.crypto.ShortBufferException;40import javax.crypto.spec.SecretKeySpec;41import java.util.function.Function;4243public class XDHKeyAgreement extends KeyAgreementSpi {4445private byte[] privateKey;46private byte[] secret;47private XECOperations ops;48private XECParameters lockedParams = null;4950XDHKeyAgreement() {51// do nothing52}5354XDHKeyAgreement(AlgorithmParameterSpec paramSpec) {55lockedParams = XECParameters.get(ProviderException::new, paramSpec);56}5758@Override59protected void engineInit(Key key, SecureRandom random)60throws InvalidKeyException {6162initImpl(key);63}6465@Override66protected void engineInit(Key key, final AlgorithmParameterSpec params,67SecureRandom random) throws InvalidKeyException,68InvalidAlgorithmParameterException {6970initImpl(key);7172// the private key parameters must match params, if present73if (params != null) {74XECParameters xecParams = XECParameters.get(75InvalidAlgorithmParameterException::new, params);76if (!xecParams.oidEquals(this.ops.getParameters())) {77throw new InvalidKeyException(78"Incorrect private key parameters"79);80}81}82}8384private85<T extends Throwable>86void checkLockedParams(Function<String, T> exception,87XECParameters params) throws T {8889if (lockedParams != null && lockedParams != params) {90throw exception.apply("Parameters must be " +91lockedParams.getName());92}93}9495private void initImpl(Key key) throws InvalidKeyException {9697if (!(key instanceof XECPrivateKey)) {98throw new InvalidKeyException99("Unsupported key type");100}101XECPrivateKey privateKey = (XECPrivateKey) key;102XECParameters xecParams = XECParameters.get(103InvalidKeyException::new, privateKey.getParams());104checkLockedParams(InvalidKeyException::new, xecParams);105106this.ops = new XECOperations(xecParams);107this.privateKey = privateKey.getScalar().orElseThrow(108() -> new InvalidKeyException("No private key value")109);110secret = null;111}112113@Override114protected Key engineDoPhase(Key key, boolean lastPhase)115throws InvalidKeyException, IllegalStateException {116117if (this.privateKey == null) {118throw new IllegalStateException("Not initialized");119}120if (this.secret != null) {121throw new IllegalStateException("Phase already executed");122}123if (!lastPhase) {124throw new IllegalStateException125("Only two party agreement supported, lastPhase must be true");126}127if (!(key instanceof XECPublicKey)) {128throw new InvalidKeyException129("Unsupported key type");130}131132XECPublicKey publicKey = (XECPublicKey) key;133134// Ensure public key parameters are compatible with private key135XECParameters xecParams = XECParameters.get(InvalidKeyException::new,136publicKey.getParams());137if (!ops.getParameters().oidEquals(xecParams)) {138throw new InvalidKeyException(139"Public key parameters are not compatible with private key.");140}141142// The privateKey may be modified to a value that is equivalent for143// the purposes of this algorithm.144byte[] computedSecret = ops.encodedPointMultiply(145this.privateKey,146publicKey.getU());147148// test for contributory behavior149if (allZero(computedSecret)) {150throw new InvalidKeyException("Point has small order");151}152153this.secret = computedSecret;154155return null;156}157158/*159* Constant-time check for an all-zero array160*/161private boolean allZero(byte[] arr) {162byte orValue = (byte) 0;163for (int i = 0; i < arr.length; i++) {164orValue |= arr[i];165}166167return orValue == (byte) 0;168}169170@Override171protected byte[] engineGenerateSecret() throws IllegalStateException {172if (secret == null) {173throw new IllegalStateException("Not initialized correctly");174}175176byte[] result = secret;177secret = null;178return result;179}180181@Override182protected int engineGenerateSecret(byte[] sharedSecret, int offset)183throws IllegalStateException, ShortBufferException {184185if (secret == null) {186throw new IllegalStateException("Not initialized correctly");187}188int secretLen = this.secret.length;189if (secretLen > sharedSecret.length - offset) {190throw new ShortBufferException("Need " + secretLen191+ " bytes, only " + (sharedSecret.length - offset)192+ " available");193}194195System.arraycopy(this.secret, 0, sharedSecret, offset, secretLen);196secret = null;197return secretLen;198}199200@Override201protected SecretKey engineGenerateSecret(String algorithm)202throws IllegalStateException, NoSuchAlgorithmException,203InvalidKeyException {204205if (algorithm == null) {206throw new NoSuchAlgorithmException("Algorithm must not be null");207}208209if (!(algorithm.equals("TlsPremasterSecret"))) {210throw new NoSuchAlgorithmException(211"Only supported for algorithm TlsPremasterSecret");212}213return new SecretKeySpec(engineGenerateSecret(), algorithm);214}215216static class X25519 extends XDHKeyAgreement {217218public X25519() {219super(NamedParameterSpec.X25519);220}221}222223static class X448 extends XDHKeyAgreement {224225public X448() {226super(NamedParameterSpec.X448);227}228}229}230231232