openssl C++ DSA对指定文件内容签名和解签

openssl C++ DSA对指定文件内容签名和解签

  • 用DSA私钥对指定文件签名
  • 用DSA公钥验证签名
  • 用DSA公钥验证解签后的信息是否与机器码一致

DSA密钥对的生成请参考我这篇文章openssl在windows上生成RSA密钥、DSA密钥

用DSA私钥对指定文件签名

//DSA用私钥对文件内容签名
#pragma warning(disable:4996)
#include 
#include 
#include 
#include 

using namespace std;

/*
函数名:DSA_sign
函数功能:用openssl的DSA接口读取DSA私钥,对指定文件内容进行签名,将签名保存到另一个文件中
输入参数:None
返回参数:bool 若签名成功,返回true,否则返回false
作者:Leo Ma
时间:2019.09.15
*/

bool DSA_sign(string input_file,string sign_file)
{
	
	DSA* dsa_private_key = DSA_new();//定义DSA私钥
	unsigned char* input_string = new unsigned char;//定义要签名的字符串
	unsigned char* sign_string;//定义签名后的字符串
	unsigned int sig_len;//签名长度


	//从文件中读取DSA私钥
	BIO *priio;//Binary IO
	priio = BIO_new_file("dsa_private_key.pem", "rb");
	dsa_private_key = PEM_read_bio_DSAPrivateKey(priio, &dsa_private_key, NULL, NULL);


	//从文件中读取要签名的内容,放在input_string中
	ifstream fin(input_file);
	if (!fin.is_open())
	{
		cout << "WARNING! NOT FOUND CHECK FILE,PLEASE CONTACT TO THE ADMISTRATOR!!!" << endl;
		return 0;
	}
	fin >> input_string;
	fin.close();



	//为签名后的字符串sign_string分配内存,如果不能正常分配内存,DSA_sign()将返回false
	sign_string = (unsigned char*)calloc(DSA_size(dsa_private_key), sizeof(unsigned char));
	if (sign_string == NULL)
	{
		fprintf(stderr, "Unable to allocate memory for sign_string\n");
		return false;
		//exit(-1);
	}


	//对input_string进行签名
	//DSA_sign输入参数:签名类型,要签名的字符串地址,要签名的字符串长度,签名后的字符串存放地址,签名后的字符串长度,私钥
	//如果签名失败,DSA_sign()将返回0,DSA_sign()将返回false
	if (DSA_sign(0, input_string, strlen((char*)input_string),
		sign_string, &sig_len, dsa_private_key) == 0)
	{
		fprintf(stderr, "Sign Error.\n");
		return false;
		//exit(-1);
	}



	//将签名后的字符串内容保存到一个文件中
	ofstream fout;
	fout.open(sign_file);
	fout << sign_string;
	fout.close();

	return true;
}



int main(int argc, char** argv) 
{

	DSA_sign("check_file.txt", "checked_file.txt");
	system("pause");
}

用DSA公钥验证签名

#pragma warning(disable:4996)
#include 
#include 
#include 
#include 
#include 

using namespace std;


/*
函数名:DSA_verify_general
函数功能:用openssl的DSA接口验证解签后的信息是否与给定信息相同
输入参数:	string sign_file 签名文件
			string verify_string 给定的验证信息
返回参数:bool 若验证通过,返回true,否则返回false
作者:Leo Ma
时间:2019.09.15
*/

