哈希算法(单向散列值)
文章目录
- 哈希的特点
- 常用哈希算法
- Md4、Md5
- SHA-1、SHA-256、SHA-384、SHA-512
- MD5相关函数和测试
- 使用的头文件
- SHA1相关函数和测试
- 哈希函数的应用
- 检测软件是否被篡改
- 消息认证码
- 数字签名
- 伪随机数生成器
- 一次性口令或登录验证
单向散列函数(one-wayftnction)有一个输人和一个输出,其中输人称为消息(message),输出称为散列值(hashvalue)。单向散列函数可以根据消息的内容计算出散列值,而散列值就可以被用来检查消息的完整性。
- 单向散列函数也称为消息摘要函数(message digest function)、哈希函数或者杂凑函数。
- 单向散列函数输出的散列值也称为消息摘要(message digest)或者指纹(fingerprint)。
- 完整性也称为一致性。
哈希的特点
-
压缩性
无论原始数据有多大,生成的散列值的长度一致。 -
强抗碰撞性
原始数据发送细微的变化,散列值变化巨大。 -
抗碰撞性
相同原始数据的散列值一致,不同原始数据的散列值不同。
应用:校验数据是否被篡改。密钥的存储校验。秒传。 -
单向性(不可逆)
不能使用单向散列函数,做加密、解码。
常用哈希算法
Md4、Md5
MD4是由Rivest于1990年设计的单向散列函数,能够产生128比特的散列值(RFC1186,修订版RFC1320)。不过,随着Dobbertin提出寻找MD4散列碰撞的方法,因此现在它已经不安全了。
MD5是由Rwest于1991年设计的单向散列函数,能够产生128比特的散列值(RFC1321)。
MD5的强抗碰撞性已经被攻破,也就是说,现在已经能够产生具备相同散列值的两条不同的消息,因此它也已经不安全了。
MD4和MD5中的MD是消息摘要(Message Digest)的缩写。
SHA-1、SHA-256、SHA-384、SHA-512
SHA-1是由NIST(National Institute Of Standardsand Technology,美国国家标准技术研究所)设计的一种能够产生160比特的散列值的单向散列函数。1993年被作为美国联邦信息处理标准规格(FIPS PUB 180)发布的是SHA,1995年发布的修订版FIPS PUB 180-1称为SHA-1。
SHA-1的消息长度存在上限,但这个值接近于264比特,是个非常巨大的数值,因此在实际应用中没有问题。
SHA-256、SHA-384和SHA-512都是由NIST设计的单向散列函数,它们的散列值长度分别为256比特、384比特和512比特。这些单向散列函数合起来统称SHA-2,它们的消息长度也存在上限(SHA-256的上限接近于 264 比特,SHA-384 和 SHA-512的上限接近于 2128 比特)。这些单向散列函数是于2002年和 SHA-1 一起作为 FIPS PUB 180-2发布的 SHA-1 的强抗碰撞性已于2005年被攻破, 也就是说,现在已经能够产生具备相同散列值的两条不同的消息。不过,SHA-2还尚未被攻破。
| 哈希函数 | 散列值长度(bit) | 散列值长度(byte) |
|---|---|---|
| Md4/Md5 | 128bit | 16byte |
| SHA-1 | 160bit | 20byte |
| SHA-256 | 256bit | 32byte |
| SHA-384 | 384bit | 48byte |
| SHA-512 | 512bit | 64byte |
| SHA-224 | 224bit | 28byte |
上述散列值长度为二进制数据长度。通常散列值采用 16 进制格式的数字串进行表示,因此看到的字符串长度是原来的2倍长.
MD5相关函数和测试
使用的头文件
#include
#include
// 相关操作函数 —— openssl中返回int: 成功:1(true)失败:0(false)// 定义md5 使用的 结构体
MD5_CTX c;// 初始化 md5 使用的结构体。
int MD5_Init(MD5_CTX *c);MD5_Init(&c);// 向md5中添加待生成散列值的原始数据。—— 可以反复调用 update ,反复添加数据。
int MD5_Update(MD5_CTX *c, const void *data, size_t len);参1:&c参2:待进行散列运算的元素数据。 —— 可以重复添加。参3:data的长度。// 生成 md5 散列值
int MD5_Final(unsigned char *md, MD5_CTX *c);参1:传出参数。散列值数据。参2:&c// 只能一次性添加待散列的数据。生成md5散列值
unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md);参1:待运算的原始数据参2:d的长度。参3:传出参数。生成的散列值。返回值:生成的散列值。
示例
#include
#include
#include
#include
//MD5算法
int main()
{int ret = -1;int i = 0;char *data = "hello";//保存MD5散列值char md[MD5_DIGEST_LENGTH + 1];MD5_CTX c;//1. 初始化ret = MD5_Init(&c);//2. 添加数据ret = MD5_Update(&c, data, strlen(data));//3. 计算结果memset(md, 0, MD5_DIGEST_LENGTH + 1);ret = MD5_Final(md, &c);//printf("MD5: %s\n", md);for (i = 0; i < MD5_DIGEST_LENGTH; i++){printf("%02x", (unsigned char)md[i]);}putchar('\n');
printf("==============================\n");//生成MD5散列值memset(md, 0, MD5_DIGEST_LENGTH + 1);MD5(data, strlen(data), md);for (i = 0; i < MD5_DIGEST_LENGTH; i++){printf("%02x", (unsigned char)md[i]);}putchar('\n');
return 0;
}
SHA1相关函数和测试
typedef struct SHAstate_st {SHA_LONG h0, h1, h2, h3, h4;SHA_LONG Nl, Nh;SHA_LONG data[SHA_LBLOCK];unsigned int num;
} SHA_CTX;
int SHA1_Init(SHA_CTX *c);
int SHA1_Update(SHA_CTX *c, const void *data, size_t len);
int SHA1_Final(unsigned char *md, SHA_CTX *c);
unsigned char *SHA1(const unsigned char *d, size_t n, unsigned char *md);
void SHA1_Transform(SHA_CTX *c, const unsigned char *data);
示例
#include
#include
#include
#include
int main()
{int ret = -1;int i = 0;
SHA_CTX ctx;
char *data = "hello";
unsigned char md[SHA_DIGEST_LENGTH + 1];
//1. 初始化ret = SHA1_Init(&ctx);if (1 != ret){printf("SHA1_Init failed...\n");return 1;}
//2. 添加数据ret = SHA1_Update(&ctx, data, strlen(data));if (1 != ret){printf("SHA1_Update failed...\n");return 1;}
//3. 计算结果memset(md, 0, SHA_DIGEST_LENGTH + 1);ret = SHA1_Final(md, &ctx);if (1 != ret){printf("SHA1_Final failed...\n");return 1;}
for (i = 0; i < SHA_DIGEST_LENGTH; i++){printf("%02x", (unsigned char)md[i]);}putchar('\n');
printf("==================================\n");
//计算散列值memset(md, 0, SHA_DIGEST_LENGTH + 1);SHA1(data, strlen(data), md);
for (i = 0; i < SHA_DIGEST_LENGTH; i++){printf("%02x", (unsigned char)md[i]);}putchar('\n');return 0;
}
哈希函数的应用
检测软件是否被篡改
我们可以使用单向散列函数来确认自己下载的软件是否被篡改。
很多软件,尤其是安全相关的软件都会把通过单向散列函数计算出的散列值公布在自己的官方网站上。用户在下载到软件之后,可以自行计算散列值,然后与官方网站上公布的散列值进行对比。通过散列值,用户可以确认自己所下载到的文件与软件作者所提供的文件是否一致。
这样的方法,在可以通过多种途径得到软件的情况下非常有用。为了减轻服务器的压力,很多软件作者都会借助多个网站(镜像站点)来发布软件,在这种情况下,单向散列函数就会在检测软件是否被篡改方面发挥重要作用。

消息认证码
使用单向散列函数可以构造消息认证码。
消息认证码是将“发送者和接收者之间的共享密钥”和“消息,进行混合后计算出的散列值。使用消息认证码可以检测并防止通信过程中的错误、篡改以及伪装。
数字签名
在进行数字签名时也会使用单向散列函数。
数字签名是现实社会中的签名(sign)和盖章这样的行为在数字世界中的实现。数字签名的处理过程非常耗时,因此一般不会对整个消息内容直接施加数字签名,而是先通过单向散列函数计算出消息的散列值,然后再对这个散列值施加数字签名。
伪随机数生成器
使用单向散列函数可以构造伪随机数生成器。
密码技术中所使用的随机数需要具备“事实上不可能根据过去的随机数列预测未来的随机数列”这样的性质。为了保证不可预测性,可以利用单向散列函数的单向性。
一次性口令或登录验证
使用单向散列函数可以构造一次性口令(one-time password)。
一次性口令经常被用于服务器对客户端的合法性认证。在这种方式中,通过使用单向散列函数可以保证口令只在通信链路上传送一次(one-time),因此即使窃听者窃取了口令,也无法使用。
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
