
/*
 * @Author: ybzhou yibo.zhou@lnxall.com
 * @Date: 2026-08-08 14:28:41
 * @LastEditors: ybzhou yibo.zhou@lnxall.com
 * @LastEditTime: 2026-08-25 13:27:57
 * @FilePath: /release-v2.10.x/proto_forward/src/frpc_cut/rsa.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include <stdlib.h>
#include <netinet/in.h>
#include <stdatomic.h>
#include <stdio.h>
#include <string.h>
#include <sys/epoll.h>
// #include "../common.h"
#include <bits/types/struct_timeval.h>
#include <pthread.h>
#include <sys/epoll.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/syslog.h>
#include <unistd.h>
#include <ctype.h>

#include <openssl/evp.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>

#include "rsa.h"
#include "frpc_cut.h"

static EVP_PKEY *load_pubkey_from_file(const char *filename)
{
    FILE *fp = fopen(filename, "rb");
    if (fp == NULL) {
        perror("fopen");
        return NULL;
    }
    EVP_PKEY *key = PEM_read_PUBKEY(fp, NULL, NULL, NULL);
    fclose(fp);
    return key;
}

static EVP_PKEY *load_privkey_from_file(const char *filename, const char *passphrase)
{
    FILE *fp = fopen(filename, "rb");
    if (fp == NULL) {
        perror("fopen");
        return NULL;
    }
    EVP_PKEY *key;
    if (passphrase != NULL) {
        key = PEM_read_PrivateKey(fp, NULL, NULL, (void *)passphrase);
    } 
    else {
        key = PEM_read_PrivateKey(fp, NULL, NULL, NULL);
    }
    fclose(fp);
    return key;
}

#if 0
// 使用 EVP API（推荐方式，OpenSSL 官方推荐）支持 OAEP / PKCS1 等多种填充模式，自动处理密钥类型

/**
 * rsa_encrypt - 使用 RSA 公钥加密数据
 *
 * @pubkey:     RSA 公钥 (EVP_PKEY*)
 * @plaintext:  明文数据
 * @plaintext_len: 明文长度
 * @ciphertext: 输出密文缓冲区（由函数分配内存，调用者负责释放）
 * @ciphertext_len: 输出密文长度
 * @padding:    填充模式 (RSA_PKCS1_OAEP_PADDING / RSA_PKCS1_PADDING 等)
 *
 * 返回值: 1 成功, 0 失败
 */
static int rsa_encrypt(EVP_PKEY *pubkey,
                const unsigned char *plaintext, size_t plaintext_len,
                unsigned char **ciphertext, size_t *ciphertext_len,
                int padding)
{
    EVP_PKEY_CTX *ctx = NULL;
    size_t outlen;
    int ret = 0;

    if (pubkey == NULL || plaintext == NULL || ciphertext == NULL)
        return 0;

    *ciphertext = NULL;
    *ciphertext_len = 0;

    // 创建加密上下文
    ctx = EVP_PKEY_CTX_new(pubkey, NULL);
    if (ctx == NULL) {
        ERR_print_errors_fp(stderr);
        return 0;
    }

    if (EVP_PKEY_encrypt_init(ctx) <= 0) {
        ERR_print_errors_fp(stderr);
        goto err;
    }

    // 设置填充模式
    if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0) {
        ERR_print_errors_fp(stderr);
        goto err;
    }

    // 第一次调用: 传入 out=NULL 获取所需输出缓冲区大小
    if (EVP_PKEY_encrypt(ctx, NULL, &outlen, plaintext, plaintext_len) <= 0) {
        ERR_print_errors_fp(stderr);
        goto err;
    }

    *ciphertext = OPENSSL_malloc(outlen);
    if (*ciphertext == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        goto err;
    }

    // 执行加密
    if (EVP_PKEY_encrypt(ctx, *ciphertext, &outlen,
                         plaintext, plaintext_len) <= 0) {
        ERR_print_errors_fp(stderr);
        OPENSSL_free(*ciphertext);
        *ciphertext = NULL;
        goto err;
    }

    *ciphertext_len = outlen;
    ret = 1;

err:
    EVP_PKEY_CTX_free(ctx);
    return ret;
}

/**
 * rsa_decrypt - 使用 RSA 私钥解密数据
 *
 * @privkey:     RSA 私钥 (EVP_PKEY*)
 * @ciphertext:  密文数据
 * @ciphertext_len: 密文长度
 * @plaintext:   输出明文缓冲区（由函数分配内存，调用者负责释放）
 * @plaintext_len: 输出明文长度
 * @padding:     填充模式（需与加密时一致）
 *
 * 返回值: 1 成功, 0 失败
 */
