R语言创建哈希摘要digest

R的极客理想系列文章,涵盖了R的思想,使用,工具,创新等的一系列要点,以我个人的学习和体验去诠释R的强大。

R语言作为统计学一门语言,一直在小众领域闪耀着光芒。直到大数据的爆发,R语言变成了一门炙手可热的数据分析的利器。随着越来越多的工程背景的人的加入,R语言的社区在迅速扩大成长。现在已不仅仅是统计领域,教育,银行,电商,互联网….都在使用R语言。

要成为有理想的极客,我们不能停留在语法上,要掌握牢固的数学,概率,统计知识,同时还要有创新精神,把R语言发挥到各个领域。让我们一起动起来吧,开始R的极客理想。

关于作者:

  • 张丹,分析师/程序员/Quant: R,Java,Nodejs
  • blog: http://blog.fens.me
  • email: bsspirit@gmail.com

转载请注明出处:
http://blog.fens.me/r-crypto-hash-digest/

前言

哈希算法,被用于对任意一组输入数据进行计算,得到一个固定长度的输出摘要,为了验证原始数据是否被篡改。哈希算法如md5,sha1,sha2等算法普遍被应用于各种数据传输和数据交互的场景。

digest包,提供了R语言在哈希计算上的能力,好用,方便,高效。

目录

  1. digest包介绍
  2. md5哈希摘要
  3. sha1哈希摘要
  4. sha256哈希摘要
  5. 其他算法哈希摘要
  6. 场景1:基于哈希的消息身份验证码hmac
  7. 场景2:文件验证checksum

1. digest包介绍

在digest包,包括了多种的hash加密算法的计算函数,包括了md5, sha1, crc32, sha256, sha512, xxhash32, xxhash64, murmur32, spookyhash, blake3,我们可以通过digest()函数直接调用。

安装digest非常简单,digest包没有底层依赖,一条命令就搞定了。


# 安装digest
> install.pacakges(digest)

# 加载digest
> library(digest)

# 初始化的字符值
> value<-"abc=!@#$%^&*()_+abc试试中文"

2. md5哈希摘要

MD5信息摘要算法(英语:MD5 Message-Digest Algorithm),一种被广泛使用的密码散列函数,可以产生出一个128位(16字节)的散列值(hash value),用于确保信息传输完整一致。MD5由MD4、MD3、MD2改进而来,主要增强算法复杂度和不可逆性。MD5算法因其普遍、稳定、快速的特点,仍广泛应用于普通数据的加密保护领域。

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

直接使用digest函数,计算md5。我们可以考虑是否需要先对原数据做序列化(serialize),默认是支持序列化的。关于序列化介绍见文章,请参见 R语言中的编码和解码


# 带序列化
> d1<-digest(value, algo="md5", serialize=TRUE);d1
[1] "ac4dea3cc2f21f37a5d9f89fd911e9c2"

# 不带序列化
> d2<-digest(value, algo="md5", serialize=FALSE);d2
[1] "2979b0983cb7e1031fb149d4da902a99"

另化一种写法,如果我想单独获得一个md5函数,可以获取算法函数的句柄。


# 定义md5()函数
> md5<-getVDigest()

# 用自定义函数进行计算
> md5(value)
[1] "ac4dea3cc2f21f37a5d9f89fd911e9c2"

3. sha1哈希摘要

SHA-1(英语:Secure Hash Algorithm 1,中文名:安全散列算法1)是一种密码散列函数,美国国家安全局设计。SHA-1可以生成一个被称为消息摘要的160位(20字节)散列值,散列值通常的呈现形式为40个十六进制数。

安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。当接收到消息的时候,这个消息摘要可以用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的消息摘要。

SHA1特性支持,不可以从消息摘要中复原信息,两个不同的消息不会产生同样的消息摘要。

 
# 计算sha1
> digest(value, algo="sha1")
[1] "a6a04474e0f670b78b18c9cbaff3c7296befb172"

