OpenSSL 入门:密码学基础知识


OpenSSL 入门:密码学基础知识

文章插图
 
想要入门密码学的基础知识,尤其是有关 OpenSSL 的入门知识吗?继续阅读 。-- Marty Kalin(作者)
 
本文是使用 OpenSSL 的密码学基础知识的两篇文章中的第一篇,OpenSSL 是在 linux 和其他系统上流行的生产级库和工具包 。(要安装 OpenSSL 的最新版本,请参阅 这里。)OpenSSL 实用程序可在命令行使用,程序也可以调用 OpenSSL 库中的函数 。本文的示例程序使用的是 C 语言,即 OpenSSL 库的源语言 。
本系列的两篇文章涵盖了加密哈希、数字签名、加密和解密以及数字证书 。你可以从 我的网站 的 ZIP 文件中找到这些代码和命令行示例 。
让我们首先回顾一下 OpenSSL 名称中的 SSL 。
OpenSSL 简史安全套接字层 (Secure Socket Layer)(SSL)是 Netscape 在 1995 年发布的一种加密协议 。该协议层可以位于 HTTP 之上,从而为 HTTPS 提供了 S: 安全(secure) 。SSL 协议提供了各种安全服务,其中包括两项在 HTTPS 中至关重要的服务:
  • 对等身份验证(Peer authentication)(也称为相互质询):连接的每一边都对另一边的身份进行身份验证 。如果 Alice 和 Bob 要通过 SSL 交换消息,则每个人首先验证彼此的身份 。
  • 机密性(Confidentiality):发送者在通过通道发送消息之前先对其进行加密 。然后,接收者解密每个接收到的消息 。此过程可保护网络对话 。即使窃听者 Eve 截获了从 Alice 到 Bob 的加密消息(即中间人攻击),Eve 会发现他无法在计算上解密此消息 。
反过来,这两个关键 SSL 服务与其他不太受关注的服务相关联 。例如,SSL 支持消息完整性,从而确保接收到的消息与发送的消息相同 。此功能是通过哈希函数实现的,哈希函数也随 OpenSSL 工具箱一起提供 。
SSL 有多个版本(例如 SSLv2 和 SSLv3),并且在 1999 年出现了一个基于 SSLv3 的类似协议 传输层安全性(Transport Layer Security)(TLS) 。TLSv1 和 SSLv3 相似,但不足以相互配合工作 。不过,通常将 SSL/TLS 称为同一协议 。例如,即使正在使用的是 TLS(而非 SSL),OpenSSL 函数也经常在名称中包含 SSL 。此外,调用 OpenSSL 命令行实用程序以 openssl 开始 。
除了 man 页面之外,OpenSSL 的文档是零零散散的,鉴于 OpenSSL 工具包很大,这些页面很难以查找使用 。命令行和代码示例可以将主要主题集中起来 。让我们从一个熟悉的示例开始(使用 HTTPS 访问网站),然后使用该示例来选出我们感兴趣的加密部分进行讲述 。
一个 HTTPS 客户端此处显示的 client 程序通过 HTTPS 连接到 google:
/* compilation: gcc -o client client.c -lssl -lcrypto */#include <stdio.h>#include <stdlib.h>#include <openssl/bio.h> /* BasicInput/Output streams */#include <openssl/err.h> /* errors */#include <openssl/ssl.h> /* core library */#define BuffSize 1024void report_and_exit(const char* msg) {perror(msg);ERR_print_errors_fp(stderr);exit(-1);}void init_ssl() {SSL_load_error_strings();SSL_library_init();}void cleanup(SSL_CTX* ctx, BIO* bio) {SSL_CTX_free(ctx);BIO_free_all(bio);}void secure_connect(const char* hostname) {char name[BuffSize];char request[BuffSize];char response[BuffSize];const SSL_METHOD* method = TLSv1_2_client_method();if (NULL == method) report_and_exit("TLSv1_2_client_method...");SSL_CTX* ctx = SSL_CTX_new(method);if (NULL == ctx) report_and_exit("SSL_CTX_new...");BIO* bio = BIO_new_ssl_connect(ctx);if (NULL == bio) report_and_exit("BIO_new_ssl_connect...");SSL* ssl = NULL;/* 链路 bio 通道,SSL 会话和服务器端点 */sprintf(name, "%s:%s", hostname, "https");BIO_get_ssl(bio, &ssl); /* 会话 */SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); /* 鲁棒性 */BIO_set_conn_hostname(bio, name); /* 准备连接 *//* 尝试连接 */if (BIO_do_connect(bio) <= 0) {cleanup(ctx, bio);report_and_exit("BIO_do_connect...");}/* 验证信任库,检查证书 */if (!SSL_CTX_load_verify_locations(ctx,"/etc/ssl/certs/ca-certificates.crt", /* 信任库 */"/etc/ssl/certs/")) /* 其它信任库 */report_and_exit("SSL_CTX_load_verify_locations...");long verify_flag = SSL_get_verify_result(ssl);if (verify_flag != X509_V_OK)fprintf(stderr,"##### Certificate verification error (%i) but continuing...n",(int) verify_flag);/* 获取主页作为示例数据 */sprintf(request,"GET / HTTP/1.1\x0D\x0AHost: %s\x0D\x0A\x43onnection: Close\x0D\x0A\x0D\x0A",hostname);BIO_puts(bio, request);/* 从服务器读取 HTTP 响应并打印到输出 */while (1) {memset(response, '', sizeof(response));int n = BIO_read(bio, response, BuffSize);if (n <= 0) break; /* 0 代表流结束,< 0 代表有错误 */puts(response);}cleanup(ctx, bio);}int main() {init_ssl();const char* hostname = "www.google.com:443";fprintf(stderr, "Trying an HTTPS connection to %s...n", hostname);secure_connect(hostname);return 0;}


推荐阅读