static int rsa_decrypt(EVP_PKEY *privkey,
                const unsigned char *ciphertext, size_t ciphertext_len,
                unsigned char **plaintext, size_t *plaintext_len,
                int padding)
{
    EVP_PKEY_CTX *ctx = NULL;
    size_t outlen;
    int ret = 0;

    if (privkey == NULL || ciphertext == NULL || plaintext == NULL)
        return 0;

    *plaintext = NULL;
    *plaintext_len = 0;

    // 创建解密上下文
    ctx = EVP_PKEY_CTX_new(privkey, NULL);
    if (ctx == NULL) {
        ERR_print_errors_fp(stderr);
        return 0;
    }

    if (EVP_PKEY_decrypt_init(ctx) <= 0) {
        ERR_print_errors_fp(stderr);
        goto err;
    }

    // 设置填充模式
    if (EVP_PKEY_CTX_set_rsa_padding(ctx, padding) <= 0) {
        ERR_print_errors_fp(stderr);
        goto err;
    }

    // 第一次调用: 传入 out=NULL 获取所需输出缓冲区大小
    if (EVP_PKEY_decrypt(ctx, NULL, &outlen, ciphertext, ciphertext_len) <= 0) {
        ERR_print_errors_fp(stderr);
        goto err;
    }

    *plaintext = OPENSSL_malloc(outlen + 1);  /* +1 用于 null 终止符 */
    if (*plaintext == NULL) {
        fprintf(stderr, "Memory allocation failed\n");
        goto err;
    }

    // 执行解密
    if (EVP_PKEY_decrypt(ctx, *plaintext, &outlen,
                         ciphertext, ciphertext_len) <= 0) {
        ERR_print_errors_fp(stderr);
        OPENSSL_free(*plaintext);
        *plaintext = NULL;
        goto err;
    }

    (*plaintext)[outlen] = '\0';
    *plaintext_len = outlen;
    ret = 1;

err:
    EVP_PKEY_CTX_free(ctx);
    return ret;
}
#endif

/**
 * rsa_encrypt_raw - 使用低层 RSA API 加密（rsautl.c 风格）
 *
 * 注意: 此方式要求 pubkey 必须是 RSA 类型，不支持其他公钥算法。
 *        新代码请优先使用 rsa_encrypt()（EVP API）。
 */
static int rsa_encrypt_raw(EVP_PKEY *pubkey,
                    const unsigned char *plaintext, size_t plaintext_len,
                    unsigned char **ciphertext, size_t *ciphertext_len,
                    int padding)
{
    RSA *rsa = NULL;
    int ret = 0;

    if (pubkey == NULL || plaintext == NULL || ciphertext == NULL)
        return 0;

    *ciphertext = NULL;
    *ciphertext_len = 0;

    // 从 EVP_PKEY 中提取 RSA 密钥
    rsa = EVP_PKEY_get1_RSA(pubkey);
    if (rsa == NULL) {
        ems_syslog(LOG_ERR, "Error: key is not an RSA key!!!");
        return 0;
    }

    int rsa_size = RSA_size(rsa);
    *ciphertext = OPENSSL_malloc(rsa_size);
    if (*ciphertext == NULL) {
        ems_syslog(LOG_ERR, "Memory allocation failed!!!");
        goto err;
    }

    int outlen = RSA_public_encrypt((int)plaintext_len, plaintext,
                                    *ciphertext, rsa, padding);
    if (outlen < 0) {
        ERR_print_errors_fp(stderr);
        OPENSSL_free(*ciphertext);
        *ciphertext = NULL;
        goto err;
    }

    *ciphertext_len = (size_t)outlen;
    ret = 1;

err:
    RSA_free(rsa);
    return ret;
}

/**
 * rsa_decrypt_raw - 使用低层 RSA API 解密（rsautl.c 风格）
 */