# 同digest
> sha1_digest(value)
[1] "a6a04474e0f670b78b18c9cbaff3c7296befb172"

另化一种写法,如果我想单独获得一个mysha1的函数,可以获取算法函数的句柄。


# 用自定义函数进行计算
> mysha1<-getVDigest("sha1")
> mysha1(value)
[1] "a6a04474e0f670b78b18c9cbaff3c7296befb172"

为老版本遗留的函数sha1.xxx()一组函数,sha1.xxx()函数用于支持digest包的0.6.14之前的版本,我当前使用为0.6.29版本,所以计算结果是不同。


> sha1(value,algo = "sha1") # digest <= 0.6.14
[1] "b62567b5a0dc60103ff91f31ec08980e0f53e695"

4. sha256哈希摘要

SHA-2,名称来自于安全散列算法2(英语:Secure Hash Algorithm 2)的缩写,一种密码散列函数算法标准,由美国国家安全局研发,由美国国家标准与技术研究院(NIST)在2001年发布。属于SHA算法之一,是SHA-1的后继者。其下又可再分为六个不同的算法标准,包括了:SHA-224、SHA-256、SHA-384、SHA-512、SHA-512/224、SHA-512/256。

对于任意长度的消息,SHA256都会产生一个256位的哈希值,称作消息摘要。这个摘要相当于是个长度为32个字节的数组,通常有一个长度为64的十六进制字符串来表示,其中1个字节=8位,一个十六进制的字符的长度为4位。

SHA256的压缩函数主要对512位的消息区块和256位的中间哈希值进行操作,本质上,它是一个通过将消息区块为密钥对中间哈希值进行加密的256位加密算法。


# sha256
> digest(value, algo="sha256")
[1] "4135d8f5fa9027f05a6b927ccc1501d73f9f30189830886f3d287a0606cc2e2b"

一个惊艳的sha256的计算动画,https://sha256algorithm.com/。最上为字符串输入,最下面为sha256的输出,中间为计算过程。

5. 其他算法哈希摘要

digest支持的其他的哈希算法,由于我也不太清晰,就不具体解释了,附上R语言的调用代码,大家随用随取。(偷懒一下)


# sha512
> digest(value, algo="sha512")
[1] "32f736716db2ae7d93b8df2f21e50d3f9bbf94f07c77ea829ab001f97a74f4d25d086d1c7a1e9e9c577c9e5765c7f5ce9c4a3c3010d83551922e1c6c9641922c"

# crc32
> digest(value, algo="crc32")
[1] "5da20b48"

# xxhash32
> digest(value, algo="xxhash32")
[1] "8104f39e"

# xxhash64
> digest(value, algo="xxhash64")
[1] "9a1c77be269ddf8d"

# murmur32
> digest(value, algo="murmur32")
[1] "9ea85aec"

# spookyhash
> digest(value, algo="spookyhash")
[1] "1bd5a355dde8fbbd4af6948d84ddab36"

# blake3
> digest(value, algo="blake3")
[1] "be8b5792da47d27c039325430fab72eb160b7887b7b34a0f9e01d7eb6030e52e"

6. 场景1:基于哈希的消息身份验证码

HMAC是密钥相关的哈希运算消息认证码(Hash-based Message Authentication Code)的缩写,为了确保接收方所接收到的报文数据的完整性,人们采用消息认证来验证。

HMAC运算利用hash算法,以一个消息M和一个密钥K作为输入,生成一个定长的消息摘要作为输出。HMAC算法更象是一种加密算法,它引入了密钥,其安全性已经不完全依赖于所使用的Hash算法,安全性主要有以下几点保证。
(1)使用的密钥是双方事先约定的,第三方不可能知道。作为非法截获信息的第三方,能够得到的信息只有作为“挑战”的随机数和作为“响应”的HMAC 结果,无法根据这两个数据推算出密钥。由于不知道密钥,所以无法仿造出一致的响应。
(2)HMAC与一般的加密重要的区别在于它具有“瞬时”性,即认证只在当时有效,而加密算法被破解后,以前的加密结果就可能被解密。

