Ксом с SHA256/512 в Русте


Я старался, как я могу реализовать HMAC как указано в документе RFC 2104. Это тоже мой первый проект ржавчины, поэтому вероятность того, что новобранец ошибки, которые были сделаны высокой. Так как я довольно новыми для языка, я ищу отзывы в целом.

use functions;
use ring::{digest, test};

// Set blocksizes
pub const BLOCKSIZE_256: usize = 64;
pub const BLOCKSIZE_512: usize = 128;

/// Return either a SHA256 or SHA512 digest of byte vector
fn hash(variant: i32, mut data: Vec<u8>) -> Vec<u8> {
    if variant == 256 {
        data = (digest::digest(&digest::SHA256, &data).as_ref()).to_vec();
    } else if variant == 512 {
        data = (digest::digest(&digest::SHA512, &data).as_ref()).to_vec();
    } else {
        panic!("Invalid variant. Valid variants are 256 and 512.");
    }
    return data;
}

/// Return a key k that has been padded to fit the selected blocksize
fn key_deriv(variant: i32, mut k: Vec<u8>) -> Vec<u8> {
    if variant == 256 {
        // If key k is bigger than blocksize, it should be hashed and then padded with zeroes
        // to fit blocksize
        if k.len() > BLOCKSIZE_256 {
            k = hash(variant, k);
        }
        while k.len() < BLOCKSIZE_256 {
            k.push(0x00);
        }
        return k;
    } else if variant == 512 {
        if k.len() > BLOCKSIZE_512 {
            k = hash(variant, k);
        }
        while k.len() < BLOCKSIZE_512 {
            k.push(0x00);
        }
        return k;
    } else {
        panic!("Invalid variant. Valid variants are 256 and 512.");
    }
}

/// Returns an HMAC from message m and key k
pub fn hmac(variant: i32, mut k: Vec<u8>, mut m: Vec<u8>) -> Vec<u8> {
    // Initialize vectors that will hold the ipad and opad
    let mut ipad = vec![];
    let mut opad = vec![];
    // Pad the key
    k = key_deriv(variant, k);

    for count in 0..k.len() {
        ipad.push(k[count] ^ 0x36);
        opad.push(k[count] ^ 0x5C);
    }

    ipad.append(&mut m);
    ipad = hash(variant, ipad);
    opad.append(&mut ipad);
    opad = hash(variant, opad);

    return opad;
}

Возможное улучшение, которую я вижу-менять ноль перетяжка K в key_deriv(). Сейчас он работает на цикл while, но я заметил, что такой подход, как показано ниже, был немного быстрее. Хотя я подозревал, что это может быть немного более интенсивным использованием памяти из-за распределения вектора и я не уверен, какой из двух выбрать.

let len = k.len();
if len < BLOCKSIZE_256 {
    k.append(&mut vec![0x00; (BLOCKSIZE_256-len)]);
}


245
6
задан 6 февраля 2018 в 06:02 Источник Поделиться
Комментарии
1 ответ


  1. Комментарий о том, что вы объявляете значения не полезно.

  2. Не использовать return в конце блоки; просто позвольте блока вычисления последнего выражения.

  3. Это распространяется на условные, как if/else: просто пусть состояние оценить, нет никаких причин, чтобы установить переменную. Обратите внимание, что это позволяет избежать ненужных переменчивости.

  4. Любой раз, когда вы окажетесь параллельно пишу условия в нескольких местах, это возможность добавить абстракции. В данном случае, перечисление будет достаточно. Обратите внимание, что это снимает панику; мы статически удален весь провал дела!

  5. Вы не должны добавить скобки, связанных функций.

  6. Обратите внимание на свои дублирования ваших условий. Вы можете извлечь большую часть дублируется код, чтобы высушить логики. Обратите внимание, как вы даже комменты есть только на одном из двух условных ветвей, хотя его следует применять как.

  7. Это даже делает так, что мы больше не нужны константы, потому что матч предотвращает дублирование.

  8. Вместо зацикливания и толкает значений, использовать Vec:resize

  9. Вместо вызова метода key_deriv и получив комментарии, объясняющие, что это колодки, просто переименовать метод.

  10. Не напрасно сделать переменными, изменчивыми; это совершенно нормально, чтобы повторно привязать тем же именем с let. Хорошим примером этого является ключевым в hmac.

  11. Взять &[u8] если вы не используете выделение памяти.

  12. Использовать Cow чтобы избежать выделения ничего, если ключ уже правильного размера.

  13. Создание Vec а затем вручную, нажимая байт-это, наверное, самый медленный путь. Вместо этого, либо выделить Vec С достаточно места или используйте collect который знает, сколько элементов существует. Вы также можете продублировать дважды ключ, а затем видоизменить его на месте.

  14. Избежать индексации в ломтик, если это возможно. Итераторы, как правило, имеют меньше накладных расходов.

  15. Не используйте имена переменных, как k. Вместо этого типа очень длинные слова, как "ключ".

  16. Нет реальной причины, чтобы использовать Vec::append как вы не используете исходный вектор, пока не будет уничтожен несколькими строками ниже. Могли бы также использовать скучные extend_from_slice.

  17. Потому что ты заставила hash для возврата Vecвы заставляете одного дополнительного распределения (что hash(inner_pad)) вы можете избежать этого, возвращая результат дайджеста и только преобразование в Vec при необходимости.

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(&self, data: &[u8]) -> Vec<u8> {
let method = match *self {
Variant::Small => &digest::SHA256,
Variant::Big => &digest::SHA512,
};
digest::digest(method, data).as_ref().to_vec()
}

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

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

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

// ... and then padded with zeroes to fit the blocksize
if k.len() < 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(&self, key: &[u8], message: &[u8]) -> Vec<u8> {
let key = self.pad_key(key);

let make_padded_key = |byte: u8| {
let mut pad = key.to_vec();
for i in &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(&inner_pad);

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

fn main() {}

2
ответ дан 7 февраля 2018 в 02:02 Источник Поделиться