在 Rust 中实现 sha256 时我做错了什么?

问题描述 投票:0回答:1

我正在尝试在 Rust 中实现 sha256。

我通常用

u8
来表达位,这样更容易理解一些东西。现在代码没有给出我想要的输出。

我确定我使用的是 Big Endian 我已经多次检查过异或、旋转和移位函数。

如果我对“ASD”进行散列,则散列应以 1100001110000111011101111 开头。

main.rs

use shash::ShaGo;
fn main() {
    let obj = ShaGo::new();

    let dataw = ShaGo::string_to_bits("ASD");
    let data = ShaGo::create_blocks(dataw);

    println!("Data: {:?}", data);

    let hasho = obj.sha256_hash(data.clone());

    println!("{:?}", hasho);
}

mod shash {
    pub struct ShaGo {
        pub current_hash: Vec<[u8; 32]>,
        constants: Vec<[u8; 32]>,
    }

    impl ShaGo {
        fn init_values() -> Vec<[u8; 32]> {
            let vals: Vec<u32> = vec![
                0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
                0x5be0cd19,
            ];
            let mut result: Vec<[u8; 32]> = Vec::new();
            for val in vals {
                result.push(Self::u32_to_bits(val).try_into().unwrap());
            }

            result
        }

        fn round_constants() -> Vec<[u8; 32]> {
            let mut result: Vec<[u8; 32]> = Vec::with_capacity(64);
            let vals: Vec<u32> = vec![
                0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
                0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
                0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
                0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
                0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
                0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
                0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
                0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
                0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
                0xc67178f2,
            ];
            for val in vals {
                result.push(Self::u32_to_bits(val).try_into().unwrap());
            }
            result
        }

        pub fn new() -> Self {
            ShaGo {
                current_hash: Self::init_values(),
                constants: Self::round_constants(),
            }
        }

        pub fn string_to_bits(text: &str) -> Vec<u8> {
            let mut result: Vec<u8> = Vec::with_capacity(text.len() * 8);

            for kar in text.chars() {
                let mut bits = [0; 8];
                let mut num = kar as u8;
                for i in 0..8 {
                    bits[7 - i] = (num & 1 == 1) as u8;
                    num >>= 1;
                }

                for b in bits {
                    result.push(b);
                }
            }

            result
        }

        fn u64_to_bits(n: u64) -> Vec<u8> {
            let mut bits = Vec::with_capacity(64);

            for i in 0..64 {
                bits.push(((n >> i) & 1) as u8);
            }

            bits.reverse();
            bits
        }

        pub fn u32_to_bits(n: u32) -> Vec<u8> {
            let mut bits = Vec::with_capacity(32);

            for i in 0..32 {
                bits.push(((n >> i) & 1) as u8);
            }

            bits.reverse();
            bits
        }

        pub fn create_blocks(mut bits: Vec<u8>) -> Vec<[u8; 512]> {
            let mut result: Vec<[u8; 512]> = Vec::new();
            let msg_len = bits.len();

            println!("Bits len: {:?}", bits.len());

            let padding_size = 512 - ((bits.len() + 64) % 512);
            println!("Padding size: {:?}", padding_size);
            bits.push(1);

            for _ in 0..(padding_size - 1) {
                bits.push(0);
            }

            bits.append(&mut Self::u64_to_bits(msg_len as u64));

            /* pushes 512 bit array */
            // println!("Bits len: {:?}", bits.len());
            for i in 0..(bits.len() / 512) {
                result.push(bits[(i * 512)..((i + 1) * 512)].try_into().unwrap());
            }

            println!("Result SIZE: {:?}", result[0].len());
            result
        }

        fn rotate_right(bits: [u8; 32], rounds: usize) -> [u8; 32] {
            let mut part1 = bits[(bits.len() - rounds)..bits.len()].to_vec();
            let part2 = bits[0..(bits.len() - rounds)].to_vec();
            part1.extend(part2);

            part1.try_into().unwrap()
        }

        fn shift_right(bits: [u8; 32], rounds: usize) -> [u8; 32] {
            let mut result = vec![];
            let part2 = bits[0..(bits.len() - rounds)].to_vec();

            for _ in 0..rounds {
                result.push(0);
            }
            result.extend(part2);

            result.try_into().unwrap()
        }

        fn extended_xor(b1: [u8; 32], b2: [u8; 32]) -> [u8; 32] {
            let mut result = Vec::with_capacity(32);
            for i in 0..32 {
                result.push((b1[i] != b2[i]) as u8)
            }

            result.try_into().unwrap()
        }

