本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