本demo主要是openssl中Diffie-Hellman,HAMC,AES的简单应用,谨供参考(文章最后有demo的下载)。
首先,demo的大概情况:
·openssl版本为openssl-1.0.1g-32bit-debug-vs2013(IDE是vs2013)
·使用MFC对话框的CAsyncsocket进行简单交互
·主要流程:
1)密钥协商。Client发起密钥协商请求,Server相应请求,并完成一次DH密钥交换过程。
2)身份认证。Server放提出认证请求,Client用协商出来的密钥对一个口令作用产生一个MAC发送给Server,Server根据口令进行认证。
3)报文发送。有一个文本输入窗,输入要通信的明文。按“发送”则报文明文发送;按“加密发送”按钮则加密并发送到对方。接收方收到密文,点击按钮可以解密;如果收到的是普通报文则直接显示在文本框。
流程图:
主要代码结构:
SCSocket ------------------------------ 服务端socket
SCClientSocket -------------------------------客户端socket
SCHandler -------------------------------下面三个类的父类
SCDHHandler -------------------------------Diffie-Hellman相关的操作(生成参数,选取秘钥,计算共享密钥)都在此类中
SCHMACHandler -------------------------------生成HMAC消息认证码
SCAESHandler ------------------------------- AES加密
XXXDlg -------------------------------显然负责界面
有关CASyncsocket的使用可参考: 一个CAsyncSocket例子
当socket收到消息,统一调用:
void SCClientSocket::OnReceive(int nErrorCode)
{
<span style="white-space:pre"> </span>// TODO: Add your specialized code here and/or call the base class
<span style="white-space:pre"> </span>pDlg->OnRecv(this);
<span style="white-space:pre"> </span>CAsyncSocket::OnReceive(nErrorCode);
}
pDlg->OnRecv :
void CSecureChatServerDlg::OnRecv(SCClientSocket * pConn)
{
if (NULL != pConn)
{
char rcvBuf[513] = { 0 };
int nRcved = 0;
nRcved = pConn->Receive(rcvBuf, 512);
if (SOCKET_ERROR != nRcved)
{
clientSocket->handler->processMessageFromConnection(rcvBuf, clientSocket);
}
}
}
不管收到什么信息,都是调用 clientSocket->handler->processMessageFromConnection(rcvBuf, clientSocket);
SCClientSocket定义如下:
class SCClientSocket : public CAsyncSocket
{
public:
SCClientSocket();
virtual ~SCClientSocket();
virtual void OnConnect(int nErrorCode);
virtual void OnClose(int nErrorCode);
virtual void OnReceive(int nErrorCode);
void send(unsigned char * data);
CSecureChatServerDlg * pDlg;
SCHandler * handler;
};
SCHandler中定义了两个虚函数:
virtual void processMessageFromConnection(char * data, SCClientSocket *conn)
{
// should never call me!
}
virtual void start(SCClientSocket *conn,int flag)
{
// should never call me!
}
保存了SCHandler * handler 指针,随着交互流程的推进,handler可以依次指向SCDHHandler,SCHMACHandler,SCAESHandler的实例(通过调用void start(SCClientSocket *conn,int flag)改变handler所指的对象)。SCHandler的子类覆盖了上面两个虚函数,因此会调用各自的 void processMessageFromConnection(char * data, SCClientSocket *conn) 处理各自的消息。
为了标识当前的交互状态,在每个消息前面插入一个字节标记当前消息的内容:
例如SCDHHandler的processMessageFromConnection函数内容如下:
void SCDHHandler::processMessageFromConnection(char * data, SCClientSocket *conn)
{
char DHType = data[0];
switch ((int)DHType)
{
case RECV_A: // 收到DH参数a(即本原根)
{
......
break;
}
case RECV_Q: // 收到DH参数q (大整数)
{
......
break;
}
case RECV_Q_RESPON: // 对方收到q发回的回应
{
......
break;
}
case RECV_SERVER_PUBLIC_KEY: // 收到服务器的公开量,只会在客户端程序触发
{
......
break;
}
case RECV_CLIENT_PUBLIC_KEY: // 收到客户端的公开量,只会在服务器程序触发
{
......
break;
}
default:
AfxMessageBox(_T("diffie hellman error occur"));
break;
}
}
SCHMACHandler 和 SCAESHandler的代码结构也是如上所示。
具体代码可查看:demo下载
参考:
另外,openssl的库是直接用别人编译好的(自己编了几次都失败了):
http://p-nand-q.com/programming/windows/building_openssl_with_visual_studio_2013.html
aes例子:
https://github.com/rockyxshen/block_cipher/blob/master/aescipher.c