【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数

零:前言(与正文内容无关):

1.写项目中,关于用户注册登录时的密码,如何加密传输,困扰了我太久太久。。。主要因为自己的思路走进一个怪圈,导致进度一直卡着。。。

准备写用户密码加密这个部分的时候,我对加密没有任何了解,所以先百度了一波,看到各种让我头大的没见过的名词:什么对称加密,非对称加密,不可逆加密,DES,AES······,在后来,网上发帖求助,有位大佬说了OpenSSL,便没了音信。

感觉这是世外高人的赶脚,于是就去看百度,看了半天也没看懂多少,只得出一个结论:我要用对称加密算法,将用户密码加密后,发送到服务器,服务器再解密,将密码存储到数据库中。

直到后面学MySQL、有学了看哈希算法的总结博客时才发现,当时真的是傻了B了,如果用对称加密算法的话,密码存储还是明文暴露在网络中,服务器被黑了怎么办?万一服务器管理员偷看了密码怎么办?

我直接就用MD5加密,将密文存储在数据库中不就行了?而且现实中很多例子也是这样做的,比如打开Linux下的MySQL,去user下查看用户名密码,看到的也是一串加密后的密文。

这样在项目中,验证用户登录是否成功就去用户输入的密码对比数据库中的密文,来验证登录是否成功。

再次反思,之前走入了一个错误的思路,导致项目中的加密模块迟迟没有完成。。。

2.看似简单深似海,一头扎进无底洞。关于密码学,真的是一个可以挖的很深很深很深很深很深的部分,这可以独立出来作为一门学科。关于这次的学习总结,只是一个简单的记录,简单的了解一个框架,然后自己可以运用就OK啦。

----------------开始正文-----------------------------

一、OpenSSL是什么?

1.简介:

    OpenSSL(Open Secure Sockets Layer),开放式安全套阶层协议。简单的说,他就是一个强大的安全套接字密码库,Apache使用它加密HTTPS,OpenSSH使用它加密SSH,当然,它只不是一个开源库的软件包,它是一个多用途、跨平台的密码工具。

  OpenSSL利用c语言编写,跨平台性能好,支持Linux、Windows、BDS、Mac、VMS等平台。

2.基本功能:

    密码算法库、SSL协议、应用程序。还有一些小功能例如:随机数的生成与管理,BIO机制(一种高层IO接口,可以进行内存访问。文件访问以及socket等),口令生成密钥的API、证书签发等等......

3.关于密码算法:

   OpenSSL提供8种对称加密算法,其中7种是分组加密算法:AES、DES、Blowfish、CAST、IDEA...,一种流行加密算法:RC4。

  OpenSSL提供4种非对称加密算法:DH算法,RSA,DSA,EC算法。

  OpenSSL提供了5种信息摘要算法:MD2,MD5,MDC2,SHA,RIPEMD。

   这里,我们只了解MD5算法。它是不可逆的,不存在解密的过程。

二、MD5是什么?

1.简介:

    MD5(Message Digest Algorithm),信息摘要算法第五版,为计算机安全领域广泛使用的一种散列函数,用以提供消息的完整性保护。

2.MD5的应用:

  (1)一致性验证:

对一段信息(Message)产生信息摘要(Message-Digest),以防止被篡改。比如,在 Unix下有很多软件在下载的时候都有一个文件名相同,文件扩展名为.md5的文件,在这个文件中通常只有一行文本,大致结构如:

MD5 (tanajiya.tar.gz) = 38b8c2c1093dd0fec383a9d9ac940515

这就是tanajiya.tar.gz文件的数字签名。MD5将整个文件当作一个大文本信息,通过其不可逆的字符串变换算法,产生了这个唯一的MD5信息摘要。

  (2)数字签名:

MD5的典型应用是对一段Message(字节串)产生fingerprint( 指纹),以防止被“篡改”。举个例子,你将一段话写在一个叫 readme.txt文件中,并对这个readme.txt产生一个MD5的值并记录在案,然后你可以传播这个文件给别人,别人如果修改了文件中的任何内容,你对这个文件重新计算MD5时就会发现(两个MD5值不相同)。如果再有一个第三方的认证机构,用MD5还可以防止文件作者的“抵赖”,这就是所谓的数字签名应用。

  (3)安全访问认证:

