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(())
}
  • 运行cargo run输出结果如下:
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(())
}
  • 运行cargo run验证.

2. 加密

2.1 使用 PBKDF2 对密码进行加密(salt)和散列(hash)运算

  对于通过 PBKDF2 密钥派生函数 pbkdf2::derive 生成的加密(加盐算法)密码,使用 ring::pbkdf2 进行散列(哈希)运算,使用 pbkdf2::verify 验证散列(哈希)运算是否正确。salt 值是使用 SecureRandom::fill 生成的,salt 字节数组被其安全生成的随机数填充。

// 导入需要用到的库
use data_encoding::HEXUPPER; // HEXUPPER 数据编码库
use ring::error::Unspecified; // Ring 库中的错误类型 Unspecified
use ring::rand::SecureRandom; // 一个安全的随机数生成器
use ring::{digest, pbkdf2, rand}; // Ring 库中的摘要、PBKDF2 和随机数模块
use std::num::NonZeroU32; // 非零的 u32 类型

fn main() -> Result<(), Unspecified> {
// 定义常量 CREDENTIAL_LEN,并赋值为 SHA512 输出的长度
const CREDENTIAL_LEN: usize = digest::SHA512_OUTPUT_LEN;
// 定义 NonZeroU32 类型变量 n_iter,赋值为 100000
let n_iter = NonZeroU32::new(100_000).unwrap();
// 创建系统随机数生成器 rng
let rng = rand::SystemRandom::new();
// 定义长度为 CREDENTIAL_LEN 的数组 salt,并用随机数生成器 rng 填充
let mut salt = [0u8; CREDENTIAL_LEN];
rng.fill(&mut salt)?;

// 定义字符串变量 password,并赋值为 "Guess Me If You Can!"
let password = "Guess Me If You Can!";
// 定义长度为 CREDENTIAL_LEN 的数组 pbkdf2_hash,并使用 PBKDF2 算法和 salt 以及 password 的字节数组填充该数组
let mut pbkdf2_hash = [0u8; CREDENTIAL_LEN];
pbkdf2::derive(
pbkdf2::PBKDF2_HMAC_SHA512, // 使用 HMAC-SHA512 算法
n_iter,
&salt,
password.as_bytes(),
&mut pbkdf2_hash,
);
// 打印 salt 和 pbkdf2_hash 的十六进制编码
println!("Salt: {}", HEXUPPER.encode(&salt));
println!("PBKDF2 hash: {}", HEXUPPER.encode(&pbkdf2_hash));

// 使用 PBKDF2 算法、salt 和 password 的字节数组验证 pbkdf2_hash 是否正确
let should_succeed = pbkdf2::verify(
pbkdf2::PBKDF2_HMAC_SHA512, // 使用 HMAC-SHA512 算法
n_iter,
&salt,
password.as_bytes(),
&pbkdf2_hash,
);
// 定义字符串变量 wrong_password,并赋值为 "Definitely not the correct password"
let wrong_password = "Definitely not the correct password";
// 使用 PBKDF2 算法、salt 和 wrong_password 的字节数组验证 pbkdf2_hash 是否正确
let should_fail = pbkdf2::verify(
pbkdf2::PBKDF2_HMAC_SHA512, // 使用 HMAC-SHA512 算法
n_iter,
&salt,
wrong_password.as_bytes(),
&pbkdf2_hash,
);

// 使用 assert! 宏判断 should_succeed 是否成功
assert!(should_succeed.is_ok());
// 使用 assert! 宏判断 should_fail 是否失败
assert!(!should_fail.is_ok());
// 如果程序没有发生错误
Ok(())
}
  • 运行cargo run输出结果如下,没有报错,说明验证成功:
Salt: CDC7242F11C2AEF4F5091F88CDD63C2D07871ACA0B13A8E9AB458DFF9F2BC7B441F5F250A9C81FB4E006286E08504F0AD7698AF8EC8F03D58AB99706051D1BAE
PBKDF2 hash: 6F547321949A89DA4A91BAD3FB1E5ACE48D0CAA57453221A82BD6CA4EA0E840FEFF2756070CB81978EBC9AFAB6017B050BF8A1D4909888470BCFA31494FBEE30