博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
openssl密码库_OpenSSL入门:密码学基础
阅读量:2527 次
发布时间:2019-05-11

本文共 13385 字,大约阅读时间需要 44 分钟。

openssl密码库

本文是使用的两种加密基础知识的第一篇, 是Linux和其他系统上流行的生产级库和工具包。 (要安装OpenSSL的最新版本,请参见 。)命令行中提供了OpenSSL实用程序,程序可以从OpenSSL库中调用函数。 本文的示例程序使用C语言,即OpenSSL库的源语言。

本系列的两篇文章共同介绍了加密哈希,数字签名,加密和解密以及数字证书。 您可以从的ZIP文件中找到代码和命令行示例。

让我们首先回顾一下OpenSSL名称中的SSL。

快速的历史

是在1995年发布的一种加密协议。该协议层可以位于HTTP之上,从而为HTTPS中的安全提供S。 SSL协议提供了各种安全服务,其中包括两项在HTTPS中居中的服务:

  • 对等身份验证(又称相互挑战):连接的每一边都对另一边的身份进行身份验证。 如果爱丽丝和鲍勃要通过SSL交换消息,则彼此首先验证彼此的身份。
  • 机密性:发件人在通过通道发送消息之前先对其进行加密。 接收器然后解密每个接收到的消息。 此过程可保护网络对话。 即使窃听者Eve截获了从Alice到Bob的加密消息( 中间人攻击),Eve仍发现在计算上无法解密此消息。

反过来,这两个关键SSL服务与其他引起较少关注的服务相关。 例如,SSL支持消息完整性,从而确保接收到的消息与发送的消息相同。 此功能是通过散列函数实现的,散列函数也随OpenSSL工具包一起提供。

SSL已版本化(例如SSLv2和SSLv3),并且在1999年,传输层安全性(TLS)成为基于SSLv3的类似协议。 TLSv1和SSLv3相似,但不足以相互配合。 但是,通常将SSL / TLS称为同一协议。 例如,即使正在使用TLS(而不是SSL),OpenSSL函数也经常在名称中包含SSL。 此外,调用OpenSSL命令行实用程序以术语openssl开头。

除了手册页之外,OpenSSL的文档也参差不齐,考虑到OpenSSL工具包的规模,它们变得笨拙。 命令行和代码示例是将主要主题集中在一起的一种方法。 让我们从一个熟悉的示例开始-使用HTTPS访问网站-并使用该示例来挑选感兴趣的加密片段。

HTTPS客户端

此处显示的客户端程序通过HTTPS连接到Google:

