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

org.shoulder.crypto.negotiation.util.TransportCryptoUtil Maven / Gradle / Ivy

Go to download

Shoulder 提供的 协商加密模块,用于非信任网络环境下的安全通信。基于 DH + ECC 实现先进的加密算法协商算法,比传统的 DH + DES 协商算法性能显著更高,更安全。

There is a newer version: 1.0.0-M2.2
Show newest version
package org.shoulder.crypto.negotiation.util;

import jakarta.annotation.Nonnull;
import jakarta.annotation.Nullable;
import org.shoulder.core.constant.ByteSpecification;
import org.shoulder.core.util.StringUtils;
import org.shoulder.crypto.asymmetric.exception.AsymmetricCryptoException;
import org.shoulder.crypto.asymmetric.exception.KeyPairException;
import org.shoulder.crypto.negotiation.constant.NegotiationConstants;
import org.shoulder.crypto.negotiation.dto.NegotiationResult;
import org.shoulder.crypto.negotiation.exception.NegotiationException;
import org.shoulder.crypto.negotiation.support.dto.NegotiationRequest;
import org.shoulder.crypto.negotiation.support.dto.NegotiationResponse;
import org.shoulder.crypto.symmetric.exception.SymmetricCryptoException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

/**
 * 为 String 提供适配
 *
 * @author lym
 */
public class TransportCryptoUtil {

    private final TransportCryptoByteUtil adapter;

    public TransportCryptoUtil(TransportCryptoByteUtil adapter) {
        this.adapter = adapter;
    }

    // =========================== 协商阶段相关 ===========================

    /**
     * 生成数据密钥(用于协商完毕,产生加密报文时使用)
     *
     * @return 数据密钥(真正加密数据的)
     */
    public static byte[] generateDataKey(int size) {
        return TransportCryptoByteUtil.generateDataKey(size);
    }

    /**
     * 生成数据密钥的密文(用于协商完毕,产生加密报文时使用,每次请求中)
     *
     * @param negotiationResult 密钥协商结果
     * @param dataKey           数据密钥
     * @return 数据密钥密文 xDk
     */
    public static String encryptDk(NegotiationResult negotiationResult, byte[] dataKey) throws SymmetricCryptoException {
        return ByteSpecification.encodeToString(TransportCryptoByteUtil.encryptDk(negotiationResult, dataKey));
    }

    /**
     * 解密 xDk(处理加密报文时使用)
     *
     * @param negotiationResult 密钥协商结果
     * @param xDk               数据密钥密文
     * @return 数据密钥明文 dataKey
     */
    public static byte[] decryptDk(NegotiationResult negotiationResult, String xDk) throws SymmetricCryptoException {
        return TransportCryptoByteUtil.decryptDk(negotiationResult, ByteSpecification.decodeToBytes(xDk));
    }

    /**
     * 加密数据
     *
     * @param negotiationResult 密钥协商结果
     * @param dataKey           数据密钥明文
     * @param text              数据明文
     * @return 数据密文 cipherText
     */
    public static String encrypt(NegotiationResult negotiationResult, byte[] dataKey, String text) throws SymmetricCryptoException {
        return ByteSpecification.encodeToString(TransportCryptoByteUtil.encrypt(negotiationResult, dataKey, text.getBytes(ByteSpecification.STD_CHAR_SET)));
    }

    /**
     * 解密数据
     *
     * @param negotiationResult 密钥协商结果
     * @param dataKey           数据密钥明文
     * @param cipherText        数据密文
     * @return 数据明文 text
     */
    public static String decrypt(NegotiationResult negotiationResult, byte[] dataKey, String cipherText) throws SymmetricCryptoException {
        return new String(TransportCryptoByteUtil.decrypt(negotiationResult, dataKey, ByteSpecification.decodeToBytes(cipherText)), ByteSpecification.STD_CHAR_SET);
    }

    /**
     * 创建一个协商请求(客户端调用)
     *
     * @return 协商请求体、请求头中需要的内容
     */
    public NegotiationRequest createRequest() throws AsymmetricCryptoException {
        return adapter.createRequest();
    }

    /**
     * 验证 token(服务端处理协商请求前)
     *
     * @param request 待校验的请求:{@link #createRequest} 方法生成结果
     */
    public boolean verifyToken(NegotiationRequest request) throws AsymmetricCryptoException {
        return adapter.verifyRequestToken(request);
    }


    // =========================== 协商完毕,遵守 DH 协议(暂时放这里,方便统一维护) ===========================

