概述
本文主要講到了openssl的基本使用方法,開發(fā)環(huán)境為windows,開發(fā)工具為VS2019.本文主要是說明openssl如何使用,不介紹任何理論知識,如果有不懂的,請自行百度。個人建議下一個everything查詢工具,真的很好用,比window自帶的查詢快了很多,可以查詢自己想要的文件
OPENSSL安裝
安裝過程網(wǎng)上有很多,OPENSSL安裝,注意你安裝的OPENSSL的版本以及位數(shù)(32位或者64位),假如我安裝的是64位的openssl,安裝目錄為D:\Program Files\OpenSSL-Win64,你可以自行選擇你的安裝目錄,安裝完成后,查看安裝的openssl版本,使用控制臺輸入openssl version即可
秘鑰key和公鑰的生成
在控制命令行中輸入以下命令:
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -sha256 -days 365
網(wǎng)上有很多生成秘鑰和公鑰的文章,不過都沒成功,最后在stackoverflow找到了可以用的方法,原文地址為:openssl秘鑰和公鑰的生成,以下是截圖
Enter PEM pass phrase:提示輸入pem文件的密碼,注意,后面要用到這個密碼,可以使用自己常用的密碼,輸入后會再次確認密碼,然后就是一些基本信息,可以默認為空。截圖如下,基本上這時候就得到了秘鑰key.pem和公鑰cert.pem,后面要用到這2個文件。,生成的位置為當前目錄,比如我的就是在C:\Users\86138,即控制臺的顯示目錄。
項目設置
使用VS創(chuàng)建一個控制臺項目,創(chuàng)建一個客戶端和服務器項目,由于我下載的是64位,openssl3.0版本。因此我項目也是64位的。
項目的配置,服務器端和客戶端都是相同配置,這里我就只說一個即可,主要是設置openssl的lib和頭文件的路徑,這和使用任外部庫都是一樣的。截圖如下,注意我的openssl安裝位置為D:\Program Files\OpenSSL-Win64,請選擇你安裝位置即可。
預處理器里添加2個定義:CRT_SECURE_NO_WARNINGS;_WINSOCK_DEPRECATED_NO_WARNINGS;
附加依賴項:libssl.lib;openssl.lib;libcrypto.lib;liblegacy.lib;
最后將前面生成的cert.pem和key.pem放到exe目錄下,為什么放到這個目錄,是因為下面的代碼用到的這2個文件是當前目錄,不管怎么樣,只要能找到這2個文件即可。
配置很簡單,就上面幾步,基本上就可以了。文章來源:http://www.zghlxwxcb.cn/news/detail-405764.html
代碼部分
客戶端代碼
#include <stdio.h>
#include <errno.h>
#include <malloc.h>
#include <string.h>
# include <winsock2.h>
#include <ws2tcpip.h>
#include <openssl/ssl.h>
#include <openssl/err.h>
#define FAIL -1
#pragma comment(lib, "Ws2_32.lib")
//Added the LoadCertificates how in the server-side makes.
int OpenConnection(const char* hostname, int port)
{
SOCKET sd;
struct hostent* host;
struct sockaddr_in addr;
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0)
{
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
sd = socket(PF_INET, SOCK_STREAM, 0);
/bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = inet_addr(hostname);
int ret = connect(sd, (struct sockaddr*)&addr, sizeof(addr));
if ( ret != 0)
{
//close(sd);
perror(hostname);
abort();
}
return sd;
}
SSL_CTX* InitCTX(void)
{
//SSL_METHOD* method;
SSL_CTX* ctx;
//OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
SSL_METHOD const* meth = SSLv23_client_method(); /* Create new client-method instance */
//method = TLSv1_method();
ctx = SSL_CTX_new(meth); /* Create new context */
if (ctx == NULL)
{
ERR_print_errors_fp(stderr);
printf("Eroor: %s\n", stderr);
abort();
}
return ctx;
}
void ShowCerts(SSL* ssl)
{
X509* cert;
char* line1, * line2;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if (cert != NULL)
{
printf("Server certificates:\n");
line1 = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line1);
//free(line); /* free the malloc'ed string */
line2 = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line2);
//free(line); /* free the malloc'ed string */
//X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("No certificates.\n");
}
int main(int count, char* strings[])
{
SSL_CTX* ctx;
SOCKET server;
SSL* ssl;
char buf[1024];
int bytes;
char const *hostname, *portnum;
SSL_library_init();
hostname = "127.0.0.1";
portnum = "1030";
ctx = InitCTX();
server = OpenConnection(hostname, atoi(portnum));
ssl = SSL_new(ctx); /* create new SSL connection state */
//SSL_set_fd(ssl, server); /* attach the socket descriptor */
BIO* bio = BIO_new_socket(server, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);
SSL_set_connect_state(ssl);
if (SSL_connect(ssl) == FAIL) /* perform the connection */
{
printf("Eroor: %s\n", stderr);
ERR_print_errors_fp(stderr);
}
else
{
printf("Connected with %s encryption\n", SSL_get_cipher(ssl));
ShowCerts(ssl); /* get any certs */
while (1)
{
char p[100];
printf("please input sned msg: ");
gets(p);
printf("strlen:%d,%s\n", strlen(p), p);
SSL_write(ssl, p, strlen(p)); /* encrypt & send message */
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
if (bytes >= 0)
{
buf[bytes] = '\0';
printf("Received: \"%s\"\n", buf);
}
else
{
SSL_ERROR_WANT_READ;
int error = SSL_get_error(ssl, bytes);
printf("error:%d\n", error);
break;
}
}
SSL_shutdown(ssl);
SSL_free(ssl); /* release connection state */
}
SSL_CTX_free(ctx); /* release context */
getchar();
return 0;
}
服務器端代碼
#include <errno.h>
#include <malloc.h>
#include <string.h>
# include <winsock2.h>
# include <ws2tcpip.h>
#include "openssl/ssl.h"
#include "openssl/err.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "openssl/applink.c"
#ifdef __cplusplus
}
#endif
#define FAIL -1
#pragma comment(lib, "Ws2_32.lib")
int OpenListener(WORD port)
{
SOCKET m_socket;
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
m_socket = socket(AF_INET, SOCK_STREAM, 0);
if (m_socket == INVALID_SOCKET)
{
printf("Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
struct sockaddr_in sain;
//bzero(&addr, sizeof(addr));
sain.sin_family = AF_INET;
sain.sin_port = htons(port);
sain.sin_addr.s_addr = inet_addr("127.0.0.1");
if (bind(m_socket, (struct sockaddr*)&sain, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
perror("can't bind port");
//abort();
}
if (listen(m_socket, 10) != 0)
{
perror("Can't configure listening port");
//abort();
}
return m_socket;
}
SSL_CTX* InitServerCTX(void)
{
SSL_CTX* ctx = NULL;
#if OPENSSL_VERSION_NUMBER >= 0x10000000L
const SSL_METHOD* method;
#else
SSL_METHOD* method;
#endif
SSL_library_init();
//OpenSSL_add_all_algorithms(); /* load & register all cryptos, etc. */
SSL_load_error_strings(); /* load all error messages */
//method = SSLv23_method(); /* create new server-method instance */
method = SSLv23_server_method();
ctx = SSL_CTX_new(method); /* create new context from method */
if (ctx == NULL)
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
void LoadCertificates(SSL_CTX* ctx, char* CertFile, char* KeyFile)
{
//New lines
int ret = SSL_CTX_load_verify_locations(ctx, CertFile, KeyFile);
if (ret != 1)
ERR_print_errors_fp(stderr);
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
ERR_print_errors_fp(stderr);
//End new lines
/* set the local certificate from CertFile */
if (SSL_CTX_use_certificate_file(ctx, CertFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
//abort();
}
/* set the private key from KeyFile (may be the same as CertFile) */
if (SSL_CTX_use_PrivateKey_file(ctx, KeyFile, SSL_FILETYPE_PEM) <= 0)
{
ERR_print_errors_fp(stderr);
abort();
}
/* verify private key */
if (!SSL_CTX_check_private_key(ctx))
{
fprintf(stderr, "Private key does not match the public certificate\n");
abort();
}
printf("LoadCertificates success\n");
}
void ShowCerts(SSL* ssl)
{
X509* cert;
char* line;
cert = SSL_get_peer_certificate(ssl); /* Get certificates (if available) */
if (cert != NULL)
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line);
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line);
X509_free(cert);
}
else
printf("No certificates.\n");
}
void Servlet(SSL* ssl, SOCKET client) /* Serve the connection -- threadable */
{
char buf[1024];
char reply[1024];
int sd, bytes;
const char* HTMLecho = "hello client";
ShowCerts(ssl); /* get any certificates */
int ret = SSL_accept(ssl);
while (1)
{
//bytes = recv(client, buf, sizeof(buf), 0);
bytes = SSL_read(ssl, buf, sizeof(buf));
if (bytes > 0)
{
buf[bytes] = '\0';
printf("Client msg: %s\n", buf);
sprintf(reply, HTMLecho, buf); /* construct reply */
SSL_write(ssl, reply, strlen(reply)); /* send reply */
}
else //其他情況
{
//printf("read byte < 0\n");
}
}
SSL_shutdown(ssl);
SSL_free(ssl);
}
int main(int count, char* strings[])
{
SSL_CTX* ctx;
SOCKET server;
char* portnum;
server = OpenListener(1030); /* create server socket */
SSL_library_init();
portnum = strings[1];
ctx = InitServerCTX(); /* initialize SSL */
LoadCertificates(ctx, (char *)"cert.pem", (char *)"key.pem"); /* load certs */
while (1)
{
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
SSL* ssl;
SOCKET client = accept(server, (struct sockaddr*)&addr, &len); /* accept connection as usual */
socklen_t len1;
struct sockaddr_storage addr1;
//add1.sin_family = AF_INET;
char ipstr[INET6_ADDRSTRLEN];
int port;
len1 = sizeof addr;
int r;
r = getpeername(client, (struct sockaddr*)&addr1, &len1);
// deal with both IPv4 and IPv6:
if (addr1.ss_family == AF_INET)
{
struct sockaddr_in* s = (struct sockaddr_in*)&addr1;
port = ntohs(s->sin_port);
inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
}
else
{ // AF_INET6
struct sockaddr_in6* s = (struct sockaddr_in6*)&addr1;
port = ntohs(s->sin6_port);
inet_ntop(AF_INET6, &s->sin6_addr, ipstr, sizeof ipstr);
}
printf("Peer IP address: %s,port:%d\n", ipstr,port);
ssl = SSL_new(ctx); /* get new SSL state with context */
//SSL_set_fd(ssl, client); /* set connection socket to SSL state */
BIO* bio = BIO_new_socket(client, BIO_NOCLOSE);
SSL_set_bio(ssl, bio, bio);
Servlet(ssl, client); /* service connection */
}
SSL_CTX_free(ctx); /* release context */
}
總結(jié)
可能遇到的問題
1.要確保代碼中applink.c文件的存在,否則服務器端代碼會提示Unlink的錯誤
2.服務器端代碼要求輸入密碼,請使用生成秘鑰時的密碼文章來源地址http://www.zghlxwxcb.cn/news/detail-405764.html
到了這里,關(guān)于windows openssl安裝和基本使用(代碼演示)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!