bool DSA_verify_general(string sign_file, string verify_string)
{
	//将DSA公钥写死在文件中
	//把DSA公钥文件内容复制到下面的字符串里,将多余的空格(这是VS编辑器的问题)删掉,换行符遵循UNIX(LF)格式,即使用\n换行
	string dsa_public_key_string = "-----BEGIN PUBLIC KEY-----\nMIIBtjCCASsGByqGSM44BAEwggEeAoGBAKenvEftAsim1cta2VzV+SCSiwJZFq6v\n+UvbdOTkM+mB9vq4NcV1mOEgPyXczgb+dU/Mn7Y0Zi5CkvCe18YyjaillKfGjVCt\n9ftffA/ML3axyfxsiPAuX0I1GRWJk6qbFaXImUAKUAGUiK1yKtJPnXIbnIQBYxji\nAXUcV6Pa6KwfAhUAhHBmLP8lIBIso865Bz7z5XQMKmkCgYBZiMp+oVyEuzZ8eS1d\nBWvbyKk/gnvGMxv10o/X1dWiD7JlT9iUl6J1kh8BnEIB6D4+zXStgq/g/t8+j/fK\nbwmin/zTC5LrzPtvzS2nsCEM4jL5UJzil24k3F8AQX5PUCt+TOwA0DudLz59K+An\nME+CxAPrCkcjg2tmco1RwO1QhQOBhAACgYA3ix4u+0IrSKDI605qCUgmBBbD3YlK\niACidMGZpzZnTaY3GzFt5m/Yn8o2mRfU2/Ouhssuum7uKXep4N9OhidM76ErPbpV\nIHP7n6fWx09MdLz5HkOmomVI8s9gQEog89Y9sw5KMymxln44QGyJPRqnRIKK+h58\ncX/Uar7hPftz7A==\n-----END PUBLIC KEY-----\n";
	ofstream public_key_file;
	public_key_file.open("dsa_public_key.pem");
	public_key_file << dsa_public_key_string;
	public_key_file.close();


	//从刚写好的文件中读取DSA公钥
	DSA* dsa_public_key = DSA_new();
	BIO *pubio;//Binary IO
	pubio = BIO_new_file("dsa_public_key.pem", "rb");
	dsa_public_key = PEM_read_bio_DSA_PUBKEY(pubio, &dsa_public_key, NULL, NULL);
	/*
	//另一种读取DSA公钥的方法
	DSA* dsa_public_key = DSA_new();
	FILE *pubio;
	pubio = fopen("dsa_public_key.pem", "rb");
	dsa_public_key = PEM_read_DSA_PUBKEY(pubio, &dsa_public_key, NULL, NULL);
	*/



	//从文件中读取DSA签名
	string sign_string;
	ifstream fin(sign_file);
	if (!fin.is_open())
	{
		cout << "WARNING! NOT FOUND CHECKED FILE,PLEASE CONTACT TO THE ADMISTRATOR!!!" << endl;
		return 0;
	}
	fin >> sign_string;
	fin.close();



	//用DSA公钥解签并验证是否跟验证信息一致
	int is_valid_signature = DSA_verify(0, (const unsigned char*)verify_string.data(), verify_string.length(),
		(const unsigned char*)sign_string.data(), sign_string.length(), dsa_public_key);


	//返回一个bool型变量
	if (is_valid_signature == 1)return true;
	else return false;
}



int main()
{
	if (DSA_verify_general("checked_file.txt", "BFEBFBFF000906E9E0D55EC381F0"))
	{
		cout << "VERIFY SUCCESSFULLY!!!" << endl;
	}
	else
	{
		cout << "VERIFY FAIL!!!" << endl;
	}
	system("pause");
	return 0;
}

用DSA公钥验证解签后的信息是否与机器码一致

关于如何获取运行机器的机器码请参考我这篇文章C++在windows下获得运行主机的硬件信息:CPU序列号、MAC地址、硬盘序列号、主板序列号

#pragma warning(disable:4996)
#include 
#include 
#include 
#include "get hardware information/get_hardware_information.h"
#include 
#include 
using namespace std;


/*
函数名:my_get_hardware_information
函数功能:获得本机硬件信息:CPU序列号,Mac地址,主板序列号,硬盘序列号
输入参数:None
返回参数:string类型,CPU序列号+Mac地址
作者:Leo Ma
时间:2019.09.15
*/
string my_get_hardware_information()
{
	char lpszCpu[128] = "";
	char lpszMac[128] = "";
	char lpszBaseBoard[128] = "";
	char lpszHDSerial[128] = "";

	GetCpuSerialByCmd(lpszCpu, 128);
	GetMacByCmd(lpszMac, 128);
	GetBaseBoardByCmd(lpszBaseBoard, 128);
	GetHDSerialByCmd(lpszHDSerial);
	//cout << "CPU ID is " << lpszCpu << endl;
	//cout << "MAC ID is " << lpszMac << endl;
	//cout << "Base Board ID is " << lpszBaseBoard << endl;
	//cout << "HD Serial is " << lpszHDSerial << endl;

	string string_return;
	string_return.assign(lpszCpu);
	string_return.append(lpszMac);
	//string_return.append("\0");
	//string_return.append(lpszBaseBoard);
	//string_return.append(lpszHDSerial);

	//cout << string_return << endl;
	return string_return;
}




