All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openeuler.sun.security.ssl.ECCKeyAgreement Maven / Gradle / Ivy

/*
 * Copyright (c) 2023, Huawei Technologies Co., Ltd. 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.  Huawei designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Huawei 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 visit https://gitee.com/openeuler/bgmprovider if you need additional
 * information or have any questions.
 */

package org.openeuler.sun.security.ssl;

import org.openeuler.spec.ECCPremasterSecretKeySpec;
import org.openeuler.sun.security.internal.spec.TlsECCKeyAgreementParameterSpec;
import sun.security.internal.spec.TlsRsaPremasterSecretParameterSpec;
import sun.security.util.KeyUtil;

import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import java.security.*;
import java.security.spec.AlgorithmParameterSpec;

public class ECCKeyAgreement extends KeyAgreementSpi {

    private final static String MSG = "ECCKeyAgreement must be "
            + "initialized using a TlsECCKeyAgreementParameterSpec";

    private TlsECCKeyAgreementParameterSpec spec;

    private SecureRandom random;

    // creat need publicKey, decode need privateKey.
    private Key key;

    private static final int ECC_PREMASTER_KEY_LEN = 48;

    @Override
    protected void engineInit(Key key, SecureRandom random) throws InvalidKeyException {
        throw new UnsupportedOperationException(MSG);
    }

    @Override
    protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
        if (!(params instanceof TlsECCKeyAgreementParameterSpec)) {
            throw new InvalidAlgorithmParameterException(MSG);
        }
        this.key = key;
        this.spec = (TlsECCKeyAgreementParameterSpec) params;
        this.random = random;
    }

    @Override
    protected Key engineDoPhase(Key key, boolean lastPhase) throws IllegalStateException {
        throw new UnsupportedOperationException("ECCKeyAgreement not support engineDoPhase.");
    }

    @Override
    protected byte[] engineGenerateSecret() throws IllegalStateException {
        throw new UnsupportedOperationException("ECCKeyAgreement.engineGenerateSecret not support the return byte[].");
    }

    @Override
    protected int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException {
        throw new UnsupportedOperationException("ECCKeyAgreement.engineGenerateSecret not support the return int.");
    }

    @Override
    protected SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, InvalidKeyException {
        byte[] premasterSecret;
        byte[] encryptedKey;
        if (spec == null) {
            throw new IllegalStateException(
                    "ECCKeyAgreement.TlsECCKeyAgreementParameterSpec must be initialized");
        }
        try {
            if (spec.isClient()) {
                premasterSecret = generatePreMasterSecret(spec.getMajorVersion(), spec.getMinorVersion(), null);
                encryptedKey = encryptSecret(premasterSecret);
                return new ECCPremasterSecretKeySpec(premasterSecret,"TlsEccPremasterSecret", encryptedKey);
            }
            premasterSecret = decryptSecret();
            encryptedKey = spec.getEncryptedSecret();
        } catch (GeneralSecurityException e) {
            throw new IllegalStateException(e.getMessage(), e.getCause());
        }

        return new ECCPremasterSecretKeySpec(premasterSecret,"TlsEccPremasterSecret", encryptedKey);
    }

    private byte[] encryptSecret(byte[] premasterSecret) throws NoSuchAlgorithmException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
        if (key == null) {
            throw new IllegalStateException(
                    "Key must be initialized");
        }
        if(!(key instanceof PublicKey)) {
            throw new IllegalStateException(
                    "decode need PublicKey");
        }
        Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_SM2);
        cipher.init(Cipher.ENCRYPT_MODE, key, random);
        return cipher.doFinal(premasterSecret);
    }

    private byte[] generatePreMasterSecret(int clientVersion, int serverVersion, byte[] encodedSecret) {
        if (encodedSecret == null) {
            if (random == null) {
                random = new SecureRandom();
            }
            encodedSecret = new byte[ECC_PREMASTER_KEY_LEN];
            random.nextBytes(encodedSecret);
        }
        encodedSecret[0] = (byte)clientVersion;
        encodedSecret[1] = (byte)serverVersion;

        return encodedSecret;
    }

    private byte[] decryptSecret() throws GeneralSecurityException {
        if (key == null) {
            throw new IllegalStateException(
                    "Key must be initialized");
        }
        if(!(key instanceof PrivateKey)) {
            throw new IllegalStateException(
                    "decode need PrivateKey");
        }
        if (spec.getEncryptedSecret() == null) {
            throw new IllegalStateException(
                    "TlsECCKeyAgreementParameterSpec.encryptedSecret must be initialized");
        }

        byte[] encoded = null;
        byte[] preMaster = null;
        Cipher cipher = JsseJce.getCipher(JsseJce.CIPHER_SM2);
        try {
            // Use DECRYPT_MODE and dispose the previous initialization.
            cipher.init(Cipher.DECRYPT_MODE, key);
            boolean failed = false;
            try {
                encoded = cipher.doFinal(spec.getEncryptedSecret());
            } catch (BadPaddingException bpe) {
                // Note: encoded == null
                failed = true;
            }
            encoded = KeyUtil.checkTlsPreMasterSecretKey(
                    spec.getClientVersion(), spec.getServerVersion(),
                    random, encoded, failed);
            preMaster = generatePreMasterSecret(spec.getClientVersion(), spec.getServerVersion(), encoded);
        } catch (InvalidKeyException | UnsupportedOperationException iue) {
            if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                SSLLogger.warning("The Cipher provider "
                        + safeProviderName(cipher)
                        + " caused exception: " + iue.getMessage());
            }
        }
        return preMaster;
    }

    /*
     * Retrieving the cipher's provider name for the debug purposes
     * can throw an exception by itself.
     */
    private static String safeProviderName(Cipher cipher) {
        try {
            return cipher.getProvider().toString();
        } catch (Exception e) {
            if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                SSLLogger.fine("Retrieving The Cipher provider name" +
                        " caused exception ", e);
            }
        }
        try {
            return cipher.toString() + " (provider name not available)";
        } catch (Exception e) {
            if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) {
                SSLLogger.fine("Retrieving The Cipher name" +
                        " caused exception ", e);
            }
        }

        return "(cipher/provider names not available)";
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy