【问题标题】:Returning a hash as String rust [duplicate]将哈希返回为 String rust [重复]
【发布时间】:2021-06-28 11:41:24
【问题描述】:

我想将哈希函数的输出打印到标准输出。我使用 groestl 哈希函数,但我想它与 sha 或其他函数相同。这样做会按应有的方式打印散列:

fn create_hash<D: Digest>(msg: &str, mut hasher: D) -> GenericArray<u8, D::OutputSize> {
  hasher.update(msg);
  hasher.finalize()
}

fn main() {
  let hasher = Groestl256::default();
  let res = create_hash("asdfasdf", hasher);
  println!("{:x}", res);
}

输出:db102d374ae45b130ae49e91dcc7b648b86ba1a0415a32dcce7806d46f316460

现在我想做一个匹配以使其他算法(Groestl512,...)也可用。

    let dig = match algorithm {
        HashTypes::groestl224 => {
            create_hash(message.as_ref().unwrap(), Groestl224::default())
        }
        HashTypes::groestl256 => {
            create_hash(message.as_ref().unwrap(), Groestl256::default())
        }
        HashTypes::groestl384 => {
            create_hash(message.as_ref().unwrap(), Groestl384::default())
        }
        HashTypes::groestl512 => {
            create_hash(message.as_ref().unwrap(), Groestl512::default())
        }
    };
    let res = HashGroestl::create_hash("asdfasdf", Groestl256::default());
    
    println!("Result: {:x}", res);

由于返回数组的大小不同,这会导致匹配臂具有不兼容的类型。我试图通过返回一个字符串而不是 GenericArray 来绕过这个。

当我想用format!("{:x}", hasher.finalize())create_hash 返回一个字符串时,会出现以下错误:

cannot add `<D as groestl::Digest>::OutputSize` to `<D as groestl::Digest>::OutputSize`
the trait `std::ops::Add` is not implemented for `<D as groestl::Digest>::OutputSize`
required because of the requirements on the impl of `std::fmt::LowerHex` for `aes::cipher::generic_array::GenericArray<u8, <D as groestl::Digest>::OutputSize>`
required by `std::fmt::LowerHex::fmt`

我还尝试将数组转换为 Vec 或使用 .as_slice()。

那么我怎样才能像上面一样返回字符串或使匹配臂兼容?

编辑:好的,刚刚在Generic function to compute a hash (digest::Digest trait) and get back a String 中找到了以字符串形式返回的解决方案。 但是让火柴臂兼容的另一部分仍然让我感兴趣,所以如果有人对此有答案,欢迎您!

【问题讨论】:

    标签: hash rust cryptography


    【解决方案1】:

    当我想使用 format!("{:x}", hasher.finalize()) 从 create_hash 返回 String 时,会导致 [...] 错误

    问题是create_hash 是泛型的D,它只需要实现Digest。虽然您提供的Digest 的具体实现也满足format!("{:x}") 接受它们所需的LowerHex 特征,但create_hash 的签名并未反映这一点。

    要修复它,您应该对摘要的输出使用附加约束,如下所示:

    fn create_hash<D>(msg: &str, mut hasher: D) -> String
    where
        D: Digest,
        digest::Output<D>: std::fmt::LowerHex,
    {
        hasher.update(msg);
        format!("{:x}", hasher.finalize())
    }
    

    Playground

    为了使不同的匹配臂兼容,你必须引入间接和分配。上面的例子已经用String 做到了,所以你可以让你的匹配臂包括format!("{:x}", create_hash(...)),它们会自动兼容。但如果你不喜欢这样,你也可以让create_hash 返回Vec&lt;u8&gt;

    fn create_hash<D: Digest>(msg: &str, mut hasher: D) -> Vec<u8> {
        hasher.update(msg);
        hasher.finalize().as_slice().to_vec()
    }
    

    这将使匹配武器兼容,但{:x} 将不再有效。你也可以让create_hash()返回一个实现LowerHex的装箱对象:

    fn create_hash<D>(msg: &str, mut hasher: D) -> Box<dyn LowerHex>
    where
        D: Digest,
        digest::Output<D>: LowerHex,
    {
        hasher.update(msg);
        Box::new(hasher.finalize())
    }
    

    然后比赛的武器开始工作:

    fn main() {
        let res = if true {
            create_hash("asdfasdf", Sha256::default())
        } else {
            create_hash("asdfasdf", Sha512::default())
        };
        println!("{:x}", res.as_ref());
    }
    

    Playground

    【讨论】:

      【解决方案2】:

      问题是您匹配的每个变体都有不同的输出类型:

      let dig = match algorithm {
              HashTypes::groestl224 => {
                  create_hash(message.as_ref().unwrap(), Groestl224::default()) // type #1
              }
              HashTypes::groestl256 => {
                  create_hash(message.as_ref().unwrap(), Groestl256::default()) // type #2
              }
              // etc
          };
      

      所以你的 dig 变量不能有任何确切的类型。

      您应该以某种方式将每个匹配的类型转换为完全相同的类型。最简单的方法是使用:

      create_hash(message.as_ref().unwrap(), Groestl256::default())
         .to_slice()
         .to_owned()
      

      之后,您将拥有一个Vec&lt;u8&gt;,您可以拥有它并做您想做的事。但它使用分配。

      或者你可以使用动态调度:

      fn create_hash<D: Digest + 'static>(msg: &str, mut hasher: D) -> Box<dyn std::ops::Deref<Target = [u8]>> {
        hasher.update(msg);
        let digest = hasher.finalize();
        Box::new(digest)
      }
      

      最好、最复杂和最 Rust 的方式是定义一些 enum,它将根据给定的摘要选择它的变体。

      【讨论】:

        猜你喜欢
        • 2015-01-19
        • 2019-05-23
        • 1970-01-01
        • 2015-09-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多