使用hmac函数进行实现,第一参数key,第二个参数为消息数据Object。


# 使用md5散列
> hmac('fens.me', value, "md5")
[1] "fe969197e99e311c8cf0c08418c25861"

# 使用sha1散列
> hmac('fens.me', value, "sha1")
[1] "acc2c9dae75272b5fa301020697f06ff8a7588c0"

7. 场景2:文件验证checksum

通过md5用来生成文件摘要,来验证文件是否是原始文件,防止文件在传输过程中被恶意篡改,是一个典型的应用场景。

我们下载软件的时候,下载的网页上会提示checksum码,用于告知这个软件的哈希摘要是什么,由于算法不可逆所以一个程序包只能匹配唯一码,类似于防伪验证码。我们把软件下载后可以比对这个验证码,当不一样时可能是软件包被改动过,加了病毒或者木马等恶意程序,特别在第三方下载站下载软件时,验证真实性就显得尤为重要。

以GO语言的下载举例:https://golang.google.cn/dl/ 。go语言软件包,提供了对应的摘要,是用的sha256来生成的哈希摘要。

在我们下载R的依赖的包时,安装过程会对每个文件做checksum检验,里面会包括一个文件名为MD5的文件,这个文件记录当前包的所有文件的md5值。我们可以使用tools包的md5sum()和checkMD5sums()函数进行检查。

以我本地安装的digest包为例。


# 加载tools包
> library(tools)

# 获得本地安装包的路径
> path<-paste0(.libPaths()[1],"/digest");path
[1] "C:/Users/bsspi/Documents/R/win-library/4.0/digest"

# 打印路径下载的文件
> dir(path)
 [1] "demo"        "DESCRIPTION" "doc"         "GPL-2"       "help"        "html"        "include"     "INDEX"      
 [9] "libs"        "MD5"         "Meta"        "NAMESPACE"   "R"           "tinytest"   

# 找到MD5文件
> file_md5<-paste0(path,"/MD5")

# 查看文件内容
> file_md5<-paste0(path,"/MD5");file_md5
[1] "C:/Users/bsspi/Documents/R/win-library/4.0/digest/MD5"
> readLines(file_md5)
 [1] "4f4d87b5b82aae40bdca115168d2f489 *DESCRIPTION"                         
 [2] "b234ee4d69f5fce4486a80fdaf4a4263 *GPL-2"                               
 [3] "d3b2d6e126889679a20971bb40faf95b *INDEX"                               
 [4] "1ef110b7a4e87edf0d4ce7e884e25c1c *Meta/Rd.rds"                         
 [5] "d90f7534e5fee11d3afe7aea19da26eb *Meta/demo.rds"                       
 [6] "4d1492de7968466564e971368d24d147 *Meta/features.rds"                   
 [7] "5023c75285b93023b6ff55d53314dd43 *Meta/hsearch.rds"                    
 [8] "4999aeefa92e6fdefc0b1648ec4dc7a0 *Meta/links.rds"                      
 [9] "d7db2c4bb971cec5af4d6357a6d3b75b *Meta/nsInfo.rds"                     