    /**
     * 服务端根据协商请求准备协商参数:确定加密算法、密钥长度、协商有效期(服务端调用)
     *
     * @param negotiationRequest 待协商的请求:{@link #createRequest} 方法生成结果
     * @return 协商参数 {@link #negotiation} 方法的入参
     */
    public NegotiationResponse prepareNegotiation(NegotiationRequest negotiationRequest) throws AsymmetricCryptoException {
        return adapter.prepareNegotiation(negotiationRequest);
    }

    // ------------------ 数据密钥处理 ----------------

    /**
     * 协商密钥与 iv(客户端、服务端都会调)
     * 生成 shareKey、根据 shareKey 生成 localKey,localIv
     *
     * @param negotiationResponse 协商参数 {@link #prepareNegotiation} 方法的返回值
     * @return 密钥协商结果
     */
    public NegotiationResult negotiation(NegotiationResponse negotiationResponse) throws KeyPairException, NegotiationException {
        return adapter.negotiation(negotiationResponse);
    }

    /**
     * 根据缓存内容生成握手响应
     *
     * @param negotiationResult 密钥交换的缓存结果
     * @return 服务端返回给客户端的响应,同 {@link #prepareNegotiation}
     */
    public NegotiationResponse createResponse(NegotiationResult negotiationResult) throws AsymmetricCryptoException {
        NegotiationResponse response = new NegotiationResponse();

        byte[] publicKey = negotiationResult.getOtherPublicKey();

        response.setPublicKey(ByteSpecification.encodeToString(publicKey));
        response.setExpireTime((int) (negotiationResult.getExpireTime() - System.currentTimeMillis()));
        response.setKeyBytesLength(negotiationResult.getKeyLength());
        // todo P1【扩展性】不应该写死256,而是支持的密钥算法,如 aes、sm4
        response.setEncryptionScheme(negotiationResult.getEncryptionScheme());

        response.setXSessionId(negotiationResult.getXSessionId());
        // todo P2 【健壮性】处理 token 生成失败
        String token = generateResponseToken(response);
        response.setToken(token);
        return response;
    }


    // ------------------ 数据处理 ----------------

    /**
     * 生成 token(服务端返回协商响应时生成)todo【可读性】考虑放到 {@link #prepareNegotiation} 内实现?
     *
     * @param response {@link #prepareNegotiation} 方法返回值
     * @return token,用于保证 response 不被篡改
     */
    public String generateResponseToken(NegotiationResponse response) throws AsymmetricCryptoException {
        return ByteSpecification.encodeToString(adapter.generateResponseToken(response));
    }

    /**
     * 验证 token(客户端接收服务端返回的协商参数响应前)
     *
     * @param response 客户端收到的,由服务端调用 {@link #prepareNegotiation} 方法的返回值
     * @return 是否合法
     */
    public boolean verifyToken(NegotiationResponse response) throws AsymmetricCryptoException {
        return adapter.verifyResponseToken(response);
    }


    // ------------------------------ 安全保障-防监听篡改/防抵赖 ----------------------------

    /**
     * 生成 token(协商完毕,每次发送安全会话请求时)
     *
     * @param xDk 每次请求发过来的临时密钥
     */
    public String generateToken(String xSessionId, @Nullable String xDk) throws AsymmetricCryptoException {
        return ByteSpecification.encodeToString(
            adapter.generateToken(xSessionId, StringUtils.isEmpty(xDk) ? null : ByteSpecification.decodeToBytes(xDk))
        );
    }

    /**
     * 验证 token(协商完毕,客户端验证服务端响应结果)
     */
    public boolean verifyToken(String xSessionId, String xDk, String token, byte[] otherPublicKey) throws AsymmetricCryptoException {
        return adapter.verifyToken(xSessionId, ByteSpecification.decodeToBytes(xDk), ByteSpecification.decodeToBytes(token), otherPublicKey);
    }

    /**
     * 发起请求前,生成头部信息
     *
     * @param negotiationResult 密钥交换结果
     * @param dataKey           数据密钥明文,如果为 null 表示请求中不带敏感信息,发起请求或收到请求时无需加密或解密
     * @return 请求头
     * @throws AsymmetricCryptoException 签名出错
     * @throws SymmetricCryptoException  加密 dataKey 出错
     */
    public HttpHeaders generateHeaders(NegotiationResult negotiationResult, @Nonnull byte[] dataKey) throws AsymmetricCryptoException, SymmetricCryptoException {
        HttpHeaders headers = new HttpHeaders();
        headers.add(NegotiationConstants.SECURITY_SESSION_ID, negotiationResult.getXSessionId());
        String xDk = encryptDk(negotiationResult, dataKey);
        headers.add(NegotiationConstants.TOKEN, generateToken(negotiationResult.getXSessionId(), xDk));
        headers.add(NegotiationConstants.SECURITY_DATA_KEY, xDk);
        headers.setContentType(MediaType.APPLICATION_JSON);
        return headers;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy