--- /dev/null 2018-02-28 15:06:04.760000000 -0500 +++ new/src/jdk.crypto.ec/share/classes/sun/security/ec/XDHKeyAgreement.java 2018-03-09 11:19:28.594014000 -0500 @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.security.ec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.Key; +import java.security.PublicKey; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.interfaces.XECPrivateKey; +import java.security.interfaces.XECPublicKey; +import java.security.spec.InvalidKeySpecException; +import javax.crypto.KeyAgreementSpi; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import java.security.spec.AlgorithmParameterSpec; + +public class XDHKeyAgreement extends KeyAgreementSpi { + + private byte[] privateKey; + private byte[] secret; + private XECOperations ops; + + @Override + protected void engineInit(Key key, SecureRandom random) + throws InvalidKeyException { + + initImpl(key); + } + + @Override + protected void engineInit(Key key, final AlgorithmParameterSpec params, + SecureRandom random) throws InvalidKeyException, + InvalidAlgorithmParameterException { + + initImpl(key); + + // the private key parameters must match params + XECParameters xecParams = XECParameters.get( + InvalidAlgorithmParameterException::new, params); + if (!xecParams.oidEquals(this.ops.getParameters())) { + throw new InvalidKeyException( + "Incorrect private key parameters" + ); + } + } + + private void initImpl(Key key) throws InvalidKeyException { + + if (!(key instanceof XECPrivateKey)) { + throw new InvalidKeyException + ("Unsupported key type"); + } + XECPrivateKey privateKey = (XECPrivateKey) key; + XECParameters xecParams = XECParameters.get( + InvalidKeyException::new, privateKey.getParams()); + + this.ops = new XECOperations(xecParams); + this.privateKey = privateKey.getScalar().orElseThrow( + () -> new InvalidKeyException("No private key value") + ); + secret = null; + } + + @Override + protected Key engineDoPhase(Key key, boolean lastPhase) + throws InvalidKeyException, IllegalStateException { + + if (this.privateKey == null) { + throw new IllegalStateException("Not initialized"); + } + if (this.secret != null) { + throw new IllegalStateException("Phase already executed"); + } + if (!lastPhase) { + throw new IllegalStateException + ("Only two party agreement supported, lastPhase must be true"); + } + if (!(key instanceof XECPublicKey)) { + throw new InvalidKeyException + ("Unsupported key type"); + } + + XECPublicKey publicKey = (XECPublicKey) key; + + // Ensure public key parameters are compatible with private key + XECParameters xecParams = XECParameters.get(InvalidKeyException::new, + publicKey.getParams()); + if (!ops.getParameters().oidEquals(xecParams)) { + throw new InvalidKeyException( + "Public key parameters are not compatible with private key."); + } + + // The privateKey may be modified to a value that is equivalent for + // the purposes of this algorithm. + byte[] computedSecret = ops.encodedPointMultiply( + this.privateKey, + publicKey.getU()); + + // test for contributory behavior + if (allZero(computedSecret)) { + throw new InvalidKeyException("Point has small order"); + } + + this.secret = computedSecret; + + return null; + } + + /* + * Constant-time check for an all-zero array + */ + private boolean allZero(byte[] arr) { + byte orValue = (byte) 0; + for (int i = 0; i < arr.length; i++) { + orValue |= arr[i]; + } + + return orValue == (byte) 0; + } + + @Override + protected byte[] engineGenerateSecret() throws IllegalStateException { + if (secret == null) { + throw new IllegalStateException("Not initialized correctly"); + } + + return secret.clone(); + } + + @Override + protected int engineGenerateSecret(byte[] sharedSecret, int offset) + throws IllegalStateException, ShortBufferException { + + if (secret == null) { + throw new IllegalStateException("Not initialized correctly"); + } + int secretLen = this.secret.length; + if (offset + secretLen > sharedSecret.length) { + throw new ShortBufferException("Need " + secretLen + + " bytes, only " + (sharedSecret.length - offset) + + " available"); + } + + System.arraycopy(this.secret, 0, sharedSecret, offset, secretLen); + return secret.length; + } + + @Override + protected SecretKey engineGenerateSecret(String algorithm) + throws IllegalStateException, NoSuchAlgorithmException, + InvalidKeyException { + + throw new NoSuchAlgorithmException("Not supported"); + } +}