1. 安装c++
在 CentOS7 上,可以使用 yum 包管理器来安装 C++11 的开发工具和库。具体步骤如下:
1.1 更新系统软件包到最新版本:
sudo yum update #更新
1.2 安装 C++11 开发工具和库:
sudo yum install gcc-c++ -y
sudo yum install libstdc++-devel -y
以上命令会安装GNU C++编译器和标准C++库的开发文件,包括头文件和库文件。其中,gcc-c++是C++编译器,libstdc+±devel是标准C++库的开发文件。
1.3 检查安装是否成功:
gcc --version
g++ --version
2. 测试程序
2.1 创建项目目录
在test目录下,创建项目目录secretkey,在该目录下创建src、obj、lib和include分别用来保存.cpp源文件、过程文件.o、生成的动态库文件.so和头文件.h,主函数创建在主目录下。
2.2 创建Makefile编译脚本文件
根据程序文件的名称,创建编译脚本,使用make执行,实现动态库编译
此处避坑,PROJECT=libprint_func.so 后面的名称必须要加上’lib’,否则编译调用函数时,无法找到该动态库文件,即原程序名称为print_func,加上lib生成动态库
#生成的动态库文件名
PROJECT=libprint_func.so
#使用的编译器,如果用c语言则使用gcc
CC=g++
#源文件保存路径,使用通配符wildcard在路径src目录下查找.cpp文件,如果用c语言则为*.c
SOURCES=$(wildcard src/*.cpp)
#patsubst函数用于将文件模式进行替换,$(patsubst 原模式, 目标模式, 文件列表)
OBJECTS=$(patsubst %.cpp,%.o,$(SOURCES))
.PHONY:clean
CFLAG = -Iinclude -fPIC -shared
LD_FLAG = -fPIC -s -Wl,-z,relro,-z,now,-z,noexecstack -fstack-protector-all
$(PROJECT): $(OBJECTS)
mkdir -p lib
$(CC) -shared -o lib/$@ $(patsubst %.o,obj/%.o,$(notdir $(OBJECTS))) $(LD_FLAG)
@echo "finish $(PROJECT)"
.cpp.o:
@mkdir -p obj
$(CC) -c $< $(CFLAG) -o obj/$(patsubst %.cpp,%.o,$(notdir $<))
clean:
-rm -rf obj lib
$echo "clean up."
2.3 创建程序文件
分别在src中创建.cpp文件,在include中创建.h文件,在secretkey主目录下创建main.cpp文件,并分别敲入c++代码
transfer.cpp
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<string>
//字符数组,用于随机数匹配
unsigned char Number[10] ={'0','1','2','3','4','5','6','7','8','9'};
unsigned char Letters[52]={'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
//long型转换成字符
bool transferLong2ByteArray(unsigned char* byte, unsigned char length, unsigned long version){
unsigned long temp = version;
for(unsigned char i = 0; i < length; ++i){
unsigned char res = (unsigned char)(temp & 0xff);
byte[i] = res;
temp = temp >> 8;
}
return true;
}
//字符转换成long型
unsigned long transferByteArrayToLong(unsigned char* byte, unsigned char length)
{
unsigned long version = 0;
#if 1
for(unsigned int i = 0; i < length; ++i){
unsigned long temp = byte[i];
version |= (temp << i * 8);
}
#else
long s = 0;
long s0 = (byte[0] & 0xff);
long s1 = (byte[1] & 0xff) << 8;
long s2 = (byte[2] & 0xff) << 16;
long s3 = (byte[3] & 0xff << 24);
version = s0 | s1 | s2 | s3;
#endif
return version;
}
//数组内随机数处理函数
void generateString(unsigned char * dest, unsigned int len)
{
unsigned int cnt, randNo;
srand((unsigned int)time(NULL));
for (cnt = 0; cnt<len; cnt++)
{
randNo = rand() % 51;
*dest = Letters[randNo];
dest++;
}
}
//char数组复制处理函数,不固定起始位置
void my_strcpy_array(unsigned char *str, unsigned char *arr, int start, int end)
{
int num = 0;
for(num = start; num <= end-1; num++)
{
str[num - start] = arr[num];
}
}
//char数组复制处理函数,固定起始位置
void my_strcpy_array1(unsigned char *str, unsigned char *arr, int len)
{
int num = 0;
for(num = 0; num <= len-1; num++)
{
str[num] = arr[num];
}
}
//解密算法函数,字符串输入进行解密,返回long型
void decrypt_func(unsigned char *decrypt, unsigned char *encryptedData, unsigned char *keyData,unsigned char *keyPeriod)
{
unsigned char kyd[10][5],kyp[10][2];
int i,j;
for(i=0; i<10;i++)
{
for(j=0; j<5;i++)
{
my_strcpy_array(kyd[i],keyData,i*5,i*5+5);
}
}
for(i=0; i<10;i++)
{
printf("kyd: %s\n",kyd[i]);
}
}
//加密算法函数
void encrypted_func(unsigned char *encryptedData,unsigned char *keyData,unsigned char *keyPeriod,long data1, long data2)
{
char tmp1[10] = "", tmp2[8] = "";
sprintf(tmp1, "%d", data1);
printf("tmp1 = %s\n", tmp1);
sprintf(tmp2, "%d", data2);
printf("tmp2 = %s\n", tmp2);
//想复杂了,在C++的库里可以用上面的方式完美解决long转字符串
//unsigned long endDate = (unsigned long)IN;
//unsigned char byte[4] = { 0 };
//transferLong2ByteArray(byte, 4, endDate);
//unsigned long finalDate = transferByteArrayToLong(byte, 4);
//printf("finalDate: %ld\n", finalDate);
//秘钥随机数处理
unsigned int i = 0, j = 0, randNo = 0;
srand((unsigned)time(NULL));
for(i=0; i < 10; i++)
{
for(j=0; j<5; j++)
{
randNo = rand() % 51;
keyData[i*5 +j] = Letters[randNo];
}
}
printf("keyData: %s\n", keyData);
//秘钥期限随机数处理
for(i=0; i < 10; i++)
{
for(j=0; j<2; j++)
{
randNo = rand() % 51;
keyPeriod[i*2 +j] = Letters[randNo];
}
}
printf("keyPeriod: %s\n", keyPeriod);
//平台使用期加密
unsigned char transferKeyData[5];
unsigned int itmp1 = 0;
for(i=0; i<sizeof(tmp1); i++)
{
itmp1 = (unsigned int)tmp1[i];
if(itmp1 == 48){my_strcpy_array(transferKeyData, keyData, 0, 5);}
else if(itmp1 == 49){my_strcpy_array(transferKeyData, keyData, 5, 10);}
else if(itmp1 == 50){my_strcpy_array(transferKeyData, keyData, 10, 15);}
else if(itmp1 == 51){my_strcpy_array(transferKeyData, keyData, 15, 20);}
else if(itmp1 == 52){my_strcpy_array(transferKeyData, keyData, 20, 25);}
else if(itmp1 == 53){my_strcpy_array(transferKeyData, keyData, 25, 30);}
else if(itmp1 == 54){my_strcpy_array(transferKeyData, keyData, 30, 35);}
else if(itmp1 == 55){my_strcpy_array(transferKeyData, keyData, 35, 40);}
else if(itmp1 == 56){my_strcpy_array(transferKeyData, keyData, 40, 45);}
else if(itmp1 == 57){my_strcpy_array(transferKeyData, keyData, 45, 50);}
my_strcpy_array1(encryptedData + i*5, transferKeyData, 5);
}
//秘钥使用期加密
unsigned char keyPeriodData[5];
unsigned int itmp2 = 0;
for(i=0; i<sizeof(tmp2); i++)
{
itmp2 = (unsigned int)tmp2[i];
if(itmp2 == 48){my_strcpy_array(keyPeriodData, keyPeriod, 0, 2);}
else if(itmp2 == 49){my_strcpy_array(keyPeriodData, keyPeriod, 2, 4);}
else if(itmp2 == 50){my_strcpy_array(keyPeriodData, keyPeriod, 4, 6);}
else if(itmp2 == 51){my_strcpy_array(keyPeriodData, keyPeriod, 6, 8);}
else if(itmp2 == 52){my_strcpy_array(keyPeriodData, keyPeriod, 8, 10);}
else if(itmp2 == 53){my_strcpy_array(keyPeriodData, keyPeriod, 10, 12);}
else if(itmp2 == 54){my_strcpy_array(keyPeriodData, keyPeriod, 12, 14);}
else if(itmp2 == 55){my_strcpy_array(keyPeriodData, keyPeriod, 14, 16);}
else if(itmp2 == 56){my_strcpy_array(keyPeriodData, keyPeriod, 16, 18);}
else if(itmp2 == 57){my_strcpy_array(keyPeriodData, keyPeriod, 18, 20);}
my_strcpy_array1(encryptedData + 50 + i*2, keyPeriodData, 2);
}
printf("encryptedData: %s\n", encryptedData);
}
long print_func(long endTime, long keyTime)
{
long t_currentTime;
long t_endTime = (long)endTime;
long t_keyTime = (long)keyTime;
time_t timer0;
int i = 0;
unsigned char retEncrypted[70];
unsigned char retkeyData[50];
unsigned char retkeyPeriod[20];
unsigned char retdecrypt[10];
//数据加密
encrypted_func(retEncrypted, retkeyData, retkeyPeriod, t_keyTime, t_endTime);
printf("encrypted_func: %s--%s--%s\n", retEncrypted, retkeyData, retkeyPeriod);
//数据解密
decrypt_func(retdecrypt, retEncrypted, retkeyData, retkeyPeriod);
printf("retdecrypt data: %s\n", retdecrypt);
struct tm* pPeriodTime = localtime(&t_endTime);
printf("Limit date:%d-%d-%d", pPeriodTime->tm_year + 1900, pPeriodTime->tm_mon + 1, pPeriodTime->tm_mday);
printf(" %d:%d:%d\n",pPeriodTime->tm_hour,pPeriodTime->tm_min,pPeriodTime->tm_sec);
timer0 = time(NULL);
t_currentTime = (long)timer0;
struct tm* plocaltime = localtime(&timer0);
printf("Current date:%d-%d-%d", plocaltime->tm_year + 1900, plocaltime->tm_mon + 1, plocaltime->tm_mday);
printf(" %d:%d:%d\n",plocaltime->tm_hour,plocaltime->tm_min,plocaltime->tm_sec);
if (t_currentTime > t_endTime)
{
return 0;
}
else
{
printf("System data: [%lld]\n", t_currentTime);
return t_currentTime;
}
}
transfer.h
long print_func(long keyTime, long endTime);
main.cpp
#include<cstdio>
#include "transfer.h"
int main()
{
unsigned long endDate = 1698681600;
unsigned long keyDate = 20231031;
unsigned long ret = print_func(endDate,keyDate);
if(ret == 0)
{
printf("Expired the period!\n");
}
else
{
printf("Get data: %ld\n", ret);
}
return 0;
}
2.4 编译并执行
1.编译动态库文件,进入到目录中,执行make命令
cd /test/secretkey/
make
分别在obj文件夹中生成了transfer.o文件,在lib文件夹中生成了libprint_func.so文件,中间文件已被清理
2. 编译主函数文件main.cpp,编译成功后,会在secretkey目录下生成demo可执行文件。
g++ -o demo main.cpp -lprint_func -Llib -Iinclude -Wall
g++ -o testEncrypted testEncrypted.cpp -lencrypted -Llib -Iinclude -Wall
g++ -o testDecrypted testDecrypted.cpp -ldecrypted -Llib -Iinclude -Wall
3.在目录/test/secretkey/下执行可执行文件demo,查看输出结果。
./demo
执行报错:
此处报错是因为动态库.so文件未被找到,这时需要查看demo依赖的共享库,查看命令为:
ldd demo
可以看到共享库中并没有libprint_func.so动态库,此时需要进行解决处理
2.5 动态库无法找到解决方案
临时解决
使用命令:export LD_LIBRARY_PATH=库路径,将当前目录加入环境变量,但是终端退出了就无效了。(适用于代码测试)
LD_LIBRARY_PATH介绍:
1、作用
①指定查找共享库(动态链接库)时除了默认路径之外的其他路径
②该路径在默认路径之前查找
2、设置方法
用export命令来设置值
例如:
export LD_LIBRARY_PATH=./lib #设置mylib文件夹路径为我们动态库所在的路径
echo $LD_LIBRARY_PATH #打印该环境变量
永久解决
将export LD_LIBRARY_PATH=./mylib写入家目录下.bashrc文件中,这样就可以永久设置了。
修改了bashrc文件后,需要将终端关掉再次打开,该文件才能生效。
永久解决(正规写法)
步骤:
需要找动态连接器的配置文件 – /etc/ld.so.conf
动态库的路径写到配置文件中 – 绝对路径,例如:/home/myproject/mylib
终端使用命令更新:sudo ldconfig -v
2.6 执行应用程序
再次输入 ./demo,执行应用程序,正常运行并输出结果。
3. 算法说明
讲一下为何用g++而不是gcc,因为g++有更加全面的标准库,很多类型转换做的比gcc要更加全面方便使用,也会省很多的代码去写专用函数转换。
3.1 unsigned char 数组与 long 类型互转
参考链接:https://www.cnblogs.com/wanghao-boke/p/17482291.html
#include<cstdio>
typedef unsigned int uint32_t;
typedef unsigned long int uint64_t;
typedef unsigned char uint8_t;
bool transferLong2ByteArray(uint8_t* byte, uint8_t length, uint64_t version){
uint64_t temp = version;
for(uint8_t i = 0; i < length; ++i){
uint8_t res = (uint8_t)(temp & 0xff);
byte[i] = res;
temp = temp >> 8;
}
return true;
}
uint64_t transferByteArrayToLong(uint8_t* byte, uint8_t length)
{
uint64_t version = 0;
#if 1
for(int i = 0; i < length; ++i){
uint64_t temp = byte[i];
version |= (temp << i * 8);
}
#else
long s = 0;
long s0 = (byte[0] & 0xff);
long s1 = (byte[1] & 0xff) << 8;
long s2 = (byte[2] & 0xff) << 16;
long s3 = (byte[3] & 0xff << 24);
version = s0 | s1 | s2 | s3;
#endif
return version;
}
int main()
{
uint32_t version = 0x000710;
uint64_t longVersion = (uint64_t)version;
uint8_t byte[4] = {0};
transferLong2ByteArray(byte, 4, longVersion);
uint64_t finalVersion = transferByteArrayToLong(byte, 4);
printf("vrsion %ld\n", finalVersion);
return 0;
}
3.2 随机字符匹配
unsigned char Letters[52]={'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z',
'A','B','C','D','E','F','G','H','I','J','K','L','M',
'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
//数组内随机数处理函数
void generateString(unsigned char * dest, unsigned int len)
{
unsigned int cnt, randNo;
srand((unsigned int)time(NULL));
for (cnt = 0; cnt<len; cnt++)
{
randNo = rand() % 51;
*dest = Letters[randNo];
dest++;
}
}
3.3 char数组间复制
//char数组复制处理函数,不固定起始位置
void my_strcpy_array(unsigned char *str, unsigned char *arr, int start, int end)
{
int num = 0;
for(num = start; num <= end-1; num++)
{
str[num - start] = arr[num];
}
}
//char数组复制处理函数,固定起始位置
void my_strcpy_array1(unsigned char *str, unsigned char *arr, int len)
{
int num = 0;
for(num = 0; num <= len-1; num++)
{
str[num] = arr[num];
}
}