Mysql UDF 实现sm4加解密(mysql 插件)

udf_sm4.c

/**
 * mysql udf sm4
 *
 * @author xieqiansong@gmail.com
 * @date 2024-05-26
 */
#include <mysql.h>
#include <mysql_com.h>
#include <stdlib.h>
#include <string.h>

#include "sm4.c" // https://github.com/NEWPLAN/SMx/tree/master/SM4/Windows/SM4/src

my_bool encrypt_sm4_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

my_bool decrypt_sm4_init(UDF_INIT *initid, UDF_ARGS *args, char *message);

char *encrypt_sm4(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);

char *decrypt_sm4(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error);

void encrypt_sm4_deinit(UDF_INIT *initid);

void decrypt_sm4_deinit(UDF_INIT *initid);

my_bool encrypt_sm4_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    // 检查参数个数
    if (args->arg_count != 1) {
        strcpy(message, "wrong number of arguments: encrypt_sm4() requires one argument");
        return 1;
    }

    // 检查参数类型
    if (args->arg_type[0] != STRING_RESULT) {
        strcpy(message, "encrypt_sm4() requires a string argument");
        return 1;
    }

    initid->maybe_null = 1;
    initid->max_length = 65535;
    return 0;

}

my_bool decrypt_sm4_init(UDF_INIT *initid, UDF_ARGS *args, char *message) {
    // 检查参数个数
    if (args->arg_count != 1) {
        strcpy(message, "wrong number of arguments: decrypt_sm4() requires one argument");
        return 1;
    }
    // 检查参数类型
    if (args->arg_type[0] != STRING_RESULT) {
        strcpy(message, "decrypt_sm4() requires a string argument");
        return 1;
    }

    initid->maybe_null = 1;
    initid->max_length = 65535;
    return 0;
}


char *do_crypt(UDF_INIT *inisid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error,
               int mode) {
    if (args->args[0] == NULL) {
        *is_null = 1;
        return NULL;
    }
    // 入参以及入参长度
    char *text = args->args[0];
    int input_length = args->lengths[0];

    // 构建加解密入参和出参
    int max_len = input_length + 20;
    char *input = (char *) malloc(max_len * sizeof(char));
    char *output = (char *) malloc(max_len * sizeof(char));

    if (input == NULL || output == NULL) {
        *is_null = 1;
        return NULL;
    }
    memset(input, 0, max_len * sizeof(char));
    memset(output, 0, max_len * sizeof(char));

    // args->args[0] 执行一次sql时是复用的,所以必须通过 input_length 来复制
    memcpy(input, text, input_length);

    // --------------------------------  加解密  Start --------------------------------
    sm4_context ctx;
    char *key = "0000000000000000"; // 密钥好像要求16个字符
    int encrypt_len = (input_length + 15) & ~15;

    if (mode == 1) {
        sm4_setkey_enc(&ctx, (unsigned char *) key);
        sm4_crypt_ecb(&ctx, mode, encrypt_len, (unsigned char *) input, (unsigned char *) output);
        *length = encrypt_len;
    } else {
        sm4_setkey_dec(&ctx, (unsigned char *) key);
        sm4_crypt_ecb(&ctx, mode, encrypt_len, (unsigned char *) input, (unsigned char *) output);
        *length = strlen(output);
    }
    // --------------------------------  加解密 End --------------------------------

    // *length 出参长度
    // *length = mode == 1 ? encrypt_len : strlen(output);
    *is_null = 0;
    return output;
}

char *encrypt_sm4(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
    return do_crypt(initid, args, result, length, is_null, error, 1);
}

char *decrypt_sm4(UDF_INIT *initid, UDF_ARGS *args, char *result, unsigned long *length, char *is_null, char *error) {
    return do_crypt(initid, args, result, length, is_null, error, 0);
}

void encrypt_sm4_deinit(UDF_INIT *initid) {
}

void decrypt_sm4_deinit(UDF_INIT *initid) {
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.27)
project(mysql_udf C)
set(CMAKE_C_STANDARD 11)

# 添加MySQL头文件夹路径
include_directories(D:/platform/middleware/mysql-5.7/include)

# 添加库文件并打包为DLL
add_library(mysql_udf SHARED udf_sm4.c)

# 在 Windows 平台上添加额外属性
if(WIN32)
    set_target_properties(mysql_udf PROPERTIES
            WIN32_EXECUTABLE TRUE
            EXPORT_NAME mysql_udf)
endif()

Windows下我用的Clion编译的


Linux可以参考这个

g++ -I /usr/include/mysql -shared -fPIC -o udf_sm4.so udf_sm4.c
cp udf_sm4.so /usr/lib64/mysql/plugin/

生成dll或so复制文件到目录、引入函数


-- 复制到这个目录下
show variables like "%plugin_dir%";

DROP FUNCTION IF EXISTS encrypt_sm4;
DROP FUNCTION IF EXISTS decrypt_sm4;
CREATE FUNCTION encrypt_sm4 RETURNS string SONAME 'libmysql_udf.dll';
CREATE FUNCTION decrypt_sm4 RETURNS string SONAME 'libmysql_udf.dll';


-- 测试UDF 没有结果应该就是成功了
select description,
       encrypt_sm4(description)                            en_description,
       length(encrypt_sm4(description))                    en_description_len,
       decrypt_sm4(encrypt_sm4(description))               de_description,
       cast(decrypt_sm4(encrypt_sm4(description)) as char) de_description_char,
       length(decrypt_sm4(encrypt_sm4(description)))       de_description_len
from mysql.help_topic
where description != cast(decrypt_sm4(encrypt_sm4(description)) as char);

要注意的地方,机器上已经安装了mysql才能编译,因为要引入mysql的头文件。编写UDF的时候注意入参和出参的长度。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值