MD5广泛用于操作系统的登陆认证上,如Unix、各类 BSD系统登录密码、 数字签名等诸多方面。如在Unix系统中用户的密码是以MD5(或其它类似的算法)经Hash运算后存储在文件系统中。当用户登录的时候,系统把用户输入的密码进行MD5 Hash运算,然后再去和保存在文件系统中的MD5值进行比较,进而确定输入的密码是否正确。通过这样的步骤,系统在并不知道用户密码的明码的情况下就可以确定用户登录系统的合法性。这可以避免用户的密码被具有系统管理员权限的用户知道。MD5将任意长度的“字节串”映射为一个128bit的大整数,并且是通过该128bit反推原始字符串是困难的,换句话说就是,即使你看到源程序和算法描述,也无法将一个MD5的值变换回原始的字符串,从数学原理上说,是因为原始的字符串有无穷多个,这有点象不存在反函数的数学函数。所以,要遇到了md5密码的问题,比较好的办法是:你可以用这个系统中的md5()函数重新设一个密码,如admin,把生成的一串密码的Hash值覆盖原来的Hash值就行了。

正是因为这个原因,现在被黑客使用最多的一种破译密码的方法就是一种被称为"跑字典"的方法。有两种方法得到字典,一种是日常搜集的用做密码的字符串表,另一种是用排列组合方法生成的,先用MD5程序计算出这些字典项的MD5值,然后再用目标的MD5值在这个字典中检索。我们假设密码的最大长度为8位字节(8 Bytes),同时密码只能是字母和数字,共26+26+10=62个字节,排列组合出的字典的项数则是P(62,1)+P(62,2)….+P(62,8),那也已经是一个很天文的数字了,存储这个字典就需要TB级的 磁盘阵列,而且这种方法还有一个前提,就是能获得目标账户的密码MD5值的情况下才可以。这种加密技术被广泛的应用于Unix系统中,这也是为什么Unix系统比一般操作系统更为坚固一个重要原因。

三、MD5如何应用于项目中?1.shell命令用法  2.库函数用法

上面介绍了MD5的3种应用场景,现在我在本机Linux虚拟机下实际运用测试一下。

1.检测单个文件的MD5值:

shell命令:md5sum filename 如图:

【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第1张图片

如图:client.c文件的MD5值为:画红线的一长串,这个MD5值是唯一的,如果将文件中的内容修改,文件的MD5值也会改变。

比如,我们在client.c中只修改一点点内容:如图,只在11行加了内容://md5

【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第2张图片

 保存后,再次查看文件MD5值:

【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第3张图片

 发现,虽然文件加了“//md5”这点内容,得到的MD5值差别却非常大。

这个MD5值得运用就是上例中的:一致性验证、数字签名。

比如运用在文件传输的项目中,检查两个文件是否相同,只需要检查文件的MD5值就可以,文件名可以不相同,如图:

【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第4张图片

 拷贝了一份client.c文件,两个文件名不同,但是文件的MD5值相同。

----------- 

我们man一下这个shell命令:man md5sum 

【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第5张图片

查看帮助文档,

-b, --binary        以二进制模式读入文件内容

-c, --check        从文件中读取MD5 的校验值并予以检查
      --tag            create a BSD-style 

-t, --text        以纯文本模式读取(默认)

--status     校验完成后,不生成错误或正确的提示信息,可以通过命令的返回值来判断。
Note: There is no difference between binary and text mode option on GNU system.
The following four options are useful only when verifying checksums:
      --quiet          don't print OK for each successfully verified file
      --status         don't output anything, status code shows success
      --strict         exit non-zero for improperly formatted checksum lines
  -w, --warn           warn about improperly formatted checksum lines

2.调用库函数,对字符串加密。

哦God,终于写到了开篇提到的问题:在项目中,将用户登录注册密码加密传输,保证安全性!

首先man MD5:查看帮助手册:有这么多个API

【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第6张图片

我们要用的API,需要的头文件 

【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第7张图片

 description(描述):MD5是密码的哈希函数,有128位输出。

-------------------------------------------------

