Giter VIP home page Giter VIP logo

Comments (9)

newpavlov avatar newpavlov commented on May 29, 2024 1

Thank you for kind words!

Crates in this repository do not provide any way to serialize/desirialize internal state of a hash function out of the box and I don't think that we'll add such functionality without compelling justification.

Though there is unsafe method which can work for you, it utilizes transmute to convert hasher to u8 array:

const SHA256_SIZE: usize = std::mem::size_of::<Sha256>();

// client 1
let mut hasher = Sha256::new();
hasher.input(b"hello");
let raw_state: [u8; SHA256_SIZE] = unsafe { std::mem::transmute(hasher) };
send(raw_state);

// client 2
let raw_state: [u8; SHA256_SIZE] = recv();
let mut hasher: Sha256 = unsafe { std::mem::transmute(raw_state) };
hasher.input(b"world");

But this approach is quite fragile, not only due to the potential breakage, but also because it does not check raw_state at all. I recommend to check other approaches which could solve your problem, e.g. Merkle tree.

from hashes.

newpavlov avatar newpavlov commented on May 29, 2024 1

Sha256 has three fields:

  • len: u64: all bit patterns are valid, it is used only for padding, so we are good
  • state: [u32; 8]: again all bit patterns are valid, so we are good.
  • buffer: BlockBuffer512: most fragile part, it contains 512 bit buffer and cursor pos which is assumed always less than buffer length in bytes. Luckily block-buffer crate does not use any unsafe code, so it should panic immediately in case of the incorrect pos.

UPD: Also note that buffer will contain parts of the secret message, so private input will be partially leaked.

from hashes.

newpavlov avatar newpavlov commented on May 29, 2024 1

Hint is here: "note: source type: &[u8; 104] (64 bits)" In other words you are passing to transmute not an array, but a pointer to it. You either will have to change function signature to use raw_state: [u8; RIPEMD160_SIZE] or use transmute_copy:

let mut hasher: Ripemd160 = unsafe { std::mem::transmute_copy(raw_state) };

from hashes.

tarcieri avatar tarcieri commented on May 29, 2024 1

@bitjson I'd strongly recommend against this approach. The same problem is easily solved without access to internal statue using a tree hash, such as a Merkle Tree which @newpavlov mentioned.

from hashes.

bitjson avatar bitjson commented on May 29, 2024

That's exactly what I was looking for, thank you! (And thanks for the quick response.)

And yes, I agree a Merkle tree would be a better solution for a real security use-case. I'm actually interested in this function specifically because I'd like to provide a purely-functional interface from the WebAssembly.

What kind of behavior would you expect if the resulting u8 array is modified? I know it would corrupt the hash – it looks like the only way I wouldn't get back a (useless) "hash" is if the bytes representing the len field get modified? (I'm OK with practically anything unexpected causing a process::abort.)

from hashes.

bitjson avatar bitjson commented on May 29, 2024

Perfect, thanks for all the info @newpavlov! This has been extremely helpful.

UPD: Also note that buffer will contain parts of the secret message, so private input will be partially leaked.

Good to know – another reason not to use this for the multi-machine scenario above. 😅 (But perfect for providing the purely-functional interface to JavaScript.)

I think you've completely solved my use case, so I'll go ahead and close this now. Thanks for your help!

from hashes.

bitjson avatar bitjson commented on May 29, 2024

@newpavlov this is probably getting into StackOverflow territory, but in case someone else finds this issue later:

When I'm trying to use that snippet, I'm seeing:

error[E0512]: transmute called with types of different sizes
  --> src/lib.rs:44:42
   |
44 |     let mut hasher: Ripemd160 = unsafe { std::mem::transmute(raw_state) };
   |                                          ^^^^^^^^^^^^^^^^^^^
   |
   = note: source type: &[u8; 104] (64 bits)
   = note: target type: ripemd160::Ripemd160 (832 bits)

error[E0512]: transmute called with types of different sizes
  --> src/lib.rs:52:42
   |
52 |     let mut hasher: Ripemd160 = unsafe { std::mem::transmute(raw_state) };
   |                                          ^^^^^^^^^^^^^^^^^^^
   |
   = note: source type: &[u8; 104] (64 bits)
   = note: target type: ripemd160::Ripemd160 (832 bits)

error: aborting due to 2 previous errors

Here's how I'm using it currently:

extern crate ripemd160;

use ripemd160::{Digest, Ripemd160};

const RIPEMD160_SIZE: usize = std::mem::size_of::<Ripemd160>();

pub fn ripemd160_init() -> [u8; RIPEMD160_SIZE] {
    let hasher = Ripemd160::new();
    let raw_state: [u8; RIPEMD160_SIZE] = unsafe { std::mem::transmute(hasher) };
    return raw_state;
}

pub fn ripemd160_update(raw_state: &[u8; RIPEMD160_SIZE], input: &[u8]) -> [u8; RIPEMD160_SIZE] {
    let mut hasher: Ripemd160 = unsafe { std::mem::transmute(raw_state) };
    hasher.input(input);
    let raw_state: [u8; RIPEMD160_SIZE] = unsafe { std::mem::transmute(hasher) };
    return raw_state;
}

pub fn ripemd160_final(raw_state: &[u8; RIPEMD160_SIZE]) -> Vec<u8> {
    let mut hasher: Ripemd160 = unsafe { std::mem::transmute(raw_state) };
    return hasher.result().to_vec();
}

Am I missing something obvious?

from hashes.

bitjson avatar bitjson commented on May 29, 2024

Back on track, thanks!

from hashes.

bitjson avatar bitjson commented on May 29, 2024

@newpavlov thanks again for the head start – I got there eventually with some help from @nacardin. And thanks @tarcieri for your recommendation – you're definitely right given my initial post.

Don't want to leave you assuming I ignored your advice and rolled my own (horribly-insecure) crypto, here's a little more background:

It's not actually a security application, and the "machines" are WebAssembly VMs. I'm exposing some hashing functions to TypeScript via a purely-functional interface, so I wanted to be able to completely return the computation state and maintain no memory in Rust-land. Here's the final result: https://github.com/bitjson/bitcoin-ts/blob/315bf2396a087fafe3931c5c7d261fd792e2501d/wasm/hashes/ripemd160/src/lib.rs#L40

(I'd certainly love pull requests if you have any ideas for making this better!)

from hashes.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.