static int rsa_decrypt_raw(EVP_PKEY *privkey,
                    const unsigned char *ciphertext, size_t ciphertext_len,
                    unsigned char **plaintext, size_t *plaintext_len,
                    int padding)
{
    RSA *rsa = NULL;
    int ret = 0;

    if (privkey == NULL || ciphertext == NULL || plaintext == NULL)
        return 0;

    *plaintext = NULL;
    *plaintext_len = 0;

    // 从 EVP_PKEY 中提取 RSA 密钥
    rsa = EVP_PKEY_get1_RSA(privkey);
    if (rsa == NULL) {
        ems_syslog(LOG_ERR, "Error: key is not an RSA key!!!");
        return 0;
    }

    int rsa_size = RSA_size(rsa);
    *plaintext = OPENSSL_malloc(rsa_size);
    if (*plaintext == NULL) {
        ems_syslog(LOG_ERR, "Memory allocation failed!!!");
        goto err;
    }

    int outlen = RSA_private_decrypt((int)ciphertext_len, ciphertext,
                                     *plaintext, rsa, padding);
    if (outlen < 0) {
        ERR_print_errors_fp(stderr);
        OPENSSL_free(*plaintext);
        *plaintext = NULL;
        goto err;
    }

    (*plaintext)[outlen] = '\0';
    *plaintext_len = (size_t)outlen;
    ret = 1;

err:
    RSA_free(rsa);
    return ret;
}

int rsa_encrypt_b64(char *str, size_t str_len)
{
    int ret = EXIT_FAILURE;
    frpc_cut_t *frpc_cut = get_frpc_cut();

    ems_syslog(LOG_INFO, "text %s", str);
    
    /* 初始化 OpenSSL */
    OpenSSL_add_all_algorithms();     
    ERR_load_crypto_strings();

    EVP_PKEY *pubkey = load_pubkey_from_file(RSA_PUBLIC_KEY_PATH);
    if (pubkey == NULL) {
        ems_syslog(LOG_ERR, "pubkey generation failed!!!");
        goto cleanup;
    }

    unsigned char *ciphertext = NULL;
    size_t ciphertext_len = 0;

    if (!rsa_encrypt_raw(pubkey,
                         (const unsigned char *)str, str_len,
                         &ciphertext, &ciphertext_len,
                         RSA_PKCS1_OAEP_PADDING)) {
        ems_syslog(LOG_ERR, "Raw RSA encryption failed!!!");
        goto cleanup;
    }
    ems_syslog(LOG_INFO, "Done. Ciphertext length: %zu bytes", ciphertext_len);

    b64_encode(ciphertext, ciphertext_len, frpc_cut->sen_buf, MAX_BUF); // base64 编码
    ems_syslog(LOG_INFO, "sen_buf: %s", frpc_cut->sen_buf);

    ret = EXIT_SUCCESS;
    OPENSSL_free(ciphertext);

cleanup:
    EVP_PKEY_free(pubkey);

    /* 清理 OpenSSL */
    EVP_cleanup();
    ERR_free_strings();

    return ret;
}

int rsa_decrypt_b64(char *str, size_t str_len)
{
    int ret = EXIT_FAILURE;
    frpc_cut_t *frpc_cut = get_frpc_cut();

    ems_syslog(LOG_INFO, "rev_buf: %s", frpc_cut->rev_buf);

    /* 初始化 OpenSSL */
    OpenSSL_add_all_algorithms();
    ERR_load_crypto_strings();
    
    EVP_PKEY *privkey = load_privkey_from_file(RSA_PRIVATE_KEY_PATH, RSA_PASSWD);
    if (privkey == NULL) {
        ems_syslog(LOG_ERR, "privkey generation failed!!!");
        goto cleanup;
    }

    unsigned char ciphertext[MAX_BUF] = {0};
    size_t ciphertext_len = b64_decode(frpc_cut->rev_buf, ciphertext, MAX_BUF); // base64 解码
 
    unsigned char *decrypted = NULL;
    size_t decrypted_len = 0;

    if (!rsa_decrypt_raw(privkey,
                         ciphertext, ciphertext_len,
                         &decrypted, &decrypted_len,
                         RSA_PKCS1_OAEP_PADDING)) {
        ems_syslog(LOG_ERR, "Raw RSA decryption failed!!!");
        goto cleanup;
    }
    ems_syslog(LOG_INFO, "Done. Decrypted text (%zu bytes)", decrypted_len);
    ems_syslog(LOG_INFO, "text %s", decrypted);

    snprintf(str, str_len, "%s", decrypted); //

    ret = EXIT_SUCCESS;
    OPENSSL_free(decrypted);

cleanup:
    EVP_PKEY_free(privkey);

    /* 清理 OpenSSL */
    EVP_cleanup();
    ERR_free_strings();

    return ret;
}