        fn sigma_zero(bits: [u8; 32]) -> [u8; 32] {
            let a = Self::rotate_right(bits, 7);
            let b = Self::rotate_right(bits, 18);
            let c = Self::shift_right(bits, 3);

            let first = Self::extended_xor(a, b);
            Self::extended_xor(first, c)
        }

        fn sigma_one(bits: [u8; 32]) -> [u8; 32] {
            let a = Self::rotate_right(bits, 17);
            let b = Self::rotate_right(bits, 19);
            let c = Self::shift_right(bits, 10);

            let first = Self::extended_xor(a, b);
            Self::extended_xor(first, c)
        }

        fn bits_to_u32(bits: &[u8; 32]) -> u32 {
            bits.iter()
                .enumerate()
                .fold(0, |acc, (i, &bit)| acc | ((bit as u32) << (31 - i)))
        }

        pub fn add_bits(a: [u8; 32], b: [u8; 32], c: [u8; 32], d: [u8; 32]) -> [u8; 32] {
            let _a = Self::bits_to_u32(&a);
            let _b = Self::bits_to_u32(&b);
            let _c = Self::bits_to_u32(&c);
            let _d = Self::bits_to_u32(&d);

            let mut sum = _a.wrapping_add(_b);
            sum = sum.wrapping_add(_c);
            sum = sum.wrapping_add(_d);

            Self::u32_to_bits(sum).try_into().unwrap()
        }

        pub fn expander(bits: [u8; 512]) -> Vec<[u8; 32]> {
            let mut result: Vec<[u8; 32]> = Vec::with_capacity(64);

            for i in 0..16 {
                result.push(bits[(i * 32)..((i + 1) * 32)].try_into().unwrap());
            }

            for i in 16..64 {
                let a = Self::sigma_one(result[i - 2]);
                let b = result[i - 7];
                let c = Self::sigma_zero(result[i - 5]);
                let d = result[i - 16];

                let data = Self::add_bits(a, b, c, d);
                result.push(data);
            }

            result
        }

        fn extended_and(a: [u8; 32], b: [u8; 32]) -> [u8; 32] {
            let mut result: Vec<u8> = Vec::with_capacity(32);

            for i in 0..32 {
                if (a[i] == 1) && (b[i] == 1) {
                    result.push(1);
                } else {
                    result.push(0);
                }
            }

            result.try_into().unwrap()
        }

        fn extended_not(a: [u8; 32]) -> [u8; 32] {
            let mut result: Vec<u8> = Vec::with_capacity(32);
            for i in 0..32 {
                result.push(1 - a[i]);
            }

            result.try_into().unwrap()
        }

        fn Ch(e: [u8; 32], f: [u8; 32], g: [u8; 32]) -> [u8; 32] {
            Self::extended_xor(
                Self::extended_and(e, f),
                Self::extended_and(Self::extended_not(e), g),
            )
        }

        fn Ma(a: [u8; 32], b: [u8; 32], c: [u8; 32]) -> [u8; 32] {
            Self::extended_xor(
                Self::extended_xor(Self::extended_and(a, b), Self::extended_and(a, c)),
                Self::extended_and(b, c),
            )
        }

        fn sig_one(e: [u8; 32]) -> [u8; 32] {
            Self::extended_xor(
                Self::extended_xor(Self::rotate_right(e, 6), Self::rotate_right(e, 11)),
                Self::rotate_right(e, 25),
            )
        }

        fn sig_zero(a: [u8; 32]) -> [u8; 32] {
            Self::extended_xor(
                Self::extended_xor(Self::rotate_right(a, 2), Self::rotate_right(a, 13)),
                Self::rotate_right(a, 22),
            )
        }

        pub fn compress_round(&self, block: [u8; 512], input: Vec<[u8; 32]>) -> Vec<[u8; 32]> {
            let start_vals = input.clone();
            let mut sinput = input.clone();

            let zero_arr = [0 as u8; 32];
            let mut result: Vec<[u8; 32]> = vec![
                zero_arr, zero_arr, zero_arr, zero_arr, zero_arr, zero_arr, zero_arr, zero_arr,
            ];
            let w = Self::expander(block);

            for t in 0..64 {
                // println!("SINPUT: {:?}", sinput);
                result[1] = sinput[0];
                result[2] = sinput[1];
                result[3] = sinput[2];
                result[5] = sinput[4];
                result[6] = sinput[5];
                result[7] = sinput[6];

                let wt_xor_kt = Self::extended_xor(w[t], self.constants[t]);
                let ch_result = Self::Ch(sinput[4], sinput[5], sinput[6]);

                let mut path =
                    Self::extended_xor(Self::extended_xor(wt_xor_kt, ch_result), sinput[7]);
                let sig_one_res = Self::sig_one(sinput[4]);

                path = Self::extended_xor(path, sig_one_res);

                result[4] = Self::extended_xor(sinput[3], path);
                path = Self::extended_xor(path, Self::Ma(sinput[0], sinput[1], sinput[2]));
                path = Self::extended_xor(Self::sig_zero(sinput[0]), path);

                result[0] = path;
                sinput = result.clone();
            }

            for i in 0..8 {
                result[i] = Self::extended_xor(result[i], start_vals[i]);
            }
            result
        }

