在TOB业务中部署在服务器中的程序可能会被窃取.对此设计一套安全模块,通过设备信息, 有效期,业务信息的确认来实现业务安全, 主要使用openssl进行加密, upx进行加壳。 为精简服务, 使用模块化方式设计.
openssl
里面实现的方式与传统算法又有一些差异.于是就只用一句话介绍一下使用到的核心算法:
openssl1.1
, 注意版本可以不同, 但是由于openssl之前版本有重大安全风险,虽然这里只是用了加密部分,但是其他业务模块可能用到对应涉及风险的包,所以建议保持版本更新:
1./config shared zlib --prefix=/usr/local/openssl && make && make install gcc ../main.cpp -I ../include/openssl/include -L../include/openssl/libs/libcrypto.a -lssl -lcrypto -ldl -lpthread
链接库, 不然编译的时候会有一系列的undefine问题, 在网上没有找到CMakeLists.txt
, 故将文件粘贴在这里:
1 2 3 4 5 6 7 8 9 10 11cmake_minimum_required(VERSION 3.10) project(rsa) set(CMAKE_CXX_STANDARD 11) set(OPENSSL_USE_STATIC_LIBS TRUE) set(CMAKE_CXX_FLAGS "-O4 -msse2 -msse3 -msse4 -std=c++11") include_directories(./include) add_executable(rsa main.cpp) target_link_libraries(rsa crypto) RSA_generate_key
版本不建议使用,调用RSA_generate_key_ex
即可:
1 2 3 4 5 6 7RSA * rsa = RSA_new(); BIGNUM* bne = BN_new(); if(bne == NULL){ printf("bne null!"); } BN_set_word(bne, RSA_F4); //65537, 标准会推荐素数(公钥) int ret = RSA_generate_key_ex(rsa, kBits, bne, NULL); 发现openssl的结果体定义有个规律, 就是小写_st. 这样的好处是全局搜索的时候可以很快找到 这里列举一下最主要用到的两个结构体
RSA
和BIO
openssl
用于进行内定结果体与外界抽象的类, 封装文件,内存,日志,stdin/stdout,socket,加解密,摘要
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19struct bio_st { const BIO_METHOD *method; /* bio, mode, argp, argi, argl, ret */ long (*callback) (struct bio_st *, int, const char *, int, long, long); char *cb_arg; /* first argument for the callback */ int init; // 初始化标记, 初始化后为1 int shutdown; // 关闭标记, 不为0释放资源 int flags; /* extra storage: 控制函数行为 */ int retry_reason; // socket/ ssl异步阻塞 int num; void *ptr; // 文件句柄/内存地址 struct bio_st *next_bio; /* used by filter BIOs */ struct bio_st *prev_bio; /* used by filter BIOs */ int references; // 被引用数量 uint64_t num_read; // 已读取字节 uint64_t num_write; // 已写入字节 CRYPTO_EX_DATA ex_data; CRYPTO_RWLOCK *lock; }; 项目配置文件独立程序体发布, 对于配置文件, 我们使用RSA2048加密由于明文长度需要小于(kBits/8-11)有以下两个问题
于是业界现有解决方案是混合加密, 也就是RSA2048加密AES秘钥, AES秘钥加密配置文件
/* data structure that contains the key itself */AES_KEY key;/* set the encryption key */AES_set_encrypt_key(ckey, 128, &key);/* set where on the 128 bit encrypted block to begin encryption*/int num = 0;while (1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, ifp); AES_encrypt(indata, outdata, &key); // AES_encrypt(indata, outdata, bytes_read, &key, ivec, &num, // AES_ENCRYPT); printf("encode------\n%s\n-----\n%s\n\n", indata, outdata); bytes_written = fwrite(outdata, 1, bytes_read, ofp); if (bytes_read < AES_BLOCK_SIZE) break;}
/* data structure that contains the key itself */AES_KEY key;/* set the encryption key */AES_set_encrypt_key(ckey, 128, &key);/* set where on the 128 bit encrypted block to begin encryption*/int num = 0;while (1) { bytes_read = fread(indata, 1, AES_BLOCK_SIZE, ifp); AES_encrypt(indata, outdata, &key); // AES_encrypt(indata, outdata, bytes_read, &key, ivec, &num, // AES_ENCRYPT); printf("encode------\n%s\n-----\n%s\n\n", indata, outdata); bytes_written = fwrite(outdata, 1, bytes_read, ofp); if (bytes_read < AES_BLOCK_SIZE) break;}
是不是看完之后就只想说一句woc… 也就是发布出去秘钥无论如何都是不安全的!!! 如果是直接发布AES秘钥可以直接找到 如果发布被RSA2048私钥加密的AES秘钥, 公钥暴露之后也就直接找到AES了.. 甚至可以直接替换公钥伪造license
upx加壳真的方便, upx ./exename 就可以了..
加壳出来文件可以看到是找不到原始字符串的啦!! 而且和源程序跑的结果一样呐 而且包体也变小啦!!
但是加壳容易, 解壳也分分钟哇!!!
这时候我们需要修改加壳程序, 只要改了一个字节, upx就不能顺畅的解密
include\openssl\rsa.h:13:34: fatal error: openssl/opensslconf.h: No such file or directory # include <openssl/opensslconf.h>
: <openssl/opensslconf.h> 是由OpenSSL的Configure命令创建的, 源代码中只有.in文件
set(OPENSSL_USE_STATIC_LIBS TRUE)
即可.