HMAC with SHA256/512 in Rust
A comment stating that you are declaring values isn't useful.
Don't use return at the end of blocks; just let the block evaluate to the last expression.
This extends to conditionals like if/else: just let the condition evaluate, there's no reason to set a variable. Note that this allows you to avoid unneeded mutability.
Any time you find yourself writing parallel conditions in multiple places, that's an opportunity to add abstraction. In this case, an enum would be sufficient. Note that this removes the panics; we've statically removed an entire failure case!
You don't need to add parenthesis for chained functions.
Pay attention to your duplication between your conditionals. You can extract most of the duplicated code to DRY up the logic. Note how you even have comments on only one of your two conditional branches even though it should apply to both.
This even makes it so that we no longer need constants because the match prevents duplication.
Instead of looping and pushing values, use Vec:resize
Instead of calling the method key_deriv and having comments explaining that it pads it, just rename the method.
Don't needlessly make variable bindings mutable; it's completely fine to re-bind the same name with let. A good example of this is the key in hmac.
Take &amp;[u8] if you aren't making use of the memory allocation.
Use a Cow to avoid allocating anything if the key is already correctly sized.
Creating a Vec and then manually pushing bytes is probably the slowest path. Instead, either allocate a Vec with enough space or use collect which knows how many elements there are. You could also duplicate the key twice and then mutate it in place.
Avoid indexing into a slice when feasible. Iterators tend to have less overhead.
Don't use variable names like k. Instead, type out very long words like "key".
There's no real reason to use Vec::append as you don't use the source vector until it's destroyed a few lines later. Might as well use the boring extend_from_slice.
Because you've forced hash to return a Vec, you are forcing one extra allocation (that of hash(inner_pad)) You can avoid that by returning the result of the digest and only converting to a Vec when needed.




extern crate ring;

use ring::digest;
use std::borrow::Cow;

enum Variant {
    Small,
    Big,
}

impl Variant {
    /// Return either a SHA256 or SHA512 digest of byte vector
    fn hash(&amp;self, data: &amp;[u8]) -&gt; Vec&lt;u8&gt; {
        let method = match *self {
            Variant::Small =&gt; &amp;digest::SHA256,
            Variant::Big =&gt; &amp;digest::SHA512,
        };
        digest::digest(method, data).as_ref().to_vec()
    }

    fn blocksize(&amp;self) -&gt; usize {
        match *self {
            Variant::Small =&gt; 64,
            Variant::Big =&gt; 128,
        }
    }

    fn pad_key&lt;'a&gt;(&amp;self, k: &amp;'a [u8]) -&gt; Cow&lt;'a, [u8]&gt; {
        let mut k = Cow::from(k);

        // If key k is bigger than blocksize, it should be hashed...
        if k.len() &gt; self.blocksize() {
            k = self.hash(&amp;k).into();
        }

        // ... and then padded with zeroes to fit the blocksize
        if k.len() &lt; self.blocksize() {
            let mut resized_key = k.into_owned();
            resized_key.resize(self.blocksize(), 0x00);
            k = resized_key.into();
        }

        k
    }

    /// Returns an HMAC from message m and key k
    pub fn hmac(&amp;self, key: &amp;[u8], message: &amp;[u8]) -&gt; Vec&lt;u8&gt; {
        let key = self.pad_key(key);

        let make_padded_key = |byte: u8| {
            let mut pad = key.to_vec();
            for i in &amp;mut pad { *i ^= byte };
            pad
        };

        let mut inner_pad = make_padded_key(0x36);
        let mut outer_pad = make_padded_key(0x5C);

        inner_pad.extend_from_slice(message);
        let inner_pad = self.hash(&amp;inner_pad);

        outer_pad.extend_from_slice(&amp;inner_pad);
        self.hash(&amp;outer_pad)
    }
}

fn main() {}