zoukankan      html  css  js  c++  java
  • 安全传输平台项目——密钥协商设计与实现--存数据库-MFC项目创建

    在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

    10-安全传输平台项目-第08天(密钥协商设计与实现--存数据库-mfc项目创建)

    目录:
    一、复习
    二、安全传输平台项目——密钥协商设计与实现--存数据库-MFC项目创建
    1、密钥协商存数据库
    2、表外键约束导致的插入时间错误
    3、密钥注销流程分析
    4、4大基础组件源码
    5、数据库连接池错误说明
    6、配置ODBC驱动
    7、ODBC驱动错误说明
    8、界面框架思想
    9、MFC空项目创建
    10、处理源码中cur图标对应错误
    11、添加消息宏定义

    一、复习

    1、数据库-SQL语句、事务、游标回顾
    2、数据库-访问API、查询语句API、非查询语句API
    3、数据库-base64编码

    二、安全传输平台项目——密钥协商设计与实现--存数据库-MFC项目创建

    1、密钥协商存数据库

    icdbapi.h和keymng_dbop.h放入inc目录下;keymng_dbop.c放入src目录下。

    >vi keymngserverop.c

    1)增加头文件icdbapi.h和keymng_dbop.h;

    2)MngServer_InitInfo函数增加-初始化数据库连接池IC_DBApi_PoolInit函数;

    3)MngServer_Agree函数增加-写数据库KeyMngsvr_DBOp_WriteSecKey函数;

    4)MngServer_Agree函数增加-获取一条数据库连接池中的连接IC_DBApi_ConnGet函数;

    5)MngServer_Agree函数增加-从数据库中获取 seckeyid的 KeyMngsvr_DBOp_GenKeyID函数;

    6)MngServer_Agree函数增加-开启事务的 IC_DBApi_BeginTran函数和关闭事务的iIC_DBApi_Rollback函数;

    7)MngServer_Agree函数增加-释放数据库连接到连接池IC_DBApi_ConnFree函数;

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include "keymngserverop.h"
    #include "keymng_msg.h"
    #include "keymnglog.h" 
    #include "keymng_shmop.h"
    #include "icdbapi.h"
    #include "keymng_dbop.h"
    
    //static int    seckeyid = 100;
    
    int MngServer_InitInfo(MngServer_Info *svrInfo)
    {
        int ret = 0;
        strcpy(svrInfo->serverId, "0001");
        strcpy(svrInfo->dbuse, "SECMNG");
        strcpy(svrInfo->dbpasswd, "SECMNG");
        strcpy(svrInfo->dbsid, "orcl");
        svrInfo->dbpoolnum = 8;    
        strcpy(svrInfo->serverip, "127.0.0.1");
        svrInfo->serverport = 8001;
        svrInfo->maxnode = 10;
        svrInfo->shmkey = 0x0001;
        svrInfo->shmhdl = 0;
        
        //创建/打开 共享内存
        ret = KeyMng_ShmInit(svrInfo->shmkey, svrInfo->maxnode, &svrInfo->shmhdl);
        if (ret != 0) {
            printf("---------服务器创建/打开 共享内存失败-----
    ");
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMng_ShmInit() err:%d", ret);
            return ret;
        }
        
        //初始化数据库连接池
        ret = IC_DBApi_PoolInit(svrInfo->dbpoolnum, svrInfo->dbsid, svrInfo->dbuse, svrInfo->dbpasswd);
        if (ret != 0) {
            printf("---------服务器初始化连接池失败-----
    ");
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 IC_DBApi_PoolInit() err:%d", ret);
            return ret;
        }
        
        return 0;    
    }
    
    int MngServer_Agree(MngServer_Info *svrInfo, MsgKey_Req *msgkeyReq, unsigned char **outData, int *datalen)
    {
        int ret = 0;
        int i = 0;
        int keyid = -1;
        
        MsgKey_Res msgKey_Res;
        
        NodeSHMInfo nodeSHMInfo;
        
        ICDBHandle handle = NULL;
        
        // --结合 r1 r2 生成密钥  ---> 成功、失败 rv
        if (strcmp(svrInfo->serverId, msgkeyReq->serverId) != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "客户端访问了错误的服务器");
            return -1;    
        }
        
        // 组织 应答结构体 res : rv r2 clientId serverId  seckeyid
        msgKey_Res.rv = 0;     //0 成功 1 失败。
        strcpy(msgKey_Res.clientId, msgkeyReq->clientId); 
        strcpy(msgKey_Res.serverId, msgkeyReq->serverId); 
        
        // 生成随机数 r2
        for (i = 0; i < 64; i++) {
            msgKey_Res.r2[i] = 'a' + i;            
        }
        
        //获取一条数据库连接池中的连接
        ret = IC_DBApi_ConnGet(&handle, 0, 0);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 IC_DBApi_ConnGet() err:%d", ret);    
            return ret;
        }
        
        //开启事务
        IC_DBApi_BeginTran(handle);
        
        //从数据库中获取 seckeyid
        //msgKey_Res.seckeyid = seckeyid++;
        ret = KeyMngsvr_DBOp_GenKeyID(handle, &keyid);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMngsvr_DBOp_GenKeyID() err:%d", ret);
            return ret;    
        }
        msgKey_Res.seckeyid = keyid;
        
        // 组织密钥节点信息结构体
        for (i = 0; i < 64; i++) {
            nodeSHMInfo.seckey[2*i] = msgkeyReq->r1[i];
            nodeSHMInfo.seckey[2*i+1] = msgKey_Res.r2[i];
        }
        nodeSHMInfo.status = 0;  //0-有效 1无效
        strcpy(nodeSHMInfo.clientId, msgkeyReq->clientId);
        strcpy(nodeSHMInfo.serverId, msgkeyReq->serverId);
        nodeSHMInfo.seckeyid = msgKey_Res.seckeyid;
        
        // --写数据库
        ret = KeyMngsvr_DBOp_WriteSecKey(handle, &nodeSHMInfo); 
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMngsvr_DBOp_WriteSecKey() err:%d", ret);    
        }
        
        // 关闭事务
        if (ret != 0) {
            iIC_DBApi_Rollback(handle);
            IC_DBApi_ConnFree(handle, 0);//释放数据库连接到连接池
            return -1;
        }
        else if(ret == 0)
        {
            IC_DBApi_Commit(handle);
            IC_DBApi_ConnFree(handle, 1);//释放数据库连接到连接池
        }
        
        // --写入共享内存。
        ret = KeyMng_ShmWrite(svrInfo->shmhdl, svrInfo->maxnode, &nodeSHMInfo);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "服务器 KeyMng_ShmWrite() err:%d", ret);
            return ret;    
        }
        
        // 编码应答报文  传出
        ret = MsgEncode(&msgKey_Res, ID_MsgKey_Res, outData, datalen);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "serverAgree MsgEncode() err:%d", ret);    
            return ret;
        }
        
        return 0;    
    }
    
    
    int MngServer_Check(MngServer_Info *svrInfo, MsgKey_Req *msgkeyReq, unsigned char **outData, int *datalen)
    {
        
        
        return 0;    
    }
    keymngserverop.c

    >vi keymngserver.c

    1)增加头文件icdbapi.h;

    2)main函数增加-释放数据库连接池 IC_DBApi_PoolFree()函数;

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <pthread.h>
    #include <signal.h>
     
    #include "poolsocket.h"  
    #include "keymngserverop.h"
    #include "keymng_msg.h"
    #include "keymnglog.h"  
    #include "icdbapi.h"
    
    MngServer_Info serverInfo;
    
    int flg = 1;
    
    //注意定义宏的时候最后是一个整体,不能有空格!
    #define CREATE_DAEMON if(fork()>0)exit(1);setsid();
     
    void *start_routine(void * arg)
    {
         int ret;
         int timeout = 3;
         int connfd = (int)arg;
         
         unsigned char *out = NULL;
         int outlen = 0;
         
         MsgKey_Req *pStruct_req = NULL;
         int iType = 0;
         
         unsigned char *res_outData = NULL;
         int res_outDataLen = 0;
         
         while (1) {
                     
            if (flg == 0) 
                break;    
    
            //服务器端端接受报文
            ret = sckServer_rev(connfd, timeout, &out, &outlen); 
            if (ret == Sck_ErrPeerClosed) {
                // 检测到 对端关闭,关闭本端。
                printf("----------------ErrPeerClosed 关闭服务器
    ");
                break;
            } else if (ret == Sck_ErrTimeOut) {
                if (out != NULL)  sck_FreeMem((void **)&out);
                continue;
            } else if (ret != 0) {
                printf("未知错误
    ");
                break;
            }
    
            // 解码客户端 密钥请求报文 ---> cmdType
            ret = MsgDecode(out, outlen, (void **)&pStruct_req, &iType);
            if (ret != 0) {
                KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MsgDecode() err:%d", ret);    
                break;    
            }
    
            switch(pStruct_req->cmdType) {
                case KeyMng_NEWorUPDATE:
                    ret = MngServer_Agree(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
                
                case KeyMng_Check:
                    MngServer_Check(&serverInfo, pStruct_req, &res_outData, &res_outDataLen);
                /*    
                case 密钥注销:
                    mngServer_Agree();
                    */
                default:
                    break;
            }
            if (ret != 0) {        
                KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_Agree() err:%d", ret);
                break;                
            }
    
             //服务器端发送报文
            ret = sckServer_send(connfd, timeout, res_outData, res_outDataLen);
             if (ret == Sck_ErrPeerClosed) {
                // 检测到 对端关闭,关闭本端。
                printf("---ErrPeerClosed 
    ");
                break;
            } else if (ret == Sck_ErrTimeOut) {
                printf("---服务器检测到本端发送数据 超时 
    ");
                if (out != NULL) sck_FreeMem((void **)&out);
                if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
                if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
                continue;
            } else if (ret != 0) {
                printf("未知错误
    ");
                break;
            }
        }
        
        if (out != NULL) sck_FreeMem((void **)&out);
        if (pStruct_req != NULL) MsgMemFree((void **)&pStruct_req, iType);
        if (res_outData != NULL) MsgMemFree((void **)&res_outData, 0);    
        
        sckServer_close(connfd);
        
         return NULL;
    }
    
    void catchSignal(int signum)
    {
        flg = 0;
        printf(" catch signal %d, process is going to die.
    ", signum);
        
        return ;
    }
    
    int main(void)
    {
        int listenfd;
        int ret = 0;
        
        int timeout = 3;
        int connfd = -1;
        
        pthread_t pid;
        
        CREATE_DAEMON
        
        signal(SIGUSR1, catchSignal);
        
        // 服务器信息初始化。
        ret = MngServer_InitInfo(&serverInfo);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "MngServer_InitInfo() err:%d", ret);    
            return ret;
        }
        
        //服务器端初始化连接
        ret = sckServer_init(serverInfo.serverport, &listenfd);
        if (ret != 0) {
            KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_init() err:%d", ret);    
            return ret;
        }
        
        while (1) {    
            if (flg == 0) 
                break;
            
            ret = sckServer_accept(listenfd, timeout, &connfd);
            if (ret == Sck_ErrTimeOut){
                KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[2], ret, "---等待客户端连接超时---");
                continue;    
            } else if(ret != 0)  {
                KeyMng_Log(__FILE__, __LINE__, KeyMngLevel[4], ret, "sckServer_accept() err:%d", ret);    
                return ret;
            }
            
            ret = pthread_create(&pid, NULL, start_routine, (void *)connfd);                    
        }
         
         //服务器端环境释放 
        sckServer_destroy();
        IC_DBApi_PoolFree();
        
        printf("服务器 优雅退出。
    ");
    
        return 0;    
    }
    keymngserver.c

    >vi makefile

    .PHONY:clean all
    
    WORKDIR=.
    VPATH = ./src
    
    CC=gcc
    CFLGS= -Wall -g -I$(WORKDIR)/inc/
    LIBFLAG = -L$(HOME)/lib
    
    
    BIN = keymngclient  keymngserver 
    
    
    all:$(BIN)
    
    keymngclient:keymngclient.o  keymnglog.o  keymngclientop.o  myipc_shm.o keymng_shmop.o
        $(CC) $(LIBFLAG) -lpthread -litcastsocket -lmessagereal $^ -o $@ 
            
    keymngserver:keymngserver.o  keymngserverop.o  keymnglog.o  myipc_shm.o  keymng_shmop.o keymng_dbop.o
        $(CC) $(LIBFLAG) $^ -o $@ -lpthread -litcastsocket -lmessagereal -lclntsh  -licdbapi
     
    #testdbapi:testdbapi.o  
    #    $(CC) $(LIBFLAG) $^ -o $@ -lpthread  -lclntsh  -licdbapi
            
    %.o:%.c
        $(CC) $(CFLGS) -c $< -o $@    
    
    clean:
        rm -f *.o $(BIN)
        
        
        
    makefile

    >make

    >./keymngserver

    打开另一个终端,切换到该目录下,执行>./keymngclient

    连续执行3次后,打开SQL Developer查看表中数据:

    >SECKYEINFO表:

    >KEYSN表:

    2、表外键约束导致的插入时间错误

    打开SQL Developer查看SECKYEINFO表:

    >SECKYEINFO表的约束条件:

    >对应SECNODE表的数据中Name中ID:

    所以,客户端和服务器的ID是固定的,给SECKYEINFO表插入数据时候,外键不满足,会报错:插入时间(日期)错误 ,所以要想添加新的服务器或客户端ID信息(如:6666),需要相应的在SECNODE表中添加相应的ID信息(如:6666)

    注意:实际不应该报时间错误,这是个bug!!!

    3、密钥注销流程分析

    》密钥注销:

    >keymngserver.c

        // 接收客户端连接 
    
        // 创建线程 , 接收数据包 TLV
    
        // 解码密钥请求结构体
    
        switch (cmdType){
            
            case KeyMng_Revoke:
    
                MngServer_Revoke();
    
                break;
        }
    
        // 发送应答报文 TLV

    》服务器:        keymngserverop.c

    int MngServer_Revoke(MngServer_Info *svrInfo, MsgKey_Req *msgkeyReq, unsigned char **outData, int *datalen)
    {
        // 取出 msgkeyReq 中的 clientID、serverID
    
        // 注销当前密钥: 根据 clienid 、 serverID --> seckeyid
        
        // 根据 seckid 修改数据库中的 对应 status 0 --> 1  (update)
    
            //封装/实现函数:----写数据库。 update --seckeyinfo -->  status  0-->1   注意事务的管理。
    
        // 根据结果 修改 rv
    
        // 修改共享内存中的 密钥 status  0-->1  
    
        // 组织应答报文结构体。

       // 编码应答报文 传出
    }

    》客户端:        keymngclientop.c

    int MngClient_Revoke(MngClient_Info *pCltInfo)
    {
        // 组织 请求报文 req        cmdType--> KeyMng_Revoke
    
        // 编码 请求报表  TLV
    
        // 发送 请求报文
                
        // 接收 应答报文
    
        // 解码 应答报文
        
        // 修改共享内存中的 密钥 status  0-->1
    
        // 返回结果给用户。
        
        return 0;    
    }

    4、4大基础组件源码

    问题:ldd keymngserver报错:libclntsh.so-->not found

    原因分析:.pc --> proc -->.c -->gcc -->a.out

    oracle的本身提供的.pc需要借助proc(编译器)转换为.c文件,然后借助liunx安装的gcc编译为a.out。如果没有proc编译器,所以就没有libclntsh.so库,也就无法使用。

    测试,linux上有没有proc编译器,shuru>porc,看是否是not found。如果是,需要在linux(Red Hat)上安装proc。

    》四大基础组件源码:

    制作libclntsh.so的源码:icdblib目录下src目录下文件;

    制作libmessagereal.so的源码:msgderlib目录下src目录下文件;

    共享内存的源码:shmlib目录下文件myipc_shm.c和myipc_shm.h;

    制作libitcastsocket.so的源码:socketlib目录下src目录下文件。

    5、数据库连接池错误说明

    主要是未按新建用户进行配置!——参看项目第一天的笔记。

    注意:先要保证>sqlplus SECMNG/SECMNG@orcl可以正常,才能运行代码。

    6、配置ODBC驱动

    》ODBC驱动连接Oracle数据库:

    7、ODBC驱动错误说明

    》wind使用Net Configuration Assistant启动TNS服务

    说明:在进行团队开发bai的时候,一般团队的每一个人du只需要安装一个客户zhi端即可,没有必要安dao装一个Oracle 数据库服务器,而数据库服务器是属于共享的,此时,我们就需要配置客户端。使用Net Configuration Assistant是一种向导式客户端。

    测试:打开后,选择“本地网络服务名配置”,点击“下一步”,选择“添加”,点击“下一步”,服务名输入:orcl,点击“下一步”,选择“TCP”,点击“下一步”,主机名输入:192.168.5.100,点击“下一步”,选中“是,进行测试”,点击“下一步”,(测试不成功)点击“更改登录”,输入用户名:SECMNGADMIN,口令:123456

    点击“确定”会提示“测试成功”(注意:执行这个测试的前提是wind和linux可以ping通),点击“下一步”,输入网络服务名:zhangsan,点击“下一步”,选择“否”,点击“下一步”,“完成”。

    在wind的C:WindowsSysWOW64 目录下搜索“ODBCAD”:

    双击“odbcad32.exe”,选择“系统DSN”,右侧点击“添加”,下拉选择“Oracle in OraClient11g_home1”,点击“完成”,然后弹出“Oracle ODBC Driver Configuration”:

    在“TNS Service Name”的下拉框中选中“ZHANGSAN”,在“Data Source Name”后输入:zhangsan,然后点击右侧“Test Connection”,输入User Name:SECMNGADMIN,Password:123456

    点击“OK”,会弹出“Connetion Successful”!

    这时打开SecMngAdmin_win文件夹下的MySecAdmin.exe进行测试(可以删除:secmngadmin.ini),输入数据源:zhangsan,用户名:SECMNGADMIN,密码:123456

    点击“测试”,会弹出“测试数据源连接成功”;点击“确定”,就可以连上:

    8、界面框架思想

    9、MFC空项目创建

    打开“VS”,“新建项目”,左侧选择“Visual C++”,右侧选择“MFC应用程序”,名称输入:secmngAdmin,路径更改后,点击“下一步”:

    点击“下一步”,“复合文档支持”保持默认无,,点击“下一步”,“文件模板属性”保持默认,点击“下一步”,“数据库支持”保持默认,点击“下一步”,“用户界面功能”:

    ,点击“下一步”,“高级功能”:取消所有勾选,点击“下一步”,“生成的类”,保持默认CsecmngAdmin433View,点击“完成”。

    》界面打开如下:(“类视图”在“视图”中;“资源视图”在“视图”的“其他窗口”中)

    注意:刚开始先运行一下,看有没有问题。

    10、处理源码中cur图标对应错误

    从网上下载MFC框架资源(如:MFC_框架资源),把下图的9个文件拷贝到项目文件夹(在MainFrm.cpp上右键打开的文件夹)下:

    然后在项目“secmngAdmin411”右键,添加“现有项”,添加这9个文件,点击“运行”,报错一堆:

    1)报错:无法将“CString”转为“const char *”?

    解决:在项目属性页“常规”右侧“字符集”选择“使用多字节字符集”;

    分析:如果是“VS2013”缺少插件“vc_mbcsmfc.exe”,解决方法:(注意:需要关闭醒项目,然后以管理员身份运行“vc_mbcsmfc.exe”)

    “VS2015”暂时不能一步解决方案!

    2)未定义的标识符?

    cur目录下有(dragging.cur、handlecur.cur、nodragging.cur)3个cur文件放入项目的文件夹的下一级res目录下;然后打开“资源视图”,在“secmngAdmin411.rc”右键“添加资源”,点击“导入”,选择这3个cur文件,点击“打开”(这时多了一个Cursor目录,里面有这3个文件),右键“属性”进行设置ID:

    其ID 更改:IDC_CURSOR2(手图标)更改为:IDC_HANDLECUR、IDC_CURSOR1(鼠标图标)更改为:IDC_DRAGGING 和IDC_CURSOR3(禁止图标)更改为:IDC_NODRAGGING

    注意,每步更改后,点击“都保存”,会弹出警告-修改影响多处,点击“是”。

    11、添加消息宏定义

    再次点击“运行”,还有8个错误:

    在resource.h中添加控件消息宏定义:

    #define ID_GFX_SMALLICON                50000
    #define ID_GFX_LARGEICON                50001
    #define ID_GFX_RENAMEITEM                50002
    #define ID_GFX_REMOVEITEM                50003
    #define ID_GFX_GROUPICON                 50004
    #define ID_GFX_FONTCICON                 50005
    #define ID_GFX_BACKCICON                 50006

    再次点击“运行”不报错了,出来了“窗口”。

    注意:当在“解决方案管理器”中打开“resource.h”(文本模式)时,在“资源视图”中会变成叉号无法编辑,这是两种资源模式,是正常现象。

    在学习安全传输平台项目总结了笔记,并分享出来。有问题请及时联系博主:Alliswell_WP,转载请注明出处。

  • 相关阅读:
    MyCat清单
    Nginx整合Tomcat
    Nginx安装与配置
    Spring清单
    Shiro清单
    Dubbo清单
    MyBatis清单
    查询数据库的编码
    myBatis
    面试
  • 原文地址:https://www.cnblogs.com/Alliswell-WP/p/CPlusPlus_SecureTransmissionPlatform_Project08.html
Copyright © 2011-2022 走看看