[10] "ad9806ce7b382276603401f495b1b33d *Meta/package.rds"                    
[11] "44e7d30ab5a91d849e5fee71c6e03370 *Meta/vignette.rds"                   
[12] "14402ee218da75987f233d61fa84ab8d *NAMESPACE"                           
[13] "d6c68f1fe41ced6e98a766a3757313da *R/digest"                            
[14] "55c37b8148f9e69a8b76329fe3cf5ba0 *R/digest.rdb"                        
[15] "a9352f140fdd099efdb9d2cc1633064b *R/digest.rdx"                        
[16] "247a7f1a523cb39feb2941b00b82906a *demo/vectorised.R"                   
[17] "99f7ecc6dd6613e9ff2e27341242366e *doc/index.html"                      
[18] "0473d4bde070176922b60166512ee4e7 *doc/sha1.R"                          
[19] "2bafc9dc174d4c0c7a4f997c4e38ab22 *doc/sha1.html"                       
[20] "6b37c59ba0b533a23e48589c49be6851 *doc/sha1.md"                         
[21] "c7a5267ecd60c94cac5e63ffbfcf7c85 *help/AnIndex"                        
[22] "9206818c55699be0e654cb71d8846766 *help/aliases.rds"                    
[23] "b62adb06d160285a19664895c2a49732 *help/digest.rdb"                     
[24] "76643649e20b6e2733b143b479773dce *help/digest.rdx"                     
[25] "d636efb2f2b15c9b8904502c3ab1db6b *help/paths.rds"                      
[26] "7a3b8c4700297a80815dd58b11fe1102 *html/00Index.html"                   
[27] "b6763e6916890c631fdc3f2643803b1a *html/R.css"                          
[28] "82a62fb6337a2be9ae069fee3d50b614 *include/pmurhashAPI.h"               
[29] "9978920e2d0e2ee72edeb5b5c08a647c *libs/i386/digest.dll"                
[30] "8c56528c9759b547c278fed635eb3d96 *libs/i386/symbols.rds"               
[31] "38981a746981dc9ed975e55b0e9e57d4 *libs/x64/digest.dll"                 
[32] "431ee5ad2c9f14b5725275ba7e0b8eab *libs/x64/symbols.rds"                
[33] "4d75623e0ffe3c04eac1752b7d3d8f6b *tinytest/test_aes.R"                 
[34] "f930ce5c1f9bbcd3b6fe97fd7b5b27f8 *tinytest/test_blake3.R"              
[35] "052184be0e884920438e1779a03f8759 *tinytest/test_crc32.R"               
[36] "8ec7f892f2bcb4b146f78078f987237b *tinytest/test_digest.R"              
[37] "6681e580fd409258ed4fbdeb77a14cd4 *tinytest/test_digest2int.R"          
[38] "8e8415ddde36eb03eae83e0ae0e5bb0c *tinytest/test_encoding.R"            
[39] "2b3efdc9712ac7f956f79a80da4d0d00 *tinytest/test_hmac.R"                
[40] "557fbd734cbf96e7946b9dca3eaa9afe *tinytest/test_misc.R"                
[41] "40f6e8975785e79091b3a9dffd430e2b *tinytest/test_new_matrix_behaviour.R"
[42] "1d71bffa7dc302062c44ed92b57bdbcc *tinytest/test_num2hex.R"             
[43] "612e0a4832b86b69c8c04f2916f3b16a *tinytest/test_raw.R"                 
[44] "6e3548a6e9bdf2681f6bdc173ee0a8d2 *tinytest/test_sha1.R"  

手动验证DESCRIPTION文件md5摘要,与MD5文件中的摘要是一致的。

 
# 计算文件 DESCRIPTION 
> md5sum(paste0(path,"/DESCRIPTION"))
C:/Users/bsspi/Documents/R/win-library/4.0/digest/DESCRIPTION 
                           "4f4d87b5b82aae40bdca115168d2f489" 

# 对整个digest包的每个文件进行md5摘要验证
> checkMD5sums("digest",path)
[1] TRUE

digest能够支持我们常用的,多种哈希散列算法,真的是非常方便。最后留一个小尾巴,关于digest包的AES加密算法,我会在后面一篇加密算法的文章中进行介绍。

本文代码已上传到github: https://github.com/bsspirit/encrypt/blob/master/digest.r

转载请注明出处:
http://blog.fens.me/r-crypto-hash-digest/

打赏作者

This entry was posted in R语言实践

0 0 votes
Article Rating
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

[…] 我们可以使用digest包的AES函数,进行AES的加密和解密操作,digest包的详细介绍,请参考文章R语言创建哈希摘要digest […]

1
0
Would love your thoughts, please comment.x
()
x