1、共享内存类图
在使用共享内存时,如果想记录共享内存的相关信息,可以在共享内存的头部来记录信息,比如设计一个结构体:类似
struct head{
int total;
int usuNum;
}
2、生成随机字符串
#include<iostream>
#include<string.h>
#include<stdlib.h>
#include<time.h>
using m=namespace std;
void getRandString(char *pRandBuf,int len){
srand(time(NULL));//最好放在main函数里
int flag;
char buf[]="!@#$%&^*()-=~+";
for(int i=0;i<len-1;++i){
flag=rand()%4;
switch(flag){
case 0:
pRandBuf[i]=rand()%10+'0';
break;
case 1:
pRandBuf[i]=rand()%26+'A';
break;
case 2:
pRandBuf[i]=rand()%26+'a';
break;
case 3:
pRandBuf[i]=buf[rand()%strlen(buf)];
break;
default:
break;
}
}
}
密钥协商流程:
1、客户端生成随机数r1,同时使用openssl中哈希函数对r1进行哈希运算,得到一个哈希值
2、将要发送的数据进行编码
3、发送数据给服务端
4、服务端收到请求数据后先解码
5、服务端根据客户端ID+服务端ID查询数据库,校验客户端是否合法,如果不合法就拒绝服务
6、服务端校验r1消息验证码:首先用和客户端相同的算法生成哈希值,然后将哈希值与接收到的哈希值作比较,如果不一样就拒绝服务;如果一致就继续后续操作
7、服务端生成随机数r2
8、服务端将r1和r2进行拼接,然后使用与客户端相同的哈希算法,得到一个哈希值,这个哈希值就当作新的秘钥seckey2;
9、将密钥信息写入共享内存和数据库中
10、服务端发送应答信息
11、客户端等待接收服务端应答
12、对接收到的数据进行解码
13、判断rv值,若为-1生成密钥失败,
14、如果rv为0,则生成成功,收到服务端生成的随机字符串r2,将r1和r2拼接,然后进行哈希运算,得到一个新的秘钥seckey1;
15、客户端将密钥信息写入共享内存
秘钥校验:
1、客户端将秘钥进行哈希运算,得到一个哈希值
2、将哈希值发送给服务端
3、服务端收到哈希值,并且自己也生成一个哈希值
4、服务端将两个哈希值进行比较,相同则协商成功,失败则重新协商
秘钥注销:
1、将clientID/serverID/秘钥ID发送给服务端
2、服务端收到请求后将共享内存的状态修改为不可用状态,将数据库中密钥的使用状态修改为不可用状态
秘钥查看:
1、根据日期
2、根据秘钥ID
// 客户端给服务器发送数据的时候用到的数据结构
struct RequestMsg
{
int cmdType; //0-秘钥协商 1-秘钥校验 2-秘钥注销 3-秘钥查看
char clientId[12]; //客户端ID, 是唯一的, 不同的客户端有不同的ID
char authCode[65]; //消息验证码, 对r1进行验证
char serverId[12]; //服务端ID
char r1[64]; //客户端生成的随机字符串
};
// 服务器给客户端回复的时候用的到结构
struct RespondMsg
{
int rv; //0-表示成功 -1-表示失败
char clientId[12]; //客户端ID
char serverId[12]; //服务端ID
char r2[64]; //秘钥协商: 随机字符串, 秘钥查看: 秘钥 秘钥校验和注销:可不写
int seckeyid; //秘钥ID :服务端生成的
};
密钥协商客户端开发流程:
1、while(1){
读取用户输入:
c=getchar();
switch(c){
case 1:
//密钥协商
break;
case 2:
//密钥校验
break;
case 3:
//密钥注销
break;
case 4:
//密钥查看
break;
}
}
struct RequestMsg
{
int cmdType; //0-秘钥协商 1-秘钥校验 2-秘钥注销 3-秘钥查看
char clientId[12]; //客户端ID, 是唯一的, 不同的客户端有不同的ID
char authCode[65]; //消息验证码, 对r1进行验证
char serverId[12]; //服务端ID
char r1[64]; //客户端生成的随机字符串
};
秘钥协商流程:
1、对请求结构体RequestMsg进行赋值
生成随机字符串r1,设置cmdType=0,clientID,serverID可以从配置文件或者环境变量
中获得,最好写死,不然改代码需要重新编译和部署
authCode对r1进行哈希运算hmac得到一个值;
2、对请求结构体进行报文编码操作,得到一个字符串
char * outData;
CodeFectory * factory=new RequestFactory(&msg);
Codec *codec=factory->createCodec();
codec->msgEncode(&outData);
3、链接密钥协商服务器
4、发送编码后的字符串给密钥协商服务器
5、等待接受服务端应答数据inData
6、解码服务端发来的应答数据到结构体RespondMsg
struct RespondMsg
{
int rv; //0-表示成功 -1-表示失败
char clientId[12]; //客户端ID
char serverId[12]; //服务端ID
char r2[64]; //秘钥协商: 随机字符串, 秘钥查看: 秘钥 秘钥校验和注销:可不写
int seckeyid; //秘钥ID :服务端生成的
};
factory=new RespondFactory();
codec=factory->createCodec();
RespondMsg* pMsg=(RespondMsg*)codec->msgDecode(inData,len);
7、根据rv值判断密钥协商是否成功
8、客户端使用r1和服务端发来的r2进行哈希运算,得到一个新的哈希值seckey1,这个值就当作生成的秘钥。
9、将新的密钥信息写入共享内存
class NodeSHMInfo
{
public:
int status;
int seckeyID;
char clientID[12];
char serverID[12];
char seckey[128];
};
10、断开与服务端的网络连接
使用hmac函数
HMAC_CTX *HMAC_CTX_new(void);
/*__owur*/ int HMAC_Init_ex(HMAC_CTX *ctx, const void *key, int len,
const EVP_MD *md, ENGINE *impl);
/*__owur*/ int HMAC_Update(HMAC_CTX *ctx, const unsigned char *data,
size_t len);
/*__owur*/ int HMAC_Final(HMAC_CTX *ctx, unsigned char *md,
unsigned int *len);
unsigned char *HMAC(const EVP_MD *evp_md, const void *key, int key_len,
const unsigned char *d, size_t n, unsigned char *md,
unsigned int *md_len);
一个报错:
服务端和客户端生成密钥不一致
原因:服务端和客户端使用哈希函数时传参类型,必须一模一样,注意buf的长度