1. 散列(哈希)
1.1 计算文件的 SHA-256 摘要
需要安装ring
,data-encoding
,error-chain
库,可通过cargo add ring
,cargo add data-encoding
,cargo add error-chain
命令安装
[dependencies] data-encoding = "2.3.3" error-chain = "0.12.4" ring = "0.16.20"
以下实例中,先创建文件,写入一些数据。然后使用 digest::Context
计算文件内容的 SHA-256
摘要 digest::Digest
。
use data_encoding::HEXUPPER;use error_chain::error_chain;use ring::digest::{Context, Digest, SHA256};use std::fs::File;use std::io::{BufReader, Read, Write};error_chain! { foreign_links { Io (std::io::Error); Decode (data_encoding::DecodeError); } } fn sha256_digest <R: Read>(mut reader: R) -> Result <Digest> { let mut context = Context::new (&SHA256); let mut buffer = [0 ; 1024 ]; loop { let count = reader.read (&mut buffer)?; if count == 0 { break ; } context.update (&buffer[..count]); } Ok (context.finish ()) } fn main () -> Result <()> { let path = "file.txt" ; let mut output = File::create (path)?; write! (output, "我们将生成此文本的摘要" )?; let input = File::open (path)?; let reader = BufReader::new (input); let digest = sha256_digest (reader)?; println! ("SHA-256 摘要是 {}" , HEXUPPER.encode (digest.as_ref ())); Ok (()) }
SHA-256 摘要是 765E79C9E2677BCA5A050906AF635703BAC1A725EC63701285A907A263182EC2
1.2. 使用 HMAC 摘要对消息进行签名和验证
使用 ring::hmac
创建字符串的签名 hmac::Signature
,然后验证签名是否正确。HMAC运算利用hash算法,以一个消息M和一个密钥K作为输入,生成一个定长的消息摘要作为输出。
use ring::error::Unspecified;use ring::rand::SecureRandom;use ring::{hmac, rand};fn main () -> Result <(), Unspecified> { let mut key_value = [0u8 ; 48 ]; let rng = rand::SystemRandom::new (); rng.fill (&mut key_value)?; let key = hmac::Key::new (hmac::HMAC_SHA256, &key_value); let message = "合法而非常重要的信息。" ; let signature = hmac::sign (&key, message.as_bytes ()); hmac::verify (&key, message.as_bytes (), signature.as_ref ())?; Ok (()) }
2. 加密
2.1 使用 PBKDF2
对密码进行加密(salt
)和散列(hash
)运算
对于通过 PBKDF2
密钥派生函数 pbkdf2::derive
生成的加密(加盐算法)密码,使用 ring::pbkdf2
进行散列(哈希)运算,使用 pbkdf2::verify
验证散列(哈希)运算是否正确。salt
值是使用 SecureRandom::fill
生成的,salt
字节数组被其安全生成的随机数填充。
use data_encoding::HEXUPPER; use ring::error::Unspecified; use ring::rand::SecureRandom; use ring::{digest, pbkdf2, rand}; use std::num::NonZeroU32; fn main () -> Result <(), Unspecified> { const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN; let n_iter = NonZeroU32::new (100_000 ).unwrap (); let rng = rand::SystemRandom::new (); let mut salt = [0u8 ; CREDENTIAL_LEN]; rng.fill (&mut salt)?; let password = "Guess Me If You Can!" ; let mut pbkdf2_hash = [0u8 ; CREDENTIAL_LEN]; pbkdf2::derive ( pbkdf2::PBKDF2_HMAC_SHA512, n_iter, &salt, password.as_bytes (), &mut pbkdf2_hash, ); println! ("Salt: {}" , HEXUPPER.encode (&salt)); println! ("PBKDF2 hash: {}" , HEXUPPER.encode (&pbkdf2_hash)); let should_succeed = pbkdf2::verify ( pbkdf2::PBKDF2_HMAC_SHA512, n_iter, &salt, password.as_bytes (), &pbkdf2_hash, ); let wrong_password = "Definitely not the correct password" ; let should_fail = pbkdf2::verify ( pbkdf2::PBKDF2_HMAC_SHA512, n_iter, &salt, wrong_password.as_bytes (), &pbkdf2_hash, ); assert! (should_succeed.is_ok ()); assert! (!should_fail.is_ok ()); Ok (()) }
运行cargo run
输出结果如下,没有报错,说明验证成功:
Salt: CDC7242F11C2AEF4F5091F88CDD63C2D07871ACA0B13A8E9AB458DFF9F2BC7B441F5F250A9C81FB4E006286E08504F0AD7698AF8EC8F03D58AB99706051D1BAE PBKDF2 hash : 6F547321949A89DA4A91BAD3FB1E5ACE48D0CAA57453221A82BD6CA4EA0E840FEFF2756070CB81978EBC9AFAB6017B050BF8A1D4909888470BCFA31494FBEE30