OpenSSL SM4加密 CMake工程链接失败

5 篇文章 0 订阅

 在项目中遇到需要使用sm4加密的功能,同事在一个动态库(C库)里面使用了openssl中的sm4加密,成功编译并功能正常。我也需要在项目(QT程序)中同样的方式使用sm4加密与之通讯,结果我卡在链接的位置无法编程完成,下面是摘出来的demo:

#include <stdio.h>
#include <memory.h>
#include <malloc.h>
#include <openssl/ossl_typ.h>
#include <openssl/aes.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/sm2.h>
#include <openssl/sm4.h>
#include <openssl/evp.h>
#include <openssl/ec.h>

#define PKCS1_HEADER "-----BEGIN RSA PUBLIC KEY-----"
#define PKCS8_HEADER "-----BEGIN PUBLIC KEY-----"


enum EncryptType {
    ET_RSA = 0,
    ET_SM2
};

int main(int argc, char *argv[])
{
    const int tokenSize = 256;
    const int padding = AES_BLOCK_SIZE - tokenSize % AES_BLOCK_SIZE;
    const int blockCount = 256;
    const int bufferSize = blockCount * AES_BLOCK_SIZE;
    char *tokenBuffer = new char[static_cast<size_t>(bufferSize)];
    memset(tokenBuffer, padding, static_cast<size_t>(bufferSize));
    char *ciphertext = new char[static_cast<size_t>(bufferSize)];
    memset(ciphertext, 0, static_cast<size_t>(bufferSize));
    char *symmetricKey = new char[static_cast<size_t>(bufferSize)];
    SM4_KEY sm4;
    AES_KEY aes;
    int ret = 0;
    EncryptType m_encryptType = ET_SM2;
    if (ET_SM2 == m_encryptType) {
        SM4_set_key(reinterpret_cast<uint8_t *>(symmetricKey), &sm4);
    } else {
        AES_set_encrypt_key(reinterpret_cast<unsigned char *>(symmetricKey), strlen(symmetricKey), &aes);
    }
    if (ret < 0) {
        delete[] tokenBuffer;
        delete[] ciphertext;
        return 0;
    }
    unsigned char *iv = new unsigned char[AES_BLOCK_SIZE];
    memset(iv, 0, AES_BLOCK_SIZE);
    if (ET_SM2 == m_encryptType) {
        SM4_encrypt(reinterpret_cast<uint8_t *>(tokenBuffer), reinterpret_cast<uint8_t *>(ciphertext), &sm4);
    } else {
        AES_cbc_encrypt(reinterpret_cast<unsigned char *>(tokenBuffer), reinterpret_cast<unsigned char *>(ciphertext), static_cast<size_t>(bufferSize), &aes, iv, AES_ENCRYPT);
    }

    delete[] ciphertext;
    delete[] tokenBuffer;
    delete[] iv;

    return 0;
}

报错如下:

$ gcc -o libtest.so test.cpp -lstdc++ -lcrypto    

/usr/bin/ld: /tmp/ccR5x6An.o: in function `main':
test.cpp:(.text+0xb0): undefined reference to `SM4_set_key(unsigned char const*, SM4_KEY_st*)'
/usr/bin/ld: test.cpp:(.text+0x14f): undefined reference to `SM4_encrypt(unsigned char const*, unsigned char*, SM4_KEY_st const*)'
collect2: error: ld returned 1 exit status

库肯定是link成功了 ,因为其他的函数都没有报错,只有sm4的程序报了。我也是百思不得其解,我尝试使用同事编译过的项目,发现,加上-shared就能编译通过

gcc -shared -o libtest.so test.cpp -lstdc++ -lcrypto

很离谱,我的QT界面项目当然不能加这个参数。

我就仔细看了下sm4.h,忽然发现头文件中没有用extern "C"修复函数!

C++在编译的过程中会改变函数的名称,与C语言的规则不一致,这样在链接的时候就无法找到C语言对应的函数,从而导致undefined reference!

在需要使用源文件中将原来的include 用extern "C"修饰就可以编译通过了。

#ifdef __cplusplus
extern "C" {
#endif
#include <openssl/sm2.h>
#include <openssl/sm4.h>
#ifdef __cplusplus
}
#endif

CMakeLists

需要注意的几个地方:

# cmake > 3.12 详见https://cmake.org/cmake/help/latest/module/FindOpenSSL.html
find_package(OpenSSL REQUIRED) 

target_link_libraries(${ProjectName} PRIVATE
    ${OPENSSL_CRYPTO_LIBRARY}
)

总结

在C++中使用C库的时候,如果遇到链接问题,要注意C库的头文件中是否使用extern "C"修饰了函数。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用OpenSSL库的SM4加密算法可以分为以下几个步骤: 1. 初始化密钥:通过调用`EVP_BytesToKey`函数生成SM4加密所需的密钥和IV值。 2. 创建并初始化SM4加密上下文:使用`EVP_CIPHER_CTX_new`函数创建一个新的加密上下文,并使用`EVP_EncryptInit_ex`函数初始化SM4加密上下文。 3. 执行加密:使用`EVP_EncryptUpdate`函数执行加密操作,将明文数据分块加密,并将结果输出到缓冲区中。 4. 结束加密操作:使用`EVP_EncryptFinal_ex`函数结束加密操作,并将最后一块数据进行加密。 5. 释放加密上下文:使用`EVP_CIPHER_CTX_free`函数释放加密上下文。 下面是一个简单的C++代码示例,演示如何使用OpenSSL库进行SM4加密操作: ```c++ #include <openssl/evp.h> #include <openssl/rand.h> void sm4_encrypt(const unsigned char *key, const unsigned char *iv, const unsigned char *in, unsigned char *out, size_t len) { EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new(); int outlen, finallen; EVP_EncryptInit_ex(ctx, EVP_sm4_cbc(), NULL, key, iv); EVP_EncryptUpdate(ctx, out, &outlen, in, len); EVP_EncryptFinal_ex(ctx, out + outlen, &finallen); EVP_CIPHER_CTX_free(ctx); } int main() { unsigned char key[16], iv[16]; unsigned char plaintext[] = "hello world"; unsigned char ciphertext[1024]; // 生成16字节的随机密钥和IV值 RAND_bytes(key, 16); RAND_bytes(iv, 16); // 执行SM4加密 sm4_encrypt(key, iv, plaintext, ciphertext, strlen((char *)plaintext)); return 0; } ``` 需要注意的是,上述代码仅供参考,实际使用时需要根据具体需求进行调整和修改。同时,为了保证加密的安全性,建议生成的密钥和IV值应该是随机的,并且要使用安全的随机数生成器进行生成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值