        pub fn sha256_hash(self, blocks: Vec<[u8; 512]>) -> Vec<[u8; 32]> {
            println!("SHA 256 hash");
            println!("BLocks: {:?}", blocks);
            let mut current_hash = self.current_hash.clone();

            for block in blocks {
                println!("First round");
                current_hash = self.compress_round(block, current_hash);
            }

            current_hash
        }
    }
}

这纯粹是一个“个人开发”项目,所以我还没有疯狂到制作自己的 sha256 库:)

rust cryptography sha256
1个回答
0
投票

代码中的部分问题在于您的结构方式使其非常冗长且容易出错。这是因为 SHA-256 通常在 32 位整数上实现(因为它的效率要高得多),并且您已将其实现为单个位。这意味着您已经重新实现了 XOR 之类的东西(使用错误的值;如果位不同,则为 1),并且您还在块压缩结束时将更新实现为 XOR 而不是加法。如果您使用标准 32 位代码方法,这两点都会更加明显。

我已经完全重构了您的代码来执行下面的操作,用本机操作替换了自定义操作实现,并添加了一些测试(根据 GNU coreutils 的

sha256sum
计算),它更短、更易于阅读且更快。请注意,因为您正在进行加法 mod 2^32,所以需要使用
Wrapping<u32>
,否则 Rust 在调试模式下会出现恐慌。您已将其实现为
wrapping_add
,这也很好。

我的版本还使用加密库中使用的标准初始化-更新-完成方法。然而,我还没有对其进行高度优化,可能还存在一些低效或有问题的做法。

请注意,我上面提到的只是我立即注意到的事情;由于我删除了所有位转换代码,因此该代码中可能存在其他问题,隐藏了我没有注意到的其他错误。如果您想继续尝试这种方法,修复这些问题将作为读者的练习。

#![allow(dead_code)]

use std::num::Wrapping;

pub struct ShaGo {
    current_hash: [u32; 8],
    buffer: [u8; 64],
    offset: usize,
    total_size: u64,
}

impl ShaGo {
    const INITIAL_VALUE: [u32; 8] = [
        0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab,
        0x5be0cd19,
    ];

    const ROUND_CONSTANTS: [u32; 64] = [
        0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4,
        0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe,
        0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f,
        0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
        0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc,
        0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b,
        0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 0x19a4c116,
        0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
        0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7,
        0xc67178f2,
    ];

    pub fn new() -> Self {
        ShaGo {
            current_hash: Self::INITIAL_VALUE,
            buffer: [0u8; 64],
            offset: 0,
            total_size: 0,
        }
    }

    pub fn update(&mut self, data: &[u8]) {
        self.total_size += data.len() as u64;
        let data = if self.offset != 0 {
            let bytes = std::cmp::min(data.len(), 64 - self.offset);
            self.buffer[self.offset..self.offset + bytes].copy_from_slice(&data[0..bytes]);
            self.offset += bytes;
            if self.offset < 64 {
                return;
            }
            Self::compress_round(&mut self.current_hash, &self.buffer);
            self.offset = 0;
            &data[bytes..]
        } else {
            data
        };
        let mut offset = 0;
        while data.len() - offset >= 64 {
            Self::compress_round(&mut self.current_hash, &data[offset..offset + 64]);
            offset += 64;
        }
        let data = &data[offset..];
        self.buffer[0..data.len()].copy_from_slice(data);
        self.offset = data.len();
    }

    pub fn finish(mut self) -> [u8; 32] {
        let offset = self.offset;
        // We know there must be at least one byte left.
        self.buffer[self.offset] = 0x80;
        if offset < 56 {
            self.buffer[self.offset + 1..56].fill(0);
        } else {
            self.buffer[self.offset + 1..].fill(0);
            Self::compress_round(&mut self.current_hash, &self.buffer);
            self.buffer[0..56].fill(0);
        }
        self.total_size <<= 3;
        self.buffer[56..].copy_from_slice(&self.total_size.to_be_bytes());
        Self::compress_round(&mut self.current_hash, &self.buffer);
        let mut result = [0u8; 32];
        for (i, val) in self.current_hash.as_slice().iter().enumerate() {
            result[i * 4..=i * 4 + 3].copy_from_slice(&val.to_be_bytes());
        }
        result
    }