/*
函数名:DSA_verify_machine
函数功能:用openssl的DSA接口验证当前机器码是否与解签的机器码一致
输入参数:None
返回参数:bool 若验证通过,返回true,否则返回false
作者:Leo Ma
时间:2019.09.15
*/

bool DSA_verify_machine()
{

	//读取本机机器码
	string hardware_info;
	hardware_info = my_get_hardware_information();//只获取CPU ID和Mac地址
	//hardware_info = get_hardware_information("check_file.txt");//获取CPU ID、Mac地址、主板序列号、硬盘序列号,并且生成文件
	

	//将DSA公钥写死在文件中
	//把DSA公钥文件内容复制到下面的字符串里,将多余的空格(这是VS编辑器的问题)删掉,换行符遵循UNIX(LF)格式,即使用\n换行
	string dsa_public_key_string = "-----BEGIN PUBLIC KEY-----\nMIIBtjCCASsGByqGSM44BAEwggEeAoGBAKenvEftAsim1cta2VzV+SCSiwJZFq6v\n+UvbdOTkM+mB9vq4NcV1mOEgPyXczgb+dU/Mn7Y0Zi5CkvCe18YyjaillKfGjVCt\n9ftffA/ML3axyfxsiPAuX0I1GRWJk6qbFaXImUAKUAGUiK1yKtJPnXIbnIQBYxji\nAXUcV6Pa6KwfAhUAhHBmLP8lIBIso865Bz7z5XQMKmkCgYBZiMp+oVyEuzZ8eS1d\nBWvbyKk/gnvGMxv10o/X1dWiD7JlT9iUl6J1kh8BnEIB6D4+zXStgq/g/t8+j/fK\nbwmin/zTC5LrzPtvzS2nsCEM4jL5UJzil24k3F8AQX5PUCt+TOwA0DudLz59K+An\nME+CxAPrCkcjg2tmco1RwO1QhQOBhAACgYA3ix4u+0IrSKDI605qCUgmBBbD3YlK\niACidMGZpzZnTaY3GzFt5m/Yn8o2mRfU2/Ouhssuum7uKXep4N9OhidM76ErPbpV\nIHP7n6fWx09MdLz5HkOmomVI8s9gQEog89Y9sw5KMymxln44QGyJPRqnRIKK+h58\ncX/Uar7hPftz7A==\n-----END PUBLIC KEY-----\n";
	ofstream public_key_file;
	public_key_file.open("dsa_public_key.pem");
	public_key_file << dsa_public_key_string;
	public_key_file.close();
	
	
	//从刚写好的文件中读取DSA公钥
	DSA* dsa_public_key = DSA_new();
	BIO *pubio;//Binary IO
	pubio = BIO_new_file("dsa_public_key.pem", "rb");
	dsa_public_key = PEM_read_bio_DSA_PUBKEY(pubio, &dsa_public_key, NULL, NULL);
	/*
	//另一种读取DSA公钥的方法
	DSA* dsa_public_key = DSA_new();
	FILE *pubio;
	pubio = fopen("dsa_public_key.pem", "rb");
	dsa_public_key = PEM_read_DSA_PUBKEY(pubio, &dsa_public_key, NULL, NULL);
	*/
	


	//从文件中读取DSA签名
	string sign_string;
	ifstream fin("checked_file.txt");
	if (!fin.is_open())
	{
		cout << "WARNING! NOT FOUND CHECKED FILE,PLEASE CONTACT TO THE ADMISTRATOR!!!" << endl;
		return 0;
	}
	fin >> sign_string;
	fin.close();
	


	//用DSA公钥验证签名和读取机器码是否一致
	int is_valid_signature = DSA_verify(0, (const unsigned char*)hardware_info.data(), hardware_info.length(),
											(const unsigned char*)sign_string.data(), sign_string.length(), dsa_public_key);


	//返回一个bool型变量
	if (is_valid_signature == 1)return true;
	else return false;
}



int main()
{
	if (DSA_verify_machine())
	{
		cout << "验证通过,假装执行代码" << endl;
	}
	else
	{
		cout << "CHECKED FAIL!PLEASE CONTACT THE ADMINASTOR!!!" << endl;
	}
	system("pause");
	return 0;
}

你可能感兴趣的:(安全)