Path: blob/master/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/P11ECDHKeyAgreement.java
41154 views
/*1* Copyright (c) 2006, 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.pkcs11;2627import java.security.*;28import java.security.interfaces.ECPublicKey;29import java.security.spec.AlgorithmParameterSpec;3031import javax.crypto.*;3233import static sun.security.pkcs11.TemplateManager.*;34import sun.security.pkcs11.wrapper.*;35import static sun.security.pkcs11.wrapper.PKCS11Constants.*;3637/**38* KeyAgreement implementation for ECDH.39*40* @author Andreas Sterbenz41* @since 1.642*/43final class P11ECDHKeyAgreement extends KeyAgreementSpi {4445// token instance46private final Token token;4748// algorithm name49private final String algorithm;5051// mechanism id52private final long mechanism;5354// private key, if initialized55private P11Key privateKey;5657// encoded public point, non-null between doPhase() and generateSecret() only58private byte[] publicValue;5960// length of the secret to be derived61private int secretLen;6263P11ECDHKeyAgreement(Token token, String algorithm, long mechanism) {64super();65this.token = token;66this.algorithm = algorithm;67this.mechanism = mechanism;68}6970// see JCE spec71protected void engineInit(Key key, SecureRandom random)72throws InvalidKeyException {73if (key instanceof PrivateKey == false) {74throw new InvalidKeyException75("Key must be instance of PrivateKey");76}77privateKey = P11KeyFactory.convertKey(token, key, "EC");78publicValue = null;79}8081// see JCE spec82protected void engineInit(Key key, AlgorithmParameterSpec params,83SecureRandom random) throws InvalidKeyException,84InvalidAlgorithmParameterException {85if (params != null) {86throw new InvalidAlgorithmParameterException87("Parameters not supported");88}89engineInit(key, random);90}9192// see JCE spec93protected Key engineDoPhase(Key key, boolean lastPhase)94throws InvalidKeyException, IllegalStateException {95if (privateKey == null) {96throw new IllegalStateException("Not initialized");97}98if (publicValue != null) {99throw new IllegalStateException("Phase already executed");100}101if (lastPhase == false) {102throw new IllegalStateException103("Only two party agreement supported, lastPhase must be true");104}105if (key instanceof ECPublicKey == false) {106throw new InvalidKeyException107("Key must be a PublicKey with algorithm EC");108}109ECPublicKey ecKey = (ECPublicKey)key;110int keyLenBits = ecKey.getParams().getCurve().getField().getFieldSize();111secretLen = (keyLenBits + 7) >> 3;112publicValue = P11ECKeyFactory.getEncodedPublicValue(ecKey);113return null;114}115116// see JCE spec117protected byte[] engineGenerateSecret() throws IllegalStateException {118if ((privateKey == null) || (publicValue == null)) {119throw new IllegalStateException("Not initialized correctly");120}121Session session = null;122long privKeyID = privateKey.getKeyID();123try {124session = token.getOpSession();125CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {126new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),127new CK_ATTRIBUTE(CKA_KEY_TYPE, CKK_GENERIC_SECRET),128};129CK_ECDH1_DERIVE_PARAMS ckParams =130new CK_ECDH1_DERIVE_PARAMS(CKD_NULL, null, publicValue);131attributes = token.getAttributes132(O_GENERATE, CKO_SECRET_KEY, CKK_GENERIC_SECRET, attributes);133long keyID = token.p11.C_DeriveKey(session.id(),134new CK_MECHANISM(mechanism, ckParams), privKeyID,135attributes);136attributes = new CK_ATTRIBUTE[] {137new CK_ATTRIBUTE(CKA_VALUE)138};139token.p11.C_GetAttributeValue(session.id(), keyID, attributes);140byte[] secret = attributes[0].getByteArray();141token.p11.C_DestroyObject(session.id(), keyID);142return secret;143} catch (PKCS11Exception e) {144throw new ProviderException("Could not derive key", e);145} finally {146privateKey.releaseKeyID();147publicValue = null;148token.releaseSession(session);149}150}151152// see JCE spec153protected int engineGenerateSecret(byte[] sharedSecret, int154offset) throws IllegalStateException, ShortBufferException {155if (offset + secretLen > sharedSecret.length) {156throw new ShortBufferException("Need " + secretLen157+ " bytes, only " + (sharedSecret.length - offset) + " available");158}159byte[] secret = engineGenerateSecret();160System.arraycopy(secret, 0, sharedSecret, offset, secret.length);161return secret.length;162}163164// see JCE spec165protected SecretKey engineGenerateSecret(String algorithm)166throws IllegalStateException, NoSuchAlgorithmException,167InvalidKeyException {168if (algorithm == null) {169throw new NoSuchAlgorithmException("Algorithm must not be null");170}171if (algorithm.equals("TlsPremasterSecret") == false) {172throw new NoSuchAlgorithmException173("Only supported for algorithm TlsPremasterSecret");174}175return nativeGenerateSecret(algorithm);176}177178private SecretKey nativeGenerateSecret(String algorithm)179throws IllegalStateException, NoSuchAlgorithmException,180InvalidKeyException {181if ((privateKey == null) || (publicValue == null)) {182throw new IllegalStateException("Not initialized correctly");183}184long keyType = CKK_GENERIC_SECRET;185Session session = null;186long privKeyID = privateKey.getKeyID();187try {188session = token.getObjSession();189CK_ATTRIBUTE[] attributes = new CK_ATTRIBUTE[] {190new CK_ATTRIBUTE(CKA_CLASS, CKO_SECRET_KEY),191new CK_ATTRIBUTE(CKA_KEY_TYPE, keyType),192};193CK_ECDH1_DERIVE_PARAMS ckParams =194new CK_ECDH1_DERIVE_PARAMS(CKD_NULL, null, publicValue);195attributes = token.getAttributes196(O_GENERATE, CKO_SECRET_KEY, keyType, attributes);197long keyID = token.p11.C_DeriveKey(session.id(),198new CK_MECHANISM(mechanism, ckParams), privKeyID,199attributes);200CK_ATTRIBUTE[] lenAttributes = new CK_ATTRIBUTE[] {201new CK_ATTRIBUTE(CKA_VALUE_LEN),202};203token.p11.C_GetAttributeValue(session.id(), keyID, lenAttributes);204int keyLen = (int)lenAttributes[0].getLong();205SecretKey key = P11Key.secretKey206(session, keyID, algorithm, keyLen << 3, attributes);207return key;208} catch (PKCS11Exception e) {209throw new InvalidKeyException("Could not derive key", e);210} finally {211privateKey.releaseKeyID();212publicValue = null;213token.releaseSession(session);214}215}216217}218219220