    fn sigma_zero(x: Wrapping<u32>) -> Wrapping<u32> {
        Wrapping(x.0.rotate_right(7) ^ x.0.rotate_right(18) ^ (x.0 >> 3))
    }

    fn sigma_one(x: Wrapping<u32>) -> Wrapping<u32> {
        Wrapping(x.0.rotate_right(17) ^ x.0.rotate_right(19) ^ (x.0 >> 10))
    }

    pub fn expander(bits: &[u32]) -> [Wrapping<u32>; 64] {
        let bits: Vec<_> = bits.iter().map(|b| Wrapping(*b)).collect();
        let mut result = [Wrapping(0u32); 64];
        result[0..16].copy_from_slice(&bits);

        for i in 16..64 {
            let s0 = Self::sigma_zero(result[i - 15]);
            let s1 = Self::sigma_one(result[i - 2]);
            result[i] = result[i - 16] + s0 + result[i - 7] + s1;
        }

        result
    }

    fn choose(e: Wrapping<u32>, f: Wrapping<u32>, g: Wrapping<u32>) -> Wrapping<u32> {
        (e & f) ^ ((!e) & g)
    }

    fn majority(a: Wrapping<u32>, b: Wrapping<u32>, c: Wrapping<u32>) -> Wrapping<u32> {
        (a & b) ^ (a & c) ^ (b & c)
    }

    fn sig_one(e: Wrapping<u32>) -> Wrapping<u32> {
        Wrapping(e.0.rotate_right(6) ^ e.0.rotate_right(11) ^ e.0.rotate_right(25))
    }

    fn sig_zero(a: Wrapping<u32>) -> Wrapping<u32> {
        Wrapping(a.0.rotate_right(2) ^ a.0.rotate_right(13) ^ a.0.rotate_right(22))
    }

    fn compress_round(input: &mut [u32; 8], block: &[u8]) {
        let block = &block[0..64];

        let block: Vec<u32> = block
            .chunks(4)
            .map(|c| u32::from_be_bytes(c.try_into().unwrap()))
            .collect();

        let w = Self::expander(&block);

        let mut a = Wrapping(input[0]);
        let mut b = Wrapping(input[1]);
        let mut c = Wrapping(input[2]);
        let mut d = Wrapping(input[3]);
        let mut e = Wrapping(input[4]);
        let mut f = Wrapping(input[5]);
        let mut g = Wrapping(input[6]);
        let mut h = Wrapping(input[7]);

        for (i, val) in w.iter().enumerate() {
            let s1 = Self::sig_one(e);
            let ch = Self::choose(e, f, g);
            let t1 = h + s1 + ch + Wrapping(Self::ROUND_CONSTANTS[i]) + val;
            let s0 = Self::sig_zero(a);
            let maj = Self::majority(a, b, c);
            let t2 = s0 + maj;

            h = g;
            g = f;
            f = e;
            e = d + t1;
            d = c;
            c = b;
            b = a;
            a = t1 + t2;
        }

        *input = [
            (Wrapping(input[0]) + a).0,
            (Wrapping(input[1]) + b).0,
            (Wrapping(input[2]) + c).0,
            (Wrapping(input[3]) + d).0,
            (Wrapping(input[4]) + e).0,
            (Wrapping(input[5]) + f).0,
            (Wrapping(input[6]) + g).0,
            (Wrapping(input[7]) + h).0,
        ];
    }
}

#[cfg(test)]
mod tests {
    fn assert_value(input: &[u8], expected: &str) {
        let mut hash = super::ShaGo::new();
        hash.update(input);
        let result = hash.finish();
        assert_eq!(hex::encode(result), expected);
    }

    #[test]
    fn basic() {
        assert_value(
            b"",
            "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
        );
        assert_value(
            b"abc",
            "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad",
        );
        assert_value(
            b"message digest",
            "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650",
        );
        let v = vec![b'a'; 1000000];
        assert_value(
            &v,
            "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0",
        );
    }
}

主要代码:

mod shash;

fn main() {
    let mut obj = shash::ShaGo::new();

    obj.update(b"ASD");

    let hasho = obj.finish();

    println!("{:?}", hasho);
}
© www.soinside.com 2019 - 2024. All rights reserved.