/* compilation: gcc -o client client.c -lssl -lcrypto */      
#include
#include
#include
/* BasicInput/Output streams */
#include
/* errors */
#include
/* core library */
#define BuffSize 1024
void report_and_exit
(
const
char
* msg
)
{
 
( msg
)
;
  ERR_print_errors_fp
( stderr
)
;
 
(
-
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
;
 
/* link bio channel, SSL session, and server endpoint */
 
( name
,
"%s:%s"
, hostname
,
"https"
)
;
  BIO_get_ssl
( bio
,
& ssl
)
;
/* session */
  SSL_set_mode
( ssl
, SSL_MODE_AUTO_RETRY
)
;
/* robustness */
  BIO_set_conn_hostname
( bio
, name
)
;
/* prepare to connect */
 
/* try to connect */
 
if
( BIO_do_connect
( bio
)
<=
0
)
{
    cleanup
( ctx
, bio
)
;
    report_and_exit
(
"BIO_do_connect..."
)
;
 
}
 
/* verify truststore, check cert */
 
if
(
! SSL_CTX_load_verify_locations
( ctx
,
                                     
"/etc/ssl/certs/ca-certificates.crt"
,
/* truststore */
                                     
"/etc/ssl/certs/"
)
)
/* more truststore */
    report_and_exit
(
"SSL_CTX_load_verify_locations..."
)
;
 
long verify_flag
= SSL_get_verify_result
( ssl
)
;
 
if
( verify_flag
!= X509_V_OK
)
   
( stderr
,
           
"##### Certificate verification error (%i) but continuing... \n "
,
           
(
int
) verify_flag
)
;
 
/* now fetch the homepage as sample data */
 
( request
,
         
"GET / HTTP/1.1 \x0D \x0A Host: %s \x0D \x0A \x43 onnection: Close \x0D \x0A \x0D \x0A "
,
          hostname
)
;
  BIO_puts
( bio
, request
)
;
 
/* read HTTP response from server and print to stdout */
 
while
(
1
)
{
   
( response
,
' \0 '
,
sizeof
( response
)
)
;
   
int n
= BIO_read
( bio
, response
, BuffSize
)
;
   
if
( n
<=
0
)
break
;
/* 0 is end-of-stream, < 0 is an error */
 
( response
)
;
 
}
  cleanup
( ctx
, bio
)
;
}
int main
(
)
{
  init_ssl
(
)
;
 
const
char
* hostname
=
"www.google.com:443"
;
 
( stderr
,
"Trying an HTTPS connection to %s... \n "
, hostname
)
;
  secure_connect
( hostname
)
;
return
0
;
}

可以从命令行编译和执行此程序(请注意-lssl-lcrypto中的小写L):

GCC -o 客户端 .C - lssl - lcrypto

该程序尝试打开与网站的安全连接。 作为与Google Web服务器的TLS握手的一部分, 客户端程序会接收一个或多个数字证书,该程序会尝试对其进行验证(但在我的系统上失败)。 尽管如此, 客户端程序仍继续通过安全通道获取Google主页。 该程序取决于前面提到的安全工件,尽管在代码中仅数字证书突出。 其他文物仍在后台,稍后将对其进行详细说明。

通常,打开HTTP(非安全)通道的C或C ++客户端程序将使用诸如网络套接字的 文件描述符之类的构造,该套接字是两个进程之间连接的端点(例如,客户端程序和Google Web服务器)。 反过来,文件描述符是一个非负整数值,它在程序内标识该程序打开的任何类似文件的构造。 这样的程序还将使用一种结构来指定有关Web服务器地址的详细信息。

这些相对较低级别的构造都不会在客户端程序中发生,因为OpenSSL库会将套接字基础结构和地址规范包装在高级安全构造中。 结果是一个简单的API。 首先看一下示例客户端程序中的安全性详细信息。

  • 该程序首先加载相关的OpenSSL库,然后我的函数init_ssl对OpenSSL进行两次调用:

    SSL_library_init(); SSL_load_error_strings();

  • 下一个初始化步骤尝试获取安全上下文 ,这是建立和维护通往Web服务器的安全通道所需的信息框架。 在示例中使用TLS 1.2 ,如对OpenSSL库函数的此调用所示:

    const SSL_METHOD *方法= TLSv1_2_client_method(); / * TLS 1.2 * /

    如果调用成功,则方法指针将传递到创建SSL_CTX类型上下文的库函数:

    SSL_CTX * ctx = SSL_CTX_new (方法);

    客户端程序检查每个关键库调用中的错误,然后,如果其中一个调用失败,则程序终止。

  • 现在还可以使用另外两个OpenSSL工件: SSL类型的安全会话,该会话从头到尾管理安全连接; BIO (基本输入/输出)类型的安全流,用于与Web服务器通信。 BIO流是通过以下调用生成的:

    BIO * bio = BIO_new_ssl_connect( ctx );

    请注意,最重要的上下文是参数。 BIO类型是C中FILE类型的OpenSSL包装器。此包装器可保护客户端程序和Google的Web服务器之间的输入和输出流。

  • 有了SSL_CTXBIO ,该程序便在SSL会话中将它们链接在一起。 三个库调用可以完成工作:

    BIO_get_ssl(bio,&ssl); / *获得TLS会话* /

    SSL_set_mode(ssl,SSL_MODE_AUTO_RETRY); / *健壮性* /

    BIO_set_conn_hostname(bio,name); / *准备连接到Google * /

    安全连接本身是通过以下调用建立的:

    BIO_do_connect(bio);

    如果最后一次调用不成功,则客户端程序终止;否则, 客户端程序终止。 否则,连接已准备就绪,可以支持客户端程序与Google Web服务器之间的机密对话。

在与Web服务器握手期间, 客户端程序会接收一个或多个数字证书,以认证服务器的身份。 但是, 客户端程序不会发送自己的证书,这意味着身份验证是单向的。 (通常将Web服务器配置为希望获得客户端证书。)尽管Web服务器证书的验证失败,但是客户端程序仍继续通过安全通道将Google主页获取到Web服务器,从而继续执行该程序。

为什么验证Google证书的尝试失败? 典型的OpenSSL安装目录为/ etc / ssl / certs ,其中包含ca-certificates.crt文件。 该目录和文件一起包含OpenSSL开箱即用信任的数字证书,因此构成了信任库 。 可以根据需要更新信任库,尤其是可以包括新信任的证书,并删除不再受信任的证书。

客户端程序从Google Web服务器接收了三个证书,但是我的计算机上的OpenSSL信任库不包含完全匹配项。 如目前所写, 客户端程序不会通过例如验证Google证书上的数字签名(证明该证书的签名)来解决此问题。 如果该签名是受信任的,则包含该签名的证书也应受信任。 尽管如此,客户端程序仍继续进行获取,然后打印Google的主页。 下一节将更详细地介绍。

客户端程序中隐藏的安全性部分

让我们从客户端示例中的可见安全工件(数字证书)开始,并考虑其他安全工件如何与之相关。 数字证书的主要布局标准是X509,生产级证书由诸如的证书颁发机构(CA)颁发。

数字证书包含各种信息(例如,激活和到期日期以及所有者的域名),包括发行者的身份和数字签名 ,该信息是加密的密码哈希值。 证书还具有未加密的哈希值,用作其识别指纹

将任意数量的位映射到固定长度的摘要会产生哈希值。 这些位所代表的内容(会计报告,小说或数字电影)无关紧要。 例如,消息摘要版本5(MD5)哈希算法将任意长度的输入位映射到128位哈希值,而SHA1(安全哈希算法版本1)算法将输入位映射到160位值。 不同的输入位会导致不同的(实际上是统计学上唯一的)哈希值。 下一篇文章将进一步详细介绍,并将重点放在使散列函数成为密码的方面

数字证书的类型不同(例如, 证书, 中间证书和最终实体证书),并形成反映这些类型的层次结构。 顾名思义, 证书位于层次结构的顶部,其下的证书继承了根证书所具有的信任。 OpenSSL库和大多数现代编程语言都具有X509类型以及处理此类证书的功能。 来自Google的证书具有X509格式,并且客户端程序检查此证书是否为X509_V_OK

X509证书基于公共密钥基础结构(PKI),其中包括用于生成密钥对的算法-RSA是占主导地位的算法-公钥及其配对的私钥。 公共密钥是一种身份: 公共密钥可以标识它,而我的公共密钥可以标识我。 私钥应由其所有者保守秘密。

一对钥匙具有标准用途。 可以使用公共密钥对消息进行加密,然后可以使用同一对中的私有密钥对消息进行解密。 私钥也可以用于对文档或其他电子产品(例如程序或电子邮件)进行签名,然后可以使用该对中的公钥来验证签名。 以下两个示例填充了一些细节。

在第一个示例中,爱丽丝将她的公钥分发给世界,包括鲍勃。 然后,Bob使用Alice的公钥加密消息,然后将加密的消息发送给Alice。 用爱丽丝的公钥加密的消息用她的私钥解密,而她的私钥(假设)只有她自己,例如:

             +------------------+ encrypted msg  +-------------------+     
Bob's msg--->|Alice's public key|--------------->|Alice's private key|---> Bob's msg
             +------------------+                +-------------------+

原则上可以在没有Alice私钥的情况下解密消息,但在实际情况下,如果使用像RSA这样的加密密钥对系统,则无法实现。

现在,对于第二个示例,考虑对文档进行签名以证明其真实性。 签名算法使用一对中的私钥来处理要签名的文档的加密哈希:

                    +-------------------+     
Hash of document--->|Alice's private key|--->Alice's digital signature of the document
                    +-------------------+

假设Alice以数字方式签署了发送给Bob的合同。 然后,Bob可以使用密钥对中的Alice的公钥来验证签名:

                                             +------------------+     
Alice's digital signature of the document--->|Alice's public key|--->verified or not
                                             +------------------+

没有Alice的私钥就无法伪造Alice的签名:因此,将其私钥保密是符合Alice的利益的。

客户端程序中,除了数字证书以外,这些安全性都没有明确规定。 下一篇文章使用使用OpenSSL实用程序和库函数的示例填充详细信息。

命令行中的OpenSSL

同时,让我们看一下OpenSSL命令行实用程序:尤其是在TLS握手期间检查来自Web服务器的证书的实用程序。 调用OpenSSL实用程序从openssl命令开始,然后添加参数和标志的组合以指定所需的操作。

考虑以下命令:

openssl list-cipher-algorithms

输出是组成密码套件的相关算法的列表。 这是列表的开始,带有注释以澄清首字母缩写词:

AES-128-CBC ## Advanced Encryption Standard, Cipher Block Chaining      
AES-128-CBC-HMAC-SHA1 ## Hash-based Message Authentication Code with SHA1 hashes
AES-128-CBC-HMAC-SHA256 ## ditto, but SHA256 rather than SHA1
...

使用参数s_client的下一个命令将打开到的安全连接,并在屏幕上显示有关该连接的所有信息:

OpenSSL的的s_client.First -connect - showcerts

端口号443是Web服务器用于接收HTTPS而不是HTTP连接的标准端口号。 (对于HTTP,标准端口为80。)网络地址也在客户端程序的代码中出现。 如果尝试的连接成功,则将显示来自Google的三个数字证书以及有关安全会话,正在使用的密码套件以及相关项目的信息。 例如,这是从头开始的一部分输出,它宣布证书链即将到来。 证书的编码为base64:

Certificate chain      
 0 s:/C=US/ST=California/L=Mountain View/O=Google LLC/CN=www.google.com
 i:/C=US/O=Google Trust Services/CN=Google Internet Authority G3
-----BEGIN CERTIFICATE-----
MIIEijCCA3KgAwIBAgIQdCea9tmy/T6rK/dDD1isujANBgkqhkiG9w0BAQsFADBU
MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMSUw
...

诸如Google之类的主要网站通常会发送多个证书进行身份验证。

输出以有关TLS会话的摘要信息结尾,包括密码套件的详细信息:

SSL-Session:      
    Protocol : TLSv1.2
    Cipher : ECDHE-RSA-AES128-GCM-SHA256
    Session-ID: A2BBF0E4991E6BBBC318774EEE37CFCB23095CC7640FFC752448D07C7F438573
...

客户端程序中使用了协议TLS 1.2 ,并且Session-ID唯一标识了openssl实用程序和Google Web服务器之间的连接。 密码项可以按以下方式进行解析:

  • ECDHE (椭圆曲线Diffie Hellman瞬时)是一种用于管理TLS握手的有效算法。 特别地,ECDHE通过确保连接的双方(例如,客户端程序和Google Web服务器)使用相同的加密/解密密钥(称为会话密钥 )来解决密钥分发问题 。 后续文章深入探讨了细节。

  • RSA (Rivest Shamir Adleman)是主要的公共密钥密码系统,以1970年代末首次描述该系统的三位学者命名。 正在使用的密钥对是使用RSA算法生成的。

  • AES128 (高级加密标准)是一种块密码 ,用于加密和解密位块。 (另一种选择是流密码 ,一次加密和解密一位。)密码是对称的 ,因为使用相同的密钥进行加密和解密,这首先引起了密钥分配问题。 AES支持128(在此处使用),192和256位的密钥大小:密钥越大,保护越好。

    通常,对称密码系统(例如AES)的密钥大小小于非对称(基于密钥对)系统(例如RSA)的密钥大小。 例如,1024位RSA密钥相对较小,而256位密钥当前是AES最大的密钥。

  • GCM (Galois计数器模式)在安全对话期间处理密码(在本例中为AES128)的重复应用。 AES128块的大小仅为128位,安全对话很可能包含从一侧到另一侧的多个AES128块。 GCM非常有效,通常与AES128搭配使用。

  • SHA256 (256位安全哈希算法)是正在使用的加密哈希算法。 生成的哈希值大小为256位,尽管使用SHA甚至可以达到更大的值。

密码套件正在不断发展。 例如,不久前,谷歌使用RC4流密码(Ron的Cipher版本4,来自RSA的Ron Rivest)。 RC4现在具有已知的漏洞,这至少部分是由Google转换为AES128引起的。

结语

通过安全的C Web客户端和各种命令行示例对OpenSSL的首次了解,使少数需要进一步澄清的主题脱颖而出。 ,从加密散列开始,最后以关于数字证书如何解决密钥分发挑战的更完整的讨论结尾。

翻译自:

openssl密码库

转载地址:http://yeizd.baihongyu.com/

你可能感兴趣的文章
代码片段收集
查看>>
vue-cli3创建项目时报错
查看>>
输入1-53周,输出1-53周的开始时间和结束时间
查看>>
实验二
查看>>
shell——按指定列排序
查看>>
crash 收集
查看>>
507 LOJ 「LibreOJ NOI Round #1」接竹竿
查看>>
UI基础--烟花动画
查看>>
2018. 2.4 Java中集合嵌套集合的练习
查看>>
精通ASP.NET Web程序测试
查看>>
vue 根据不同属性 设置背景
查看>>
51Nod1601 完全图的最小生成树计数 Trie Prufer编码
查看>>
Codeforces 1110D. Jongmah 动态规划
查看>>
android驱动在win10系统上安装的心酸历程
查看>>
优雅的程序员
查看>>
oracle之三 自动任务调度
查看>>
Android dex分包方案
查看>>
ThreadLocal为什么要用WeakReference
查看>>
删除本地文件
查看>>
FOC实现概述
查看>>