想要分析头文件中的几个函数,就要知道:

MD5的大概原理:

参考链接1

参考链接2

参考链接3

参考链接4

MD5加密算法以512位分组来处理输入的信息,且每一分组又被划分为16个32位子分组,经过了一系列的处理后,算法的输出由四个32位分组组成,将这四个32位分组级联后将生成一个128位散列值。

在MD5加密算法中,首先需要对信息进行填充,使其字节长度对512求余数的结果等于448。因此,信息的字节长度(Bits Length)将被扩展至N*512+448,即N*64+56个字节(Bytes),N为一个正整数。

填充的方法如下,在信息的后面填充一个1和无数个0,直到满足上面的条件时才停止用0对信息的填充。然后再在这个结果后面附加一个以64位二进制表示的填充前的信息长度。经过这两步的处理,现在的信息字节长度=N*512+448+64=(N+1)*512,即长度恰好是512的整数倍数。这样做的原因是为满足后面处理中对信息长度的要求。

MD5中有四个32位被称作链接变量(Chaining Variable)的整数参数,他们分别为:

A=0x01234567

B=0x89abcdef

C=0xfedcba98

D=0x76543210

当设置好这四个链接变量后,就开始进入算法的四轮循环运算,循环的次数是信息中512位信息分组的数目。

将上面四个链接变量复制到另外四个变量中:A到a,B到b,C到c,D到d。 主循环有四轮(MD4只有三轮),每轮循环都很相似。第一轮进行16次操作。每次操作对a、b、c和d中的其中三个作一次非线性函数运算,然后将所得结果加上第四个变量(文本中的一个子分组和一个常数)。

再将所得结果向右环移一个不定的数,并加上a、b、c或d中之一。最后用该结果取代a、b、c或d中之一。 以一下是每次操作中用到的四个非线性函数(每轮一个)。

F(X,Y,Z)=(X∧Y)∨(( X)∧Z)
G(X,Y,Z)=(X∧Z)∨(Y∧( Z))
H(X,Y,Z)=X?Y?Z
I(X,Y,Z)=Y?(X∨( Z))

其中,?是异或,∧是与,∨是或, 是反符号。

如果X、Y和Z的对应位是独立和均匀的,那么结果的每一位也应是独立和均匀的。F是一个逐位运算的函数。即,如果X,那么Y,否则Z。函数H是逐位奇偶操作符。所有这些完成之后,将A,B,C,D分别加上a,b,c,d。然后用下一分组数据继续运行算法,最后的输出是A,B,C和D的级联。最后得到的A,B,C,D就是输出结果,A是低位,D为高位,DCBA组成128位输出结果。

3.分析代码,注释库函数作用:

#include   
#include   
#include 
#include   
#include   
#include   
#include   
#include   


using namespace std; // C++STL库

string MD5_Digest(const string cleartext)  
{  
    string strDigest;  // 密文
    unsigned char tmp[16] = {0};  //声明tmp[]


    MD5((const unsigned char*)cleartext.c_str(), cleartext.length(), tmp); 
//补位填充
//cleartext.c_str():c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同

    MD5_CTX c;  //MD5_CTX结构体指针
    MD5_Init(&c);  //初始化MD5_CTX
    MD5_Update(&c, cleartext.c_str(), cleartext.length());  //进行hash
    MD5_Final(tmp, &c);  //tmp是当前加密结果,放置结果


    char* tmp1 = new char[32 + 1];  //声明tmp1[]
    memset(tmp1, 0, 32 + 1);  

    for(int i = 0; i < 16; i++)   
        sprintf(&(tmp1[i*2]), "%02x", tmp[i]);  


    strDigest = (char*)tmp1;  //密文就是tmp1

    delete [] tmp1;  

    return strDigest;  //返回32位密文
}  


int main()
{

    string pw = "password";

    string md5_pw = MD5_Digest(pw);

    cout<<"pw="<【算法】OpenSSL库介绍,关于MD5加密的应用:shell命令以及库函数_第8张图片

这样,我们就运用openssl/md5.h库函数对一个string加密,得要密文,用于项目中登录注册的用户密码加密。

你可能感兴趣的:(数据结构和算法)