Diffie-Hellman密钥协商算法原理及实现

  • Post author:
  • Post category:其他




前言

  • 做的东西涉及一些指令的传输,很容易通过抓包获取指令内容,为了保证指令安全,需要对指令进行加密,决定自己实现一个基于Diffie-Hellman密钥协商算法的封装类


  • GitHub



原理



密钥交换协议

1、通信双方通过协商,共同建立会话密钥,任何一个参与者均对结果产生影响,不需要任何第三方参与

2、会话密钥由每个协议参与者分别产生的参数通过计算得到



Diffie-Hellman密钥协商过程(左为A,右为B)

在这里插入图片描述

1、初始化:A选取一个生成元

g

和一个大素数

p

,发送给B

2、A随机选取0<

x

<p-1,计算

X

= g

x

mod p后,将X传给B

3、B随机选取0<

y

<p-1,计算

Y

= g

y

mod p后,将Y传给A

4、A计算Y

x

mod p得到会话密钥

K1


5、B计算X

y

mod p得到会话密钥

K2


6、由下可知 K1 == K2,此时双方便可利用会话密钥进行加密通信了
证明



实现



crypto.h

#ifndef CRYPTO_H
#define CRYPTO_H
#include <stdlib.h>

/**
* 作者:公羽向阳
* 时间:20201025
* 编译器:TDM-GCC 4.8.1 64bit
* 
* 基于DH的密钥协商加密类 
* 1、请先使用Crypto::init()方法初始化随机种子 
* 2、客户端构造此类,服务端通过客户端生成的 [g,p] 构造 
* 3、客户端通过调用get_public()方法得到一个数组 [g, p] 
* 4、客户端、服务端通过get_pub_key()方法获取公钥 C、S 用于协商 
* 5、客户端、服务端通过get_key(size_t pub_key)方法获取密钥用于加密 
* 6、客户端、服务端可使用crypto(char *data, size_t size, const char *key)方法加解密 
*/
class Crypto
{
	public:
		Crypto();
		Crypto(size_t g, size_t p);
		static void init();
		size_t *get_public();
		size_t get_pub_key();
		char *get_key(size_t pub_key);
		void crypto(char *data, size_t size, const char *key);
		virtual ~Crypto();
		
	protected:
		size_t create_big_integer();
		size_t pow_mod(size_t n, unsigned int times, size_t mod);
		
	private:
		size_t _g, _p;
		size_t *_public;
		size_t _private;
		size_t _pub_key;
		char *_pri_key;
};

#endif



crypto.cpp

#include "crypto.h"
#include <stdio.h>
#include <unistd.h>
#include <time.h>

Crypto::Crypto()
{
	this->_g = (unsigned)rand()%9+2; 
	this->_p = create_big_integer();
	this->_private = (size_t)rand()%this->_p; // create_big_integer()>>8%this->_p;
	this->_pub_key = pow_mod(this->_g, this->_private, this->_p); 
	this->_pri_key = new char[sizeof(size_t)+1];
	this->_public = new size_t[2];
}

Crypto::Crypto(size_t g, size_t p)
{
	this->_g = g;
	this->_p = p;
	this->_private = (size_t)rand()%this->_p; // create_big_integer()>>8%this->_p;
	this->_pub_key = pow_mod(this->_g, this->_private, this->_p); 
	this->_pri_key = new char[sizeof(size_t)+1];
	this->_public = new size_t[2];
}

void Crypto::init()
{
	srand((unsigned)time(0));
}

size_t *Crypto::get_public()
{
	this->_public[0] = _g;
	this->_public[1] = _p;
	return this->_public;
}

size_t Crypto::get_pub_key()
{
	return this->_pub_key;
}

char *Crypto::get_key(size_t pub_key)
{
	size_t tmp = pow_mod(pub_key, this->_private, this->_p);
	sprintf(this->_pri_key, "%08x", tmp);
	return this->_pri_key;
}

void Crypto::crypto(char *data, size_t size, const char *key)
{
	size_t len = strlen(key);
	for(size_t i=0; i<size; ++i)
	{
		data[i] ^= key[i%len];
	}
}

size_t Crypto::create_big_integer()
{
	return ((size_t)((size_t)rand()<<16)|(size_t)rand());// | (size_t)0x80000000; // 8:1000, 28*0
}

size_t Crypto::pow_mod(size_t n, unsigned int times, size_t mod)
{
	size_t tmp = 1;
	for(unsigned int i=0; i<times; i++)
	{
		tmp = tmp*n%mod;
	}
	return tmp;
}

Crypto::~Crypto()
{
	delete [] this->_public;
	delete [] this->_pri_key;
}



main.cpp

#include <iostream>
#include <string.h>
#include "crypto.h"
using namespace std;

void print(char *data, int size)
{
	for(int i=0; i<size; i++)
	{
		cout << data[i];
	}
	cout << endl;
}

int main(int argc, char** argv) 
{
	Crypto::init(); // 初始化随机种子 
	
	// 模拟协商 
	Crypto client;  // A 
	size_t *g_p = client.get_public(); // 生成 (g, p) 
	size_t X = client.get_pub_key();   // 计算 X 
	
	Crypto server(g_p[0], g_p[1]);     // B, 接收 (g, p)  
	size_t Y = server.get_pub_key();   // 计算 Y 
	char *K2 = server.get_key(X);      // B 计算会话密钥 
	char *K1 = client.get_key(Y);      // A 通过 B 发的 Y 计算会话密钥 
	cout << "K1: " << K1 << "\nK2: " << K2 << endl << endl;
	if(strcmp(K1, K2))
	{
		cout<< "会话密钥生成错误" << endl;
		return 0; 
	}
	
	// 模拟会话 
	char data[11] = "helloworld";     // 明文 
	
	cout << "A加密: " << endl; 
	client.crypto(data, 10, K1);       // 使用密钥加密 
	print(data, 10);
	cout << "==========" << endl;
	
	cout << "B解密: " << endl; 
	server.crypto(data, 10, K2);       // 使用密钥解密 
	print(data, 10);
	cout << "==========" << endl;	
	return 0;
}



效果

效果



补充

原理中说的是生成随机大素数,在实现的时候我生成的是大整数,因为大素数生成是个麻烦的事情,我也尝试写过,但是生成速度太慢,影响体验。考虑到我们的加密方式是按位异或加解密,用这种方法就算不使用大素数依旧不会出问题,所以直接生成的是一个大整数,关于大素数的生成可以看一下

这篇文章

,讲得挺好的。



版权声明:本文为qq_42766994原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。