首先需要使用openssl生成公钥和私钥,然后对字符串进行签名和认证.
license.h
#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <vector>
#define DEFAULT_BUFFER_SIZE 8192
class License {
public:
License() {}
~License() {}
///获取mac
void parse_mac_address(const char *file_name, const char *match_words, std::string &mac_address)
{
mac_address.c_str();
std::ifstream ifs(file_name, std::ios::binary);
if (!ifs.is_open()) {
return;
}
char line[4096] = {0};
while (!ifs.eof()) {
ifs.getline(line, sizeof(line));
if (!ifs.good()) {
break;
}
const char *mac = strstr(line, match_words);
if (NULL == mac) {
continue;
}
mac += strlen(match_words);
while ('\0' != mac[0]) {
if (' ' != mac[0] && ':' != mac[0]) {
mac_address.push_back(mac[0]);
}
++mac;
}
if (!mac_address.empty()) {
break;
}
}
ifs.close();
}
///by_system获取mac
bool get_mac_address_by_system(std::string &mac_address)
{
mac_address.clear();
const char *lshw_result = ".lshw_result.txt";
char command[512] = {0};
snprintf(command, sizeof(command), "lshw -c network | grep serial | head -n 1 > %s", lshw_result);
if (0 == system(command)) {
parse_mac_address(lshw_result, "serial:", mac_address);
}
unlink(lshw_result);
return (!mac_address.empty());
}
///获取本机全部的mac地址
bool get_mac_address(std::vector<std::string> &mac_address)
{
struct ifreq ifr;
struct ifconf ifc;
char buf[2048];
int success = 0;
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
printf("socket error\n");
return -1;
}
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
printf("ioctl error\n");
return -1;
}
struct ifreq* it = ifc.ifc_req;
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
char szMac[64];
for (; it != end; ++it) {
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
unsigned char * ptr ;
ptr = (unsigned char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];
snprintf(szMac,64,"%02X:%02X:%02X:%02X:%02X:%02X",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));
printf("%s : %s \n",ifr.ifr_name,szMac);
if(strncmp(ifr.ifr_name,"eth",3) == 0)
{
mac_address.push_back(szMac);
break;
}
}
}
}else{
printf("get mac info error\n");
return -1;
}
}
}
//base64转码
char *enbase64(const char *input, size_t length, size_t size)
{
BIO *bmem = NULL;
BIO *b64 = NULL;
BUF_MEM *bptr = NULL;
assert(NULL != input);
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new(BIO_s_mem());
if (NULL == b64 || NULL == bmem) {
perror("BIO_new");
return NULL;
}
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
b64 = BIO_push(b64, bmem);
BIO_write(b64, input, length);
BIO_flush(b64);
BIO_get_mem_ptr(b64, &bptr);
if ((unsigned int) (bptr->length + 1) > size) {
BIO_free_all(b64);
return NULL;
}
char *result = new char[bptr->length];
memset(result, 0, bptr->length);
memcpy(result, bptr->data, bptr->length);
result[bptr->length] = 0;
BIO_free_all(b64);
return result;
}
//base64转码
char *debase64(char *input, size_t length, size_t size)
{
BIO *b64 = NULL;
BIO *bmem = NULL;
assert(NULL != input);
if (length > size)
return NULL;
char *result = new char[size];
memset(result, 0, size);
b64 = BIO_new(BIO_f_base64());
bmem = BIO_new_mem_buf(input, length);
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
if (NULL == b64 || NULL == bmem) {
perror("BIO_new");
return NULL;
}
bmem = BIO_push(b64, bmem);
BIO_read(bmem, result, length);
BIO_free_all(b64);
return result;
}
///签名
char *rsa_sign(const char *text, size_t size, const char *sk_filename)
{
RSA *rsa;
unsigned int len;
char *signature = nullptr;
assert(text != NULL && sk_filename != NULL);
OpenSSL_add_all_algorithms();
BIO *in = NULL;
in = BIO_new(BIO_s_file());
BIO_read_filename(in, sk_filename);
if (in == NULL) {
perror(sk_filename);
return NULL;
}
//将IO中数据以PEM格式读入EVP_PKEY结构中
rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL, NULL);
if (in != NULL)
BIO_free(in);
if (rsa == NULL) {
perror("PEM_read_bio_RSAPrivateKey");
return NULL;
}
unsigned char *sig = new unsigned char[RSA_size(rsa)];
unsigned char sha1[20] = {'\0'};
//result len of sha1:20 bytes
SHA1((const unsigned char *) text, strlen(text), sha1);
if (1 != RSA_sign(NID_sha1, sha1, 20, sig, &len, rsa)) {
delete[] sig;
sig = nullptr;
RSA_free(rsa);
printf("RSA_sign error.\n");
return NULL;
}
signature = enbase64((char *) sig, 128, size);
if (!signature) {
delete[] sig;
sig = nullptr;
RSA_free(rsa);
printf("enbase64 error.\n");
return NULL;
}
delete[] sig;
sig = nullptr;
RSA_free(rsa);
return signature;
}
///验证
bool rsa_verify(const char *text, char *signature, const char *pk_filename)
{
RSA *rsa;
BIO *in = NULL;
assert(NULL != text && NULL != signature);
in = BIO_new(BIO_s_file());
BIO_read_filename(in, pk_filename);
if (NULL == in) {
printf("BIO_read_filename error.\n");
return false;
}
//将IO中数据以PEM格式读入EVP_PKEY结构中
//rsa = PEM_read_bio_RSAPublicKey(in, NULL, NULL, NULL);
rsa = PEM_read_bio_RSA_PUBKEY(in, NULL, NULL, NULL);
if (in != NULL) BIO_free(in);
if (rsa == NULL) {
printf("PEM_read_bio_RSA_PUBKEY error.\n");
return false;
}
//unsigned char sig_temp[250];
char *sig_debase = debase64(signature, strlen((char *) signature), 250);
if (!sig_debase) {
RSA_free(rsa);
printf("debase64 error.\n");
return false;
}
unsigned char sha1[20];
SHA1((const unsigned char *) text, strlen(text), sha1);
if (1 != RSA_verify(NID_sha1, sha1, 20, (unsigned char *) sig_debase, 128, rsa)) {
delete[] sig_debase;
sig_debase = nullptr;
RSA_free(rsa);
printf("RSA_verify error.\n");
return false;
}
delete[] sig_debase;
sig_debase = nullptr;
RSA_free(rsa);
return true;
}
//根据license-key.txt获取文件信息
char* getlicense(const char* file_name)
{
FILE *pFile;
size_t lSize;
char *buffer;
size_t result;
pFile = fopen(file_name, "rb");
if (pFile == NULL)
fputs("File error", stderr);
fseek(pFile, 0, SEEK_END);
lSize = ftell(pFile);
rewind(pFile);
buffer = new char[lSize];
if (buffer == NULL)
fputs("Memory error", stderr);
result = fread(buffer, 1, lSize, pFile);
if (result != lSize)
fputs("Reading error", stderr);
return buffer;
}
};
main.cpp
#include <iostream>
#include "license.h"
int main()
{
License license;
//获取mac_address
std::vector<std::string> vec_mac_address;
license.get_mac_address(vec_mac_address);
//给mac_address签名后生成一个字符串
char *signature = license.rsa_sign(vec_mac_address[0].c_str(), DEFAULT_BUFFER_SIZE,"rsa_private_key.pem");
printf ("signature: %s\n",signature);
//把签名后的字符串存到license-key.txt
FILE *fp;
if((fp=fopen("license-key.txt","a"))==NULL)
{
printf("You can't open the license-key.txt!\n");
exit(1);
}
fprintf(fp,"%s",signature);
fclose(fp);
//认证
bool bRet =license.rsa_verify(vec_mac_address[0].c_str(),signature,"rsa_public_key.pem");
if (bRet == true)
{
printf ("认证通过!\n");
}
else
{
printf ("认证失败!\n");
}
delete[] signature;
signature = nullptr;
return 0;
}
运行结果:
eth1 : 2C:FD:A1:5C:B0:B1
signature: h6dg747tF7Wxa+NNo24uo1vQKO0sYHbBgaXWTzrcG7tsXHbZ5AKAmLK9wopMohhjMFP4HSscYmKwHjaTBCqfWX3gP5RL5Ut2BV7bSbhmtDP/ow4aDBo9+hFSh5SGPBvmGN7bl0l8zER6ugCLASAyj1nQQYAsNySvfe9m9+G8go0=
认证通过!