From d3a63792dfc1ad3831be7a075fefbd9f6a363994 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Sat, 27 Jul 2013 13:41:50 -0400 Subject: [PATCH 1/9] Sha2: Remove unecessary integer type specifications. --- src/libextra/crypto/sha2.rs | 72 ++++++++++++++++++------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index f21722e8d7af0..9ded8dbaf57b6 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -314,26 +314,26 @@ impl Engine512 { // Constants necessary for SHA-2 512 family of digests. static K64: [u64, ..80] = [ - 0x428a2f98d728ae22u64, 0x7137449123ef65cdu64, 0xb5c0fbcfec4d3b2fu64, 0xe9b5dba58189dbbcu64, - 0x3956c25bf348b538u64, 0x59f111f1b605d019u64, 0x923f82a4af194f9bu64, 0xab1c5ed5da6d8118u64, - 0xd807aa98a3030242u64, 0x12835b0145706fbeu64, 0x243185be4ee4b28cu64, 0x550c7dc3d5ffb4e2u64, - 0x72be5d74f27b896fu64, 0x80deb1fe3b1696b1u64, 0x9bdc06a725c71235u64, 0xc19bf174cf692694u64, - 0xe49b69c19ef14ad2u64, 0xefbe4786384f25e3u64, 0x0fc19dc68b8cd5b5u64, 0x240ca1cc77ac9c65u64, - 0x2de92c6f592b0275u64, 0x4a7484aa6ea6e483u64, 0x5cb0a9dcbd41fbd4u64, 0x76f988da831153b5u64, - 0x983e5152ee66dfabu64, 0xa831c66d2db43210u64, 0xb00327c898fb213fu64, 0xbf597fc7beef0ee4u64, - 0xc6e00bf33da88fc2u64, 0xd5a79147930aa725u64, 0x06ca6351e003826fu64, 0x142929670a0e6e70u64, - 0x27b70a8546d22ffcu64, 0x2e1b21385c26c926u64, 0x4d2c6dfc5ac42aedu64, 0x53380d139d95b3dfu64, - 0x650a73548baf63deu64, 0x766a0abb3c77b2a8u64, 0x81c2c92e47edaee6u64, 0x92722c851482353bu64, - 0xa2bfe8a14cf10364u64, 0xa81a664bbc423001u64, 0xc24b8b70d0f89791u64, 0xc76c51a30654be30u64, - 0xd192e819d6ef5218u64, 0xd69906245565a910u64, 0xf40e35855771202au64, 0x106aa07032bbd1b8u64, - 0x19a4c116b8d2d0c8u64, 0x1e376c085141ab53u64, 0x2748774cdf8eeb99u64, 0x34b0bcb5e19b48a8u64, - 0x391c0cb3c5c95a63u64, 0x4ed8aa4ae3418acbu64, 0x5b9cca4f7763e373u64, 0x682e6ff3d6b2b8a3u64, - 0x748f82ee5defb2fcu64, 0x78a5636f43172f60u64, 0x84c87814a1f0ab72u64, 0x8cc702081a6439ecu64, - 0x90befffa23631e28u64, 0xa4506cebde82bde9u64, 0xbef9a3f7b2c67915u64, 0xc67178f2e372532bu64, - 0xca273eceea26619cu64, 0xd186b8c721c0c207u64, 0xeada7dd6cde0eb1eu64, 0xf57d4f7fee6ed178u64, - 0x06f067aa72176fbau64, 0x0a637dc5a2c898a6u64, 0x113f9804bef90daeu64, 0x1b710b35131c471bu64, - 0x28db77f523047d84u64, 0x32caab7b40c72493u64, 0x3c9ebe0a15c9bebcu64, 0x431d67c49c100d4cu64, - 0x4cc5d4becb3e42b6u64, 0x597f299cfc657e2au64, 0x5fcb6fab3ad6faecu64, 0x6c44198c4a475817u64 + 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, 0x59f111f1b605d019, 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, + 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, 0xd5a79147930aa725, 0x06ca6351e003826f, 0x142929670a0e6e70, + 0x27b70a8546d22ffc, 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, + 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, 0x92722c851482353b, + 0xa2bfe8a14cf10364, 0xa81a664bbc423001, 0xc24b8b70d0f89791, 0xc76c51a30654be30, + 0xd192e819d6ef5218, 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, + 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, 0xc67178f2e372532b, + 0xca273eceea26619c, 0xd186b8c721c0c207, 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, + 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 ]; // A structure that represents that state of a digest computation @@ -578,22 +578,22 @@ impl Engine256 { } static K32: [u32, ..64] = [ - 0x428a2f98u32, 0x71374491u32, 0xb5c0fbcfu32, 0xe9b5dba5u32, - 0x3956c25bu32, 0x59f111f1u32, 0x923f82a4u32, 0xab1c5ed5u32, - 0xd807aa98u32, 0x12835b01u32, 0x243185beu32, 0x550c7dc3u32, - 0x72be5d74u32, 0x80deb1feu32, 0x9bdc06a7u32, 0xc19bf174u32, - 0xe49b69c1u32, 0xefbe4786u32, 0x0fc19dc6u32, 0x240ca1ccu32, - 0x2de92c6fu32, 0x4a7484aau32, 0x5cb0a9dcu32, 0x76f988dau32, - 0x983e5152u32, 0xa831c66du32, 0xb00327c8u32, 0xbf597fc7u32, - 0xc6e00bf3u32, 0xd5a79147u32, 0x06ca6351u32, 0x14292967u32, - 0x27b70a85u32, 0x2e1b2138u32, 0x4d2c6dfcu32, 0x53380d13u32, - 0x650a7354u32, 0x766a0abbu32, 0x81c2c92eu32, 0x92722c85u32, - 0xa2bfe8a1u32, 0xa81a664bu32, 0xc24b8b70u32, 0xc76c51a3u32, - 0xd192e819u32, 0xd6990624u32, 0xf40e3585u32, 0x106aa070u32, - 0x19a4c116u32, 0x1e376c08u32, 0x2748774cu32, 0x34b0bcb5u32, - 0x391c0cb3u32, 0x4ed8aa4au32, 0x5b9cca4fu32, 0x682e6ff3u32, - 0x748f82eeu32, 0x78a5636fu32, 0x84c87814u32, 0x8cc70208u32, - 0x90befffau32, 0xa4506cebu32, 0xbef9a3f7u32, 0xc67178f2u32 + 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 ]; struct Sha512 { From 2e95cccbd4fdd13b9609490f53b7d3400c80cd08 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Sat, 27 Jul 2013 13:46:58 -0400 Subject: [PATCH 2/9] Sha2: Rearrage traits / impls / structs. The code was arranged so that the core Sha2 code came first, and then all of the various implementation of Digest followed along later. The problem is that the Sha512 compression function code is far away from the Sha512 Digest implementation, so, if you are trying to read over the code, you need to scroll all around the file for no good reason. The code was rearranged so that all of the Sha512 code is in one place and all of the Sha256 code is in another and so that all impls for a struct are near the definition of that struct. --- src/libextra/crypto/sha2.rs | 505 ++++++++++++++++++------------------ 1 file changed, 257 insertions(+), 248 deletions(-) diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index 9ded8dbaf57b6..5d13da67aee06 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -13,6 +13,7 @@ use std::uint; use digest::Digest; + // BitCounter is a specialized structure intended simply for counting the // number of bits that have been processed by the SHA-2 512 family of functions. // It does very little overflow checking since such checking is not necessary @@ -46,6 +47,7 @@ impl BitCounter { } } + // A structure that represents that state of a digest computation // for the SHA-2 512 family of digest functions struct Engine512 { @@ -336,6 +338,231 @@ static K64: [u64, ..80] = [ 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, 0x5fcb6fab3ad6faec, 0x6c44198c4a475817 ]; + +struct Sha512 { + priv engine: Engine512 +} + +impl Sha512 { + /** + * Construct an new instance of a SHA-512 digest. + */ + pub fn new() -> Sha512 { + Sha512 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0x6a09e667f3bcc908u64, + H1: 0xbb67ae8584caa73bu64, + H2: 0x3c6ef372fe94f82bu64, + H3: 0xa54ff53a5f1d36f1u64, + H4: 0x510e527fade682d1u64, + H5: 0x9b05688c2b3e6c1fu64, + H6: 0x1f83d9abfb41bd6bu64, + H7: 0x5be0cd19137e2179u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Digest for Sha512 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_512(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x6a09e667f3bcc908u64; + self.engine.H1 = 0xbb67ae8584caa73bu64; + self.engine.H2 = 0x3c6ef372fe94f82bu64; + self.engine.H3 = 0xa54ff53a5f1d36f1u64; + self.engine.H4 = 0x510e527fade682d1u64; + self.engine.H5 = 0x9b05688c2b3e6c1fu64; + self.engine.H6 = 0x1f83d9abfb41bd6bu64; + self.engine.H7 = 0x5be0cd19137e2179u64; + } + + fn output_bits(&self) -> uint { 512 } +} + + +struct Sha384 { + priv engine: Engine512 +} + +impl Sha384 { + /** + * Construct an new instance of a SHA-384 digest. + */ + pub fn new() -> Sha384 { + Sha384 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0xcbbb9d5dc1059ed8u64, + H1: 0x629a292a367cd507u64, + H2: 0x9159015a3070dd17u64, + H3: 0x152fecd8f70e5939u64, + H4: 0x67332667ffc00b31u64, + H5: 0x8eb44a8768581511u64, + H6: 0xdb0c2e0d64f98fa7u64, + H7: 0x47b5481dbefa4fa4u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Digest for Sha384 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_384(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0xcbbb9d5dc1059ed8u64; + self.engine.H1 = 0x629a292a367cd507u64; + self.engine.H2 = 0x9159015a3070dd17u64; + self.engine.H3 = 0x152fecd8f70e5939u64; + self.engine.H4 = 0x67332667ffc00b31u64; + self.engine.H5 = 0x8eb44a8768581511u64; + self.engine.H6 = 0xdb0c2e0d64f98fa7u64; + self.engine.H7 = 0x47b5481dbefa4fa4u64; + } + + fn output_bits(&self) -> uint { 384 } +} + + +struct Sha512Trunc256 { + priv engine: Engine512 +} + +impl Sha512Trunc256 { + /** + * Construct an new instance of a SHA-512/256 digest. + */ + pub fn new() -> Sha512Trunc256 { + Sha512Trunc256 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0x22312194fc2bf72cu64, + H1: 0x9f555fa3c84c64c2u64, + H2: 0x2393b86b6f53b151u64, + H3: 0x963877195940eabdu64, + H4: 0x96283ee2a88effe3u64, + H5: 0xbe5e1e2553863992u64, + H6: 0x2b0199fc2c85b8aau64, + H7: 0x0eb72ddc81c52ca2u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Digest for Sha512Trunc256 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_256(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x22312194fc2bf72cu64; + self.engine.H1 = 0x9f555fa3c84c64c2u64; + self.engine.H2 = 0x2393b86b6f53b151u64; + self.engine.H3 = 0x963877195940eabdu64; + self.engine.H4 = 0x96283ee2a88effe3u64; + self.engine.H5 = 0xbe5e1e2553863992u64; + self.engine.H6 = 0x2b0199fc2c85b8aau64; + self.engine.H7 = 0x0eb72ddc81c52ca2u64; + } + + fn output_bits(&self) -> uint { 256 } +} + + +struct Sha512Trunc224 { + priv engine: Engine512 +} + +impl Sha512Trunc224 { + /** + * Construct an new instance of a SHA-512/224 digest. + */ + pub fn new() -> Sha512Trunc224 { + Sha512Trunc224 { + engine: Engine512 { + input_buffer: [0u8, ..8], + input_buffer_idx: 0, + bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, + H0: 0x8c3d37c819544da2u64, + H1: 0x73e1996689dcd4d6u64, + H2: 0x1dfab7ae32ff9c82u64, + H3: 0x679dd514582f9fcfu64, + H4: 0x0f6d2b697bd44da8u64, + H5: 0x77e36f7304c48942u64, + H6: 0x3f9d85a86a1d36c8u64, + H7: 0x1112e6ad91d692a1u64, + W: [0u64, ..80], + W_idx: 0, + finished: false, + } + } + } +} + +impl Digest for Sha512Trunc224 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_224(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x8c3d37c819544da2u64; + self.engine.H1 = 0x73e1996689dcd4d6u64; + self.engine.H2 = 0x1dfab7ae32ff9c82u64; + self.engine.H3 = 0x679dd514582f9fcfu64; + self.engine.H4 = 0x0f6d2b697bd44da8u64; + self.engine.H5 = 0x77e36f7304c48942u64; + self.engine.H6 = 0x3f9d85a86a1d36c8u64; + self.engine.H7 = 0x1112e6ad91d692a1u64; + } + + fn output_bits(&self) -> uint { 224 } +} + + // A structure that represents that state of a digest computation // for the SHA-2 256 family of digest functions struct Engine256 { @@ -596,134 +823,11 @@ static K32: [u32, ..64] = [ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 ]; -struct Sha512 { - priv engine: Engine512 -} - -struct Sha384 { - priv engine: Engine512 -} - -struct Sha512Trunc256 { - priv engine: Engine512 -} - -struct Sha512Trunc224 { - priv engine: Engine512 -} struct Sha256 { priv engine: Engine256 } -struct Sha224 { - priv engine: Engine256 -} - -impl Sha512 { - /** - * Construct an new instance of a SHA-512 digest. - */ - pub fn new() -> Sha512 { - Sha512 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0x6a09e667f3bcc908u64, - H1: 0xbb67ae8584caa73bu64, - H2: 0x3c6ef372fe94f82bu64, - H3: 0xa54ff53a5f1d36f1u64, - H4: 0x510e527fade682d1u64, - H5: 0x9b05688c2b3e6c1fu64, - H6: 0x1f83d9abfb41bd6bu64, - H7: 0x5be0cd19137e2179u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } - } - } -} - -impl Sha384 { - /** - * Construct an new instance of a SHA-384 digest. - */ - pub fn new() -> Sha384 { - Sha384 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0xcbbb9d5dc1059ed8u64, - H1: 0x629a292a367cd507u64, - H2: 0x9159015a3070dd17u64, - H3: 0x152fecd8f70e5939u64, - H4: 0x67332667ffc00b31u64, - H5: 0x8eb44a8768581511u64, - H6: 0xdb0c2e0d64f98fa7u64, - H7: 0x47b5481dbefa4fa4u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } - } - } -} - -impl Sha512Trunc256 { - /** - * Construct an new instance of a SHA-512/256 digest. - */ - pub fn new() -> Sha512Trunc256 { - Sha512Trunc256 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0x22312194fc2bf72cu64, - H1: 0x9f555fa3c84c64c2u64, - H2: 0x2393b86b6f53b151u64, - H3: 0x963877195940eabdu64, - H4: 0x96283ee2a88effe3u64, - H5: 0xbe5e1e2553863992u64, - H6: 0x2b0199fc2c85b8aau64, - H7: 0x0eb72ddc81c52ca2u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } - } - } -} - -impl Sha512Trunc224 { - /** - * Construct an new instance of a SHA-512/224 digest. - */ - pub fn new() -> Sha512Trunc224 { - Sha512Trunc224 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0x8c3d37c819544da2u64, - H1: 0x73e1996689dcd4d6u64, - H2: 0x1dfab7ae32ff9c82u64, - H3: 0x679dd514582f9fcfu64, - H4: 0x0f6d2b697bd44da8u64, - H5: 0x77e36f7304c48942u64, - H6: 0x3f9d85a86a1d36c8u64, - H7: 0x1112e6ad91d692a1u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } - } - } -} - impl Sha256 { /** * Construct an new instance of a SHA-256 digest. @@ -750,6 +854,36 @@ impl Sha256 { } } +impl Digest for Sha256 { + fn input(&mut self, d: &[u8]) { + self.engine.input_vec(d); + } + + fn result(&mut self, out: &mut [u8]) { + self.engine.result_256(out) + } + + fn reset(&mut self) { + self.engine.reset(); + + self.engine.H0 = 0x6a09e667u32; + self.engine.H1 = 0xbb67ae85u32; + self.engine.H2 = 0x3c6ef372u32; + self.engine.H3 = 0xa54ff53au32; + self.engine.H4 = 0x510e527fu32; + self.engine.H5 = 0x9b05688cu32; + self.engine.H6 = 0x1f83d9abu32; + self.engine.H7 = 0x5be0cd19u32; + } + + fn output_bits(&self) -> uint { 256 } +} + + +struct Sha224 { + priv engine: Engine256 +} + impl Sha224 { /** * Construct an new instance of a SHA-224 digest. @@ -776,131 +910,6 @@ impl Sha224 { } } -impl Digest for Sha512 { - fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); - } - - fn result(&mut self, out: &mut [u8]) { - self.engine.result_512(out) - } - - fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x6a09e667f3bcc908u64; - self.engine.H1 = 0xbb67ae8584caa73bu64; - self.engine.H2 = 0x3c6ef372fe94f82bu64; - self.engine.H3 = 0xa54ff53a5f1d36f1u64; - self.engine.H4 = 0x510e527fade682d1u64; - self.engine.H5 = 0x9b05688c2b3e6c1fu64; - self.engine.H6 = 0x1f83d9abfb41bd6bu64; - self.engine.H7 = 0x5be0cd19137e2179u64; - } - - fn output_bits(&self) -> uint { 512 } -} - -impl Digest for Sha384 { - fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); - } - - fn result(&mut self, out: &mut [u8]) { - self.engine.result_384(out) - } - - fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0xcbbb9d5dc1059ed8u64; - self.engine.H1 = 0x629a292a367cd507u64; - self.engine.H2 = 0x9159015a3070dd17u64; - self.engine.H3 = 0x152fecd8f70e5939u64; - self.engine.H4 = 0x67332667ffc00b31u64; - self.engine.H5 = 0x8eb44a8768581511u64; - self.engine.H6 = 0xdb0c2e0d64f98fa7u64; - self.engine.H7 = 0x47b5481dbefa4fa4u64; - } - - fn output_bits(&self) -> uint { 384 } -} - -impl Digest for Sha512Trunc256 { - fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); - } - - fn result(&mut self, out: &mut [u8]) { - self.engine.result_256(out) - } - - fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x22312194fc2bf72cu64; - self.engine.H1 = 0x9f555fa3c84c64c2u64; - self.engine.H2 = 0x2393b86b6f53b151u64; - self.engine.H3 = 0x963877195940eabdu64; - self.engine.H4 = 0x96283ee2a88effe3u64; - self.engine.H5 = 0xbe5e1e2553863992u64; - self.engine.H6 = 0x2b0199fc2c85b8aau64; - self.engine.H7 = 0x0eb72ddc81c52ca2u64; - } - - fn output_bits(&self) -> uint { 256 } -} - -impl Digest for Sha512Trunc224 { - fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); - } - - fn result(&mut self, out: &mut [u8]) { - self.engine.result_224(out) - } - - fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x8c3d37c819544da2u64; - self.engine.H1 = 0x73e1996689dcd4d6u64; - self.engine.H2 = 0x1dfab7ae32ff9c82u64; - self.engine.H3 = 0x679dd514582f9fcfu64; - self.engine.H4 = 0x0f6d2b697bd44da8u64; - self.engine.H5 = 0x77e36f7304c48942u64; - self.engine.H6 = 0x3f9d85a86a1d36c8u64; - self.engine.H7 = 0x1112e6ad91d692a1u64; - } - - fn output_bits(&self) -> uint { 224 } -} - -impl Digest for Sha256 { - fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); - } - - fn result(&mut self, out: &mut [u8]) { - self.engine.result_256(out) - } - - fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x6a09e667u32; - self.engine.H1 = 0xbb67ae85u32; - self.engine.H2 = 0x3c6ef372u32; - self.engine.H3 = 0xa54ff53au32; - self.engine.H4 = 0x510e527fu32; - self.engine.H5 = 0x9b05688cu32; - self.engine.H6 = 0x1f83d9abu32; - self.engine.H7 = 0x5be0cd19u32; - } - - fn output_bits(&self) -> uint { 256 } -} - impl Digest for Sha224 { fn input(&mut self, d: &[u8]) { self.engine.input_vec(d); From 9cc757368481c8605be44ac0c9ca5ade8b036f3e Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Sat, 27 Jul 2013 13:59:41 -0400 Subject: [PATCH 3/9] Sha2: Remove the result_X() methods; move logic into the Digest impls. The result_X() methods just calculate an output of a fixed size. They don't really have much to do with running the actually hash algorithm until the very last step - the output. It makes much more sense to put all this logic into the Digest impls for each specific variation on the hash function. --- src/libextra/crypto/sha2.rs | 123 +++++++++++++++--------------------- 1 file changed, 50 insertions(+), 73 deletions(-) diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index 5d13da67aee06..862bf243bc652 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -270,48 +270,6 @@ impl Engine512 { self.finished = true; } - - fn result_512(&mut self, out: &mut [u8]) { - self.finish(); - - from_u64(self.H0, out.mut_slice(0, 8)); - from_u64(self.H1, out.mut_slice(8, 16)); - from_u64(self.H2, out.mut_slice(16, 24)); - from_u64(self.H3, out.mut_slice(24, 32)); - from_u64(self.H4, out.mut_slice(32, 40)); - from_u64(self.H5, out.mut_slice(40, 48)); - from_u64(self.H6, out.mut_slice(48, 56)); - from_u64(self.H7, out.mut_slice(56, 64)); - } - - fn result_384(&mut self, out: &mut [u8]) { - self.finish(); - - from_u64(self.H0, out.mut_slice(0, 8)); - from_u64(self.H1, out.mut_slice(8, 16)); - from_u64(self.H2, out.mut_slice(16, 24)); - from_u64(self.H3, out.mut_slice(24, 32)); - from_u64(self.H4, out.mut_slice(32, 40)); - from_u64(self.H5, out.mut_slice(40, 48)); - } - - fn result_256(&mut self, out: &mut [u8]) { - self.finish(); - - from_u64(self.H0, out.mut_slice(0, 8)); - from_u64(self.H1, out.mut_slice(8, 16)); - from_u64(self.H2, out.mut_slice(16, 24)); - from_u64(self.H3, out.mut_slice(24, 32)); - } - - fn result_224(&mut self, out: &mut [u8]) { - self.finish(); - - from_u64(self.H0, out.mut_slice(0, 8)); - from_u64(self.H1, out.mut_slice(8, 16)); - from_u64(self.H2, out.mut_slice(16, 24)); - from_u32((self.H3 >> 32) as u32, out.mut_slice(24, 28)); - } } // Constants necessary for SHA-2 512 family of digests. @@ -375,7 +333,17 @@ impl Digest for Sha512 { } fn result(&mut self, out: &mut [u8]) { - self.engine.result_512(out) + self.engine.finish(); + + from_u64(self.engine.H0, out.mut_slice(0, 8)); + from_u64(self.engine.H1, out.mut_slice(8, 16)); + from_u64(self.engine.H2, out.mut_slice(16, 24)); + from_u64(self.engine.H3, out.mut_slice(24, 32)); + from_u64(self.engine.H4, out.mut_slice(32, 40)); + from_u64(self.engine.H5, out.mut_slice(40, 48)); + from_u64(self.engine.H6, out.mut_slice(48, 56)); + from_u64(self.engine.H7, out.mut_slice(56, 64)); + } fn reset(&mut self) { @@ -431,7 +399,14 @@ impl Digest for Sha384 { } fn result(&mut self, out: &mut [u8]) { - self.engine.result_384(out) + self.engine.finish(); + + from_u64(self.engine.H0, out.mut_slice(0, 8)); + from_u64(self.engine.H1, out.mut_slice(8, 16)); + from_u64(self.engine.H2, out.mut_slice(16, 24)); + from_u64(self.engine.H3, out.mut_slice(24, 32)); + from_u64(self.engine.H4, out.mut_slice(32, 40)); + from_u64(self.engine.H5, out.mut_slice(40, 48)); } fn reset(&mut self) { @@ -487,7 +462,12 @@ impl Digest for Sha512Trunc256 { } fn result(&mut self, out: &mut [u8]) { - self.engine.result_256(out) + self.engine.finish(); + + from_u64(self.engine.H0, out.mut_slice(0, 8)); + from_u64(self.engine.H1, out.mut_slice(8, 16)); + from_u64(self.engine.H2, out.mut_slice(16, 24)); + from_u64(self.engine.H3, out.mut_slice(24, 32)); } fn reset(&mut self) { @@ -543,7 +523,12 @@ impl Digest for Sha512Trunc224 { } fn result(&mut self, out: &mut [u8]) { - self.engine.result_224(out) + self.engine.finish(); + + from_u64(self.engine.H0, out.mut_slice(0, 8)); + from_u64(self.engine.H1, out.mut_slice(8, 16)); + from_u64(self.engine.H2, out.mut_slice(16, 24)); + from_u32((self.engine.H3 >> 32) as u32, out.mut_slice(24, 28)); } fn reset(&mut self) { @@ -777,31 +762,6 @@ impl Engine256 { self.finished = true; } - - fn result_256(&mut self, out: &mut [u8]) { - self.finish(); - - from_u32(self.H0, out.mut_slice(0, 4)); - from_u32(self.H1, out.mut_slice(4, 8)); - from_u32(self.H2, out.mut_slice(8, 12)); - from_u32(self.H3, out.mut_slice(12, 16)); - from_u32(self.H4, out.mut_slice(16, 20)); - from_u32(self.H5, out.mut_slice(20, 24)); - from_u32(self.H6, out.mut_slice(24, 28)); - from_u32(self.H7, out.mut_slice(28, 32)); - } - - fn result_224(&mut self, out: &mut [u8]) { - self.finish(); - - from_u32(self.H0, out.mut_slice(0, 4)); - from_u32(self.H1, out.mut_slice(4, 8)); - from_u32(self.H2, out.mut_slice(8, 12)); - from_u32(self.H3, out.mut_slice(12, 16)); - from_u32(self.H4, out.mut_slice(16, 20)); - from_u32(self.H5, out.mut_slice(20, 24)); - from_u32(self.H6, out.mut_slice(24, 28)); - } } static K32: [u32, ..64] = [ @@ -860,7 +820,16 @@ impl Digest for Sha256 { } fn result(&mut self, out: &mut [u8]) { - self.engine.result_256(out) + self.engine.finish(); + + from_u32(self.engine.H0, out.mut_slice(0, 4)); + from_u32(self.engine.H1, out.mut_slice(4, 8)); + from_u32(self.engine.H2, out.mut_slice(8, 12)); + from_u32(self.engine.H3, out.mut_slice(12, 16)); + from_u32(self.engine.H4, out.mut_slice(16, 20)); + from_u32(self.engine.H5, out.mut_slice(20, 24)); + from_u32(self.engine.H6, out.mut_slice(24, 28)); + from_u32(self.engine.H7, out.mut_slice(28, 32)); } fn reset(&mut self) { @@ -916,7 +885,15 @@ impl Digest for Sha224 { } fn result(&mut self, out: &mut [u8]) { - self.engine.result_224(out) + self.engine.finish(); + + from_u32(self.engine.H0, out.mut_slice(0, 4)); + from_u32(self.engine.H1, out.mut_slice(4, 8)); + from_u32(self.engine.H2, out.mut_slice(8, 12)); + from_u32(self.engine.H3, out.mut_slice(12, 16)); + from_u32(self.engine.H4, out.mut_slice(16, 20)); + from_u32(self.engine.H5, out.mut_slice(20, 24)); + from_u32(self.engine.H6, out.mut_slice(24, 28)); } fn reset(&mut self) { From e771aefd1046795865ea995480fe7b59e9da5047 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Sat, 27 Jul 2013 14:02:18 -0400 Subject: [PATCH 4/9] Sha2: Create cryptoutil.rs and re-write the Sha2 module to make use of it. There are 2 main pieces of functionality in cryptoutil.rs: * A set of unsafe function for efficiently reading and writing u32 and u64 values. All of these functions are fairly easy to audit to confirm that they do what they are supposed to. * A FixedBuffer struct. This struct keeps track of input data until there is enough of it to execute the a function on it which expects a fixed block of data. The Sha2 module was rewritten to take advantage of the new functions in cryptoutil as well as FixedBuffer. The result is that the duplicate code for maintaining a buffer of input data is removed from the Sha512 and Sha256 implementation. Additionally, the FixedBuffer code is much more efficient than the previous code was. --- src/libextra/crypto/cryptoutil.rs | 243 ++++++++++ src/libextra/crypto/sha2.rs | 756 ++++++++++++------------------ src/libextra/extra.rs | 2 + 3 files changed, 549 insertions(+), 452 deletions(-) create mode 100644 src/libextra/crypto/cryptoutil.rs diff --git a/src/libextra/crypto/cryptoutil.rs b/src/libextra/crypto/cryptoutil.rs new file mode 100644 index 0000000000000..71e27a56083b7 --- /dev/null +++ b/src/libextra/crypto/cryptoutil.rs @@ -0,0 +1,243 @@ +// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::vec::bytes::{MutableByteVector, copy_memory}; + + +/// Write a u64 into a vector, which must be 8 bytes long. The value is written in big-endian +/// format. +pub fn write_u64_be(dst: &mut[u8], in: u64) { + use std::cast::transmute; + use std::unstable::intrinsics::to_be64; + assert!(dst.len() == 8); + unsafe { + let x: *mut i64 = transmute(dst.unsafe_mut_ref(0)); + *x = to_be64(in as i64); + } +} + +/// Write a u32 into a vector, which must be 4 bytes long. The value is written in big-endian +/// format. +pub fn write_u32_be(dst: &mut[u8], in: u32) { + use std::cast::transmute; + use std::unstable::intrinsics::to_be32; + assert!(dst.len() == 4); + unsafe { + let x: *mut i32 = transmute(dst.unsafe_mut_ref(0)); + *x = to_be32(in as i32); + } +} + +/// Read a vector of bytes into a vector of u64s. The values are read in big-endian format. +pub fn read_u64v_be(dst: &mut[u64], in: &[u8]) { + use std::cast::transmute; + use std::unstable::intrinsics::to_be64; + assert!(dst.len() * 8 == in.len()); + unsafe { + let mut x: *mut i64 = transmute(dst.unsafe_mut_ref(0)); + let mut y: *i64 = transmute(in.unsafe_ref(0)); + for dst.len().times() { + *x = to_be64(*y); + x = x.offset(1); + y = y.offset(1); + } + } +} + +/// Read a vector of bytes into a vector of u32s. The values are read in big-endian format. +pub fn read_u32v_be(dst: &mut[u32], in: &[u8]) { + use std::cast::transmute; + use std::unstable::intrinsics::to_be32; + assert!(dst.len() * 4 == in.len()); + unsafe { + let mut x: *mut i32 = transmute(dst.unsafe_mut_ref(0)); + let mut y: *i32 = transmute(in.unsafe_ref(0)); + for dst.len().times() { + *x = to_be32(*y); + x = x.offset(1); + y = y.offset(1); + } + } +} + + +/// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it +/// must be processed. The input() method takes care of processing and then clearing the buffer +/// automatically. However, other methods do not and require the caller to process the buffer. Any +/// method that modifies the buffer directory or provides the caller with bytes that can be modifies +/// results in those bytes being marked as used by the buffer. +pub trait FixedBuffer { + /// Input a vector of bytes. If the buffer becomes full, proccess it with the provided + /// function and then clear the buffer. + fn input(&mut self, in: &[u8], func: &fn(&[u8])); + + /// Reset the buffer. + fn reset(&mut self); + + /// Zero the buffer up until the specified index. The buffer position currently must not be + /// greater than that index. + fn zero_until(&mut self, idx: uint); + + /// Get a slice of the buffer of the specified size. There must be at least that many bytes + /// remaining in the buffer. + fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8]; + + /// Get the current buffer. The buffer must already be full. This clears the buffer as well. + fn full_buffer<'s>(&'s mut self) -> &'s [u8]; + + /// Get the current position of the buffer. + fn position(&self) -> uint; + + /// Get the number of bytes remaining in the buffer until it is full. + fn remaining(&self) -> uint; + + /// Get the size of the buffer + fn size(&self) -> uint; +} + +macro_rules! impl_fixed_buffer( ($name:ident, $size:expr) => ( + impl FixedBuffer for $name { + fn input(&mut self, in: &[u8], func: &fn(&[u8])) { + let mut i = 0; + + // FIXME: #6304 - This local variable shouldn't be necessary. + let size = $size; + + // If there is already data in the buffer, copy as much as we can into it and process + // the data if the buffer becomes full. + if self.buffer_idx != 0 { + let buffer_remaining = size - self.buffer_idx; + if in.len() >= buffer_remaining { + copy_memory( + self.buffer.mut_slice(self.buffer_idx, size), + in.slice_to(buffer_remaining), + buffer_remaining); + self.buffer_idx = 0; + func(self.buffer); + i += buffer_remaining; + } else { + copy_memory( + self.buffer.mut_slice(self.buffer_idx, self.buffer_idx + in.len()), + in, + in.len()); + self.buffer_idx += in.len(); + return; + } + } + + // While we have at least a full buffer size chunks's worth of data, process that data + // without copying it into the buffer + while in.len() - i >= size { + func(in.slice(i, i + size)); + i += size; + } + + // Copy any input data into the buffer. At this point in the method, the ammount of + // data left in the input vector will be less than the buffer size and the buffer will + // be empty. + let in_remaining = in.len() - i; + copy_memory( + self.buffer.mut_slice(0, in_remaining), + in.slice_from(i), + in.len() - i); + self.buffer_idx += in_remaining; + } + + fn reset(&mut self) { + self.buffer_idx = 0; + } + + fn zero_until(&mut self, idx: uint) { + assert!(idx >= self.buffer_idx); + self.buffer.mut_slice(self.buffer_idx, idx).set_memory(0); + self.buffer_idx = idx; + } + + fn next<'s>(&'s mut self, len: uint) -> &'s mut [u8] { + self.buffer_idx += len; + return self.buffer.mut_slice(self.buffer_idx - len, self.buffer_idx); + } + + fn full_buffer<'s>(&'s mut self) -> &'s [u8] { + assert!(self.buffer_idx == $size); + self.buffer_idx = 0; + return self.buffer.slice_to($size); + } + + fn position(&self) -> uint { self.buffer_idx } + + fn remaining(&self) -> uint { $size - self.buffer_idx } + + fn size(&self) -> uint { $size } + } +)) + + +/// A fixed size buffer of 64 bytes useful for cryptographic operations. +pub struct FixedBuffer64 { + priv buffer: [u8, ..64], + priv buffer_idx: uint, +} + +impl FixedBuffer64 { + /// Create a new buffer + pub fn new() -> FixedBuffer64 { + return FixedBuffer64 { + buffer: [0u8, ..64], + buffer_idx: 0 + }; + } +} + +impl_fixed_buffer!(FixedBuffer64, 64) + +/// A fixed size buffer of 128 bytes useful for cryptographic operations. +pub struct FixedBuffer128 { + priv buffer: [u8, ..128], + priv buffer_idx: uint, +} + +impl FixedBuffer128 { + /// Create a new buffer + pub fn new() -> FixedBuffer128 { + return FixedBuffer128 { + buffer: [0u8, ..128], + buffer_idx: 0 + }; + } +} + +impl_fixed_buffer!(FixedBuffer128, 128) + + +/// The StandardPadding trait adds a method useful for various hash algorithms to a FixedBuffer +/// struct. +pub trait StandardPadding { + /// Add standard padding to the buffer. The buffer must not be full when this method is called + /// and is guaranteed to have exactly rem remaining bytes when it returns. If there are not at + /// least rem bytes available, the buffer will be zero padded, processed, cleared, and then + /// filled with zeros again until only rem bytes are remaining. + fn standard_padding(&mut self, rem: uint, func: &fn(&[u8])); +} + +impl StandardPadding for T { + fn standard_padding(&mut self, rem: uint, func: &fn(&[u8])) { + let size = self.size(); + + self.next(1)[0] = 128; + + if self.remaining() < rem { + self.zero_until(size); + func(self.full_buffer()); + } + + self.zero_until(size - rem); + } +} diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index 862bf243bc652..0b2a3cb903ea3 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -8,9 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use std::uint; +use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, FixedBuffer, + FixedBuffer128, FixedBuffer64, StandardPadding}; use digest::Digest; @@ -25,6 +26,13 @@ struct BitCounter { } impl BitCounter { + fn new() -> BitCounter { + return BitCounter { + high_bit_count: 0, + low_byte_count: 0 + }; + } + fn add_bytes(&mut self, bytes: uint) { self.low_byte_count += bytes as u64; if(self.low_byte_count > 0x1fffffffffffffffu64) { @@ -48,12 +56,9 @@ impl BitCounter { } -// A structure that represents that state of a digest computation -// for the SHA-2 512 family of digest functions -struct Engine512 { - input_buffer: [u8, ..8], - input_buffer_idx: uint, - bit_counter: BitCounter, +// A structure that represents that state of a digest computation for the SHA-2 512 family of digest +// functions +struct Engine512State { H0: u64, H1: u64, H2: u64, @@ -62,91 +67,34 @@ struct Engine512 { H5: u64, H6: u64, H7: u64, - W: [u64, ..80], - W_idx: uint, - finished: bool, } -// Convert a [u8] to a u64 in big-endian format -fn to_u64(in: &[u8]) -> u64 { - (in[0] as u64) << 56 | - (in[1] as u64) << 48 | - (in[2] as u64) << 40 | - (in[3] as u64) << 32 | - (in[4] as u64) << 24 | - (in[5] as u64) << 16 | - (in[6] as u64) << 8 | - (in[7] as u64) -} - -// Convert a u64 to a [u8] in big endian format -fn from_u64(in: u64, out: &mut [u8]) { - out[0] = (in >> 56) as u8; - out[1] = (in >> 48) as u8; - out[2] = (in >> 40) as u8; - out[3] = (in >> 32) as u8; - out[4] = (in >> 24) as u8; - out[5] = (in >> 16) as u8; - out[6] = (in >> 8) as u8; - out[7] = in as u8; -} - -impl Engine512 { - fn input_byte(&mut self, in: u8) { - assert!(!self.finished) - - self.input_buffer[self.input_buffer_idx] = in; - self.input_buffer_idx += 1; - - if (self.input_buffer_idx == 8) { - self.input_buffer_idx = 0; - let w = to_u64(self.input_buffer); - self.process_word(w); - } - - self.bit_counter.add_bytes(1); - } - - fn input_vec(&mut self, in: &[u8]) { - assert!(!self.finished) - - let mut i = 0; - - while i < in.len() && self.input_buffer_idx != 0 { - self.input_byte(in[i]); - i += 1; - } - - while in.len() - i >= 8 { - let w = to_u64(in.slice(i, i + 8)); - self.process_word(w); - self.bit_counter.add_bytes(8); - i += 8; - } - - while i < in.len() { - self.input_byte(in[i]); - i += 1; - } +impl Engine512State { + fn new(h: &[u64, ..8]) -> Engine512State { + return Engine512State { + H0: h[0], + H1: h[1], + H2: h[2], + H3: h[3], + H4: h[4], + H5: h[5], + H6: h[6], + H7: h[7] + }; } - fn reset(&mut self) { - self.bit_counter.reset(); - self.finished = false; - self.input_buffer_idx = 0; - self.W_idx = 0; - } - - fn process_word(&mut self, in: u64) { - self.W[self.W_idx] = in; - self.W_idx += 1; - if (self.W_idx == 16) { - self.W_idx = 0; - self.process_block(); - } + fn reset(&mut self, h: &[u64, ..8]) { + self.H0 = h[0]; + self.H1 = h[1]; + self.H2 = h[2]; + self.H3 = h[3]; + self.H4 = h[4]; + self.H5 = h[5]; + self.H6 = h[6]; + self.H7 = h[7]; } - fn process_block(&mut self) { + fn process_block(&mut self, data: &[u8]) { fn ch(x: u64, y: u64, z: u64) -> u64 { ((x & y) ^ ((!x) & z)) } @@ -171,9 +119,13 @@ impl Engine512 { ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6) } + let mut W = [0u64, ..80]; + + read_u64v_be(W.mut_slice(0, 16), data); + for uint::range(16, 80) |t| { - self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) + - self.W[t - 16]; + W[t] = sigma1(W[t - 2]) + W[t - 7] + sigma0(W[t - 15]) + + W[t - 16]; } let mut a = self.H0; @@ -187,42 +139,42 @@ impl Engine512 { let mut t = 0; for uint::range(0, 10) |_| { - h += sum1(e) + ch(e, f, g) + K64[t] + self.W[t]; + h += sum1(e) + ch(e, f, g) + K64[t] + W[t]; d += h; h += sum0(a) + maj(a, b, c); t += 1; - g += sum1(d) + ch(d, e, f) + K64[t] + self.W[t]; + g += sum1(d) + ch(d, e, f) + K64[t] + W[t]; c += g; g += sum0(h) + maj(h, a, b); t += 1; - f += sum1(c) + ch(c, d, e) + K64[t] + self.W[t]; + f += sum1(c) + ch(c, d, e) + K64[t] + W[t]; b += f; f += sum0(g) + maj(g, h, a); t += 1; - e += sum1(b) + ch(b, c, d) + K64[t] + self.W[t]; + e += sum1(b) + ch(b, c, d) + K64[t] + W[t]; a += e; e += sum0(f) + maj(f, g, h); t += 1; - d += sum1(a) + ch(a, b, c) + K64[t] + self.W[t]; + d += sum1(a) + ch(a, b, c) + K64[t] + W[t]; h += d; d += sum0(e) + maj(e, f, g); t += 1; - c += sum1(h) + ch(h, a, b) + K64[t] + self.W[t]; + c += sum1(h) + ch(h, a, b) + K64[t] + W[t]; g += c; c += sum0(d) + maj(d, e, f); t += 1; - b += sum1(g) + ch(g, h, a) + K64[t] + self.W[t]; + b += sum1(g) + ch(g, h, a) + K64[t] + W[t]; f += b; b += sum0(c) + maj(c, d, e); t += 1; - a += sum1(f) + ch(f, g, h) + K64[t] + self.W[t]; + a += sum1(f) + ch(f, g, h) + K64[t] + W[t]; e += a; a += sum0(b) + maj(b, c, d); t += 1; @@ -237,39 +189,6 @@ impl Engine512 { self.H6 += g; self.H7 += h; } - - fn finish(&mut self) { - if (self.finished) { - return; - } - - // must get message length before padding is added - let high_bit_count = self.bit_counter.get_high_bit_count(); - let low_bit_count = self.bit_counter.get_low_bit_count(); - - // add padding - self.input_byte(128u8); - - while self.input_buffer_idx != 0 { - self.input_byte(0u8); - } - - // add length - if (self.W_idx > 14) { - for uint::range(self.W_idx, 16) |_| { - self.process_word(0); - } - } - - while self.W_idx < 14 { - self.process_word(0); - } - - self.process_word(high_bit_count); - self.process_word(low_bit_count); - - self.finished = true; - } } // Constants necessary for SHA-2 512 family of digests. @@ -297,6 +216,53 @@ static K64: [u64, ..80] = [ ]; +// A structure that keeps track of the state of the Sha-512 operation and contains the logic +// necessary to perform the final calculations. +struct Engine512 { + bit_counter: BitCounter, + buffer: FixedBuffer128, + state: Engine512State, + finished: bool, +} + +impl Engine512 { + fn new(h: &[u64, ..8]) -> Engine512 { + return Engine512 { + bit_counter: BitCounter::new(), + buffer: FixedBuffer128::new(), + state: Engine512State::new(h), + finished: false + } + } + + fn reset(&mut self, h: &[u64, ..8]) { + self.bit_counter.reset(); + self.buffer.reset(); + self.state.reset(h); + self.finished = false; + } + + fn input(&mut self, in: &[u8]) { + assert!(!self.finished) + self.bit_counter.add_bytes(in.len()); + self.buffer.input(in, |in: &[u8]| { self.state.process_block(in) }); + } + + fn finish(&mut self) { + if self.finished { + return; + } + + self.buffer.standard_padding(16, |in: &[u8]| { self.state.process_block(in) }); + write_u64_be(self.buffer.next(8), self.bit_counter.get_high_bit_count()); + write_u64_be(self.buffer.next(8), self.bit_counter.get_low_bit_count()); + self.state.process_block(self.buffer.full_buffer()); + + self.finished = true; + } +} + + struct Sha512 { priv engine: Engine512 } @@ -306,62 +272,48 @@ impl Sha512 { * Construct an new instance of a SHA-512 digest. */ pub fn new() -> Sha512 { - Sha512 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0x6a09e667f3bcc908u64, - H1: 0xbb67ae8584caa73bu64, - H2: 0x3c6ef372fe94f82bu64, - H3: 0xa54ff53a5f1d36f1u64, - H4: 0x510e527fade682d1u64, - H5: 0x9b05688c2b3e6c1fu64, - H6: 0x1f83d9abfb41bd6bu64, - H7: 0x5be0cd19137e2179u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } - } + return Sha512 { + engine: Engine512::new(&H512) + }; } } impl Digest for Sha512 { fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); + self.engine.input(d); } fn result(&mut self, out: &mut [u8]) { self.engine.finish(); - from_u64(self.engine.H0, out.mut_slice(0, 8)); - from_u64(self.engine.H1, out.mut_slice(8, 16)); - from_u64(self.engine.H2, out.mut_slice(16, 24)); - from_u64(self.engine.H3, out.mut_slice(24, 32)); - from_u64(self.engine.H4, out.mut_slice(32, 40)); - from_u64(self.engine.H5, out.mut_slice(40, 48)); - from_u64(self.engine.H6, out.mut_slice(48, 56)); - from_u64(self.engine.H7, out.mut_slice(56, 64)); - + write_u64_be(out.mut_slice(0, 8), self.engine.state.H0); + write_u64_be(out.mut_slice(8, 16), self.engine.state.H1); + write_u64_be(out.mut_slice(16, 24), self.engine.state.H2); + write_u64_be(out.mut_slice(24, 32), self.engine.state.H3); + write_u64_be(out.mut_slice(32, 40), self.engine.state.H4); + write_u64_be(out.mut_slice(40, 48), self.engine.state.H5); + write_u64_be(out.mut_slice(48, 56), self.engine.state.H6); + write_u64_be(out.mut_slice(56, 64), self.engine.state.H7); } fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x6a09e667f3bcc908u64; - self.engine.H1 = 0xbb67ae8584caa73bu64; - self.engine.H2 = 0x3c6ef372fe94f82bu64; - self.engine.H3 = 0xa54ff53a5f1d36f1u64; - self.engine.H4 = 0x510e527fade682d1u64; - self.engine.H5 = 0x9b05688c2b3e6c1fu64; - self.engine.H6 = 0x1f83d9abfb41bd6bu64; - self.engine.H7 = 0x5be0cd19137e2179u64; + self.engine.reset(&H512); } fn output_bits(&self) -> uint { 512 } } +static H512: [u64, ..8] = [ + 0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179 +]; + struct Sha384 { priv engine: Engine512 @@ -373,58 +325,45 @@ impl Sha384 { */ pub fn new() -> Sha384 { Sha384 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0xcbbb9d5dc1059ed8u64, - H1: 0x629a292a367cd507u64, - H2: 0x9159015a3070dd17u64, - H3: 0x152fecd8f70e5939u64, - H4: 0x67332667ffc00b31u64, - H5: 0x8eb44a8768581511u64, - H6: 0xdb0c2e0d64f98fa7u64, - H7: 0x47b5481dbefa4fa4u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } + engine: Engine512::new(&H384) } } } impl Digest for Sha384 { fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); + self.engine.input(d); } fn result(&mut self, out: &mut [u8]) { self.engine.finish(); - from_u64(self.engine.H0, out.mut_slice(0, 8)); - from_u64(self.engine.H1, out.mut_slice(8, 16)); - from_u64(self.engine.H2, out.mut_slice(16, 24)); - from_u64(self.engine.H3, out.mut_slice(24, 32)); - from_u64(self.engine.H4, out.mut_slice(32, 40)); - from_u64(self.engine.H5, out.mut_slice(40, 48)); + write_u64_be(out.mut_slice(0, 8), self.engine.state.H0); + write_u64_be(out.mut_slice(8, 16), self.engine.state.H1); + write_u64_be(out.mut_slice(16, 24), self.engine.state.H2); + write_u64_be(out.mut_slice(24, 32), self.engine.state.H3); + write_u64_be(out.mut_slice(32, 40), self.engine.state.H4); + write_u64_be(out.mut_slice(40, 48), self.engine.state.H5); } fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0xcbbb9d5dc1059ed8u64; - self.engine.H1 = 0x629a292a367cd507u64; - self.engine.H2 = 0x9159015a3070dd17u64; - self.engine.H3 = 0x152fecd8f70e5939u64; - self.engine.H4 = 0x67332667ffc00b31u64; - self.engine.H5 = 0x8eb44a8768581511u64; - self.engine.H6 = 0xdb0c2e0d64f98fa7u64; - self.engine.H7 = 0x47b5481dbefa4fa4u64; + self.engine.reset(&H384); } fn output_bits(&self) -> uint { 384 } } +static H384: [u64, ..8] = [ + 0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4 +]; + struct Sha512Trunc256 { priv engine: Engine512 @@ -436,56 +375,43 @@ impl Sha512Trunc256 { */ pub fn new() -> Sha512Trunc256 { Sha512Trunc256 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0x22312194fc2bf72cu64, - H1: 0x9f555fa3c84c64c2u64, - H2: 0x2393b86b6f53b151u64, - H3: 0x963877195940eabdu64, - H4: 0x96283ee2a88effe3u64, - H5: 0xbe5e1e2553863992u64, - H6: 0x2b0199fc2c85b8aau64, - H7: 0x0eb72ddc81c52ca2u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } + engine: Engine512::new(&H512_TRUNC_256) } } } impl Digest for Sha512Trunc256 { fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); + self.engine.input(d); } fn result(&mut self, out: &mut [u8]) { self.engine.finish(); - from_u64(self.engine.H0, out.mut_slice(0, 8)); - from_u64(self.engine.H1, out.mut_slice(8, 16)); - from_u64(self.engine.H2, out.mut_slice(16, 24)); - from_u64(self.engine.H3, out.mut_slice(24, 32)); + write_u64_be(out.mut_slice(0, 8), self.engine.state.H0); + write_u64_be(out.mut_slice(8, 16), self.engine.state.H1); + write_u64_be(out.mut_slice(16, 24), self.engine.state.H2); + write_u64_be(out.mut_slice(24, 32), self.engine.state.H3); } fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x22312194fc2bf72cu64; - self.engine.H1 = 0x9f555fa3c84c64c2u64; - self.engine.H2 = 0x2393b86b6f53b151u64; - self.engine.H3 = 0x963877195940eabdu64; - self.engine.H4 = 0x96283ee2a88effe3u64; - self.engine.H5 = 0xbe5e1e2553863992u64; - self.engine.H6 = 0x2b0199fc2c85b8aau64; - self.engine.H7 = 0x0eb72ddc81c52ca2u64; + self.engine.reset(&H512_TRUNC_256); } fn output_bits(&self) -> uint { 256 } } +static H512_TRUNC_256: [u64, ..8] = [ + 0x22312194fc2bf72c, + 0x9f555fa3c84c64c2, + 0x2393b86b6f53b151, + 0x963877195940eabd, + 0x96283ee2a88effe3, + 0xbe5e1e2553863992, + 0x2b0199fc2c85b8aa, + 0x0eb72ddc81c52ca2 +]; + struct Sha512Trunc224 { priv engine: Engine512 @@ -497,63 +423,47 @@ impl Sha512Trunc224 { */ pub fn new() -> Sha512Trunc224 { Sha512Trunc224 { - engine: Engine512 { - input_buffer: [0u8, ..8], - input_buffer_idx: 0, - bit_counter: BitCounter { high_bit_count: 0, low_byte_count: 0 }, - H0: 0x8c3d37c819544da2u64, - H1: 0x73e1996689dcd4d6u64, - H2: 0x1dfab7ae32ff9c82u64, - H3: 0x679dd514582f9fcfu64, - H4: 0x0f6d2b697bd44da8u64, - H5: 0x77e36f7304c48942u64, - H6: 0x3f9d85a86a1d36c8u64, - H7: 0x1112e6ad91d692a1u64, - W: [0u64, ..80], - W_idx: 0, - finished: false, - } + engine: Engine512::new(&H512_TRUNC_224) } } } impl Digest for Sha512Trunc224 { fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); + self.engine.input(d); } fn result(&mut self, out: &mut [u8]) { self.engine.finish(); - from_u64(self.engine.H0, out.mut_slice(0, 8)); - from_u64(self.engine.H1, out.mut_slice(8, 16)); - from_u64(self.engine.H2, out.mut_slice(16, 24)); - from_u32((self.engine.H3 >> 32) as u32, out.mut_slice(24, 28)); + write_u64_be(out.mut_slice(0, 8), self.engine.state.H0); + write_u64_be(out.mut_slice(8, 16), self.engine.state.H1); + write_u64_be(out.mut_slice(16, 24), self.engine.state.H2); + write_u32_be(out.mut_slice(24, 28), (self.engine.state.H3 >> 32) as u32); } fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x8c3d37c819544da2u64; - self.engine.H1 = 0x73e1996689dcd4d6u64; - self.engine.H2 = 0x1dfab7ae32ff9c82u64; - self.engine.H3 = 0x679dd514582f9fcfu64; - self.engine.H4 = 0x0f6d2b697bd44da8u64; - self.engine.H5 = 0x77e36f7304c48942u64; - self.engine.H6 = 0x3f9d85a86a1d36c8u64; - self.engine.H7 = 0x1112e6ad91d692a1u64; + self.engine.reset(&H512_TRUNC_224); } fn output_bits(&self) -> uint { 224 } } +static H512_TRUNC_224: [u64, ..8] = [ + 0x8c3d37c819544da2, + 0x73e1996689dcd4d6, + 0x1dfab7ae32ff9c82, + 0x679dd514582f9fcf, + 0x0f6d2b697bd44da8, + 0x77e36f7304c48942, + 0x3f9d85a86a1d36c8, + 0x1112e6ad91d692a1, +]; -// A structure that represents that state of a digest computation -// for the SHA-2 256 family of digest functions -struct Engine256 { - input_buffer: [u8, ..4], - input_buffer_idx: uint, - length_bytes: u64, + +// A structure that represents that state of a digest computation for the SHA-2 512 family of digest +// functions +struct Engine256State { H0: u32, H1: u32, H2: u32, @@ -562,84 +472,34 @@ struct Engine256 { H5: u32, H6: u32, H7: u32, - W: [u32, ..64], - W_idx: uint, - finished: bool } -// Convert a [u8] to a u32 in big endian format -fn to_u32(in: &[u8]) -> u32 { - (in[0] as u32) << 24 | - (in[1] as u32) << 16 | - (in[2] as u32) << 8 | - (in[3] as u32) -} - -// Convert a u32 to a [u8] in big endian format -fn from_u32(in: u32, out: &mut [u8]) { - out[0] = (in >> 24) as u8; - out[1] = (in >> 16) as u8; - out[2] = (in >> 8) as u8; - out[3] = in as u8; -} - -impl Engine256 { - fn input_byte(&mut self, in: u8) { - assert!(!self.finished) - - self.input_buffer[self.input_buffer_idx] = in; - self.input_buffer_idx += 1; - - if (self.input_buffer_idx == 4) { - self.input_buffer_idx = 0; - let w = to_u32(self.input_buffer); - self.process_word(w); - } - - self.length_bytes += 1; - } - - fn input_vec(&mut self, in: &[u8]) { - assert!(!self.finished) - - let mut i = 0; - - while i < in.len() && self.input_buffer_idx != 0 { - self.input_byte(in[i]); - i += 1; - } - - while in.len() - i >= 4 { - let w = to_u32(in.slice(i, i + 4)); - self.process_word(w); - self.length_bytes += 4; - i += 4; - } - - while i < in.len() { - self.input_byte(in[i]); - i += 1; - } - +impl Engine256State { + fn new(h: &[u32, ..8]) -> Engine256State { + return Engine256State { + H0: h[0], + H1: h[1], + H2: h[2], + H3: h[3], + H4: h[4], + H5: h[5], + H6: h[6], + H7: h[7] + }; } - fn reset(&mut self) { - self.length_bytes = 0; - self.finished = false; - self.input_buffer_idx = 0; - self.W_idx = 0; + fn reset(&mut self, h: &[u32, ..8]) { + self.H0 = h[0]; + self.H1 = h[1]; + self.H2 = h[2]; + self.H3 = h[3]; + self.H4 = h[4]; + self.H5 = h[5]; + self.H6 = h[6]; + self.H7 = h[7]; } - fn process_word(&mut self, in: u32) { - self.W[self.W_idx] = in; - self.W_idx += 1; - if (self.W_idx == 16) { - self.W_idx = 0; - self.process_block(); - } - } - - fn process_block(&mut self) { + fn process_block(&mut self, data: &[u8]) { fn ch(x: u32, y: u32, z: u32) -> u32 { ((x & y) ^ ((!x) & z)) } @@ -664,9 +524,13 @@ impl Engine256 { ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10) } + let mut W = [0u32, ..80]; + + read_u32v_be(W.mut_slice(0, 16), data); + for uint::range(16, 64) |t| { - self.W[t] = sigma1(self.W[t - 2]) + self.W[t - 7] + sigma0(self.W[t - 15]) + - self.W[t - 16]; + W[t] = sigma1(W[t - 2]) + W[t - 7] + sigma0(W[t - 15]) + + W[t - 16]; } let mut a = self.H0; @@ -680,42 +544,42 @@ impl Engine256 { let mut t = 0; for uint::range(0, 8) |_| { - h += sum1(e) + ch(e, f, g) + K32[t] + self.W[t]; + h += sum1(e) + ch(e, f, g) + K32[t] + W[t]; d += h; h += sum0(a) + maj(a, b, c); t += 1; - g += sum1(d) + ch(d, e, f) + K32[t] + self.W[t]; + g += sum1(d) + ch(d, e, f) + K32[t] + W[t]; c += g; g += sum0(h) + maj(h, a, b); t += 1; - f += sum1(c) + ch(c, d, e) + K32[t] + self.W[t]; + f += sum1(c) + ch(c, d, e) + K32[t] + W[t]; b += f; f += sum0(g) + maj(g, h, a); t += 1; - e += sum1(b) + ch(b, c, d) + K32[t] + self.W[t]; + e += sum1(b) + ch(b, c, d) + K32[t] + W[t]; a += e; e += sum0(f) + maj(f, g, h); t += 1; - d += sum1(a) + ch(a, b, c) + K32[t] + self.W[t]; + d += sum1(a) + ch(a, b, c) + K32[t] + W[t]; h += d; d += sum0(e) + maj(e, f, g); t += 1; - c += sum1(h) + ch(h, a, b) + K32[t] + self.W[t]; + c += sum1(h) + ch(h, a, b) + K32[t] + W[t]; g += c; c += sum0(d) + maj(d, e, f); t += 1; - b += sum1(g) + ch(g, h, a) + K32[t] + self.W[t]; + b += sum1(g) + ch(g, h, a) + K32[t] + W[t]; f += b; b += sum0(c) + maj(c, d, e); t += 1; - a += sum1(f) + ch(f, g, h) + K32[t] + self.W[t]; + a += sum1(f) + ch(f, g, h) + K32[t] + W[t]; e += a; a += sum0(b) + maj(b, c, d); t += 1; @@ -730,38 +594,6 @@ impl Engine256 { self.H6 += g; self.H7 += h; } - - fn finish(&mut self) { - if (self.finished) { - return; - } - - // must get length before adding padding - let bit_length = self.length_bytes << 3; - - // add padding - self.input_byte(128u8); - - while self.input_buffer_idx != 0 { - self.input_byte(0u8); - } - - // add length - if (self.W_idx > 14) { - for uint::range(self.W_idx, 16) |_| { - self.process_word(0); - } - } - - while self.W_idx < 14 { - self.process_word(0); - } - - self.process_word((bit_length >> 32) as u32); - self.process_word(bit_length as u32); - - self.finished = true; - } } static K32: [u32, ..64] = [ @@ -784,6 +616,53 @@ static K32: [u32, ..64] = [ ]; +// A structure that keeps track of the state of the Sha-256 operation and contains the logic +// necessary to perform the final calculations. +struct Engine256 { + length: u64, + buffer: FixedBuffer64, + state: Engine256State, + finished: bool, +} + +impl Engine256 { + fn new(h: &[u32, ..8]) -> Engine256 { + return Engine256 { + length: 0, + buffer: FixedBuffer64::new(), + state: Engine256State::new(h), + finished: false + } + } + + fn reset(&mut self, h: &[u32, ..8]) { + self.length = 0; + self.buffer.reset(); + self.state.reset(h); + self.finished = false; + } + + fn input(&mut self, in: &[u8]) { + assert!(!self.finished) + self.length += in.len() as u64; + self.buffer.input(in, |in: &[u8]| { self.state.process_block(in) }); + } + + fn finish(&mut self) { + if self.finished { + return; + } + + self.buffer.standard_padding(8, |in: &[u8]| { self.state.process_block(in) }); + write_u32_be(self.buffer.next(4), (self.length >> 29) as u32 ); + write_u32_be(self.buffer.next(4), (self.length << 3) as u32); + self.state.process_block(self.buffer.full_buffer()); + + self.finished = true; + } +} + + struct Sha256 { priv engine: Engine256 } @@ -794,60 +673,47 @@ impl Sha256 { */ pub fn new() -> Sha256 { Sha256 { - engine: Engine256 { - input_buffer: [0u8, ..4], - input_buffer_idx: 0, - length_bytes: 0, - H0: 0x6a09e667u32, - H1: 0xbb67ae85u32, - H2: 0x3c6ef372u32, - H3: 0xa54ff53au32, - H4: 0x510e527fu32, - H5: 0x9b05688cu32, - H6: 0x1f83d9abu32, - H7: 0x5be0cd19u32, - W: [0u32, ..64], - W_idx: 0, - finished: false, - } + engine: Engine256::new(&H256) } } } impl Digest for Sha256 { fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); + self.engine.input(d); } fn result(&mut self, out: &mut [u8]) { self.engine.finish(); - from_u32(self.engine.H0, out.mut_slice(0, 4)); - from_u32(self.engine.H1, out.mut_slice(4, 8)); - from_u32(self.engine.H2, out.mut_slice(8, 12)); - from_u32(self.engine.H3, out.mut_slice(12, 16)); - from_u32(self.engine.H4, out.mut_slice(16, 20)); - from_u32(self.engine.H5, out.mut_slice(20, 24)); - from_u32(self.engine.H6, out.mut_slice(24, 28)); - from_u32(self.engine.H7, out.mut_slice(28, 32)); + write_u32_be(out.mut_slice(0, 4), self.engine.state.H0); + write_u32_be(out.mut_slice(4, 8), self.engine.state.H1); + write_u32_be(out.mut_slice(8, 12), self.engine.state.H2); + write_u32_be(out.mut_slice(12, 16), self.engine.state.H3); + write_u32_be(out.mut_slice(16, 20), self.engine.state.H4); + write_u32_be(out.mut_slice(20, 24), self.engine.state.H5); + write_u32_be(out.mut_slice(24, 28), self.engine.state.H6); + write_u32_be(out.mut_slice(28, 32), self.engine.state.H7); } fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0x6a09e667u32; - self.engine.H1 = 0xbb67ae85u32; - self.engine.H2 = 0x3c6ef372u32; - self.engine.H3 = 0xa54ff53au32; - self.engine.H4 = 0x510e527fu32; - self.engine.H5 = 0x9b05688cu32; - self.engine.H6 = 0x1f83d9abu32; - self.engine.H7 = 0x5be0cd19u32; + self.engine.reset(&H256); } fn output_bits(&self) -> uint { 256 } } +static H256: [u32, ..8] = [ + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19 +]; + struct Sha224 { priv engine: Engine256 @@ -859,59 +725,45 @@ impl Sha224 { */ pub fn new() -> Sha224 { Sha224 { - engine: Engine256 { - input_buffer: [0u8, ..4], - input_buffer_idx: 0, - length_bytes: 0, - H0: 0xc1059ed8u32, - H1: 0x367cd507u32, - H2: 0x3070dd17u32, - H3: 0xf70e5939u32, - H4: 0xffc00b31u32, - H5: 0x68581511u32, - H6: 0x64f98fa7u32, - H7: 0xbefa4fa4u32, - W: [0u32, ..64], - W_idx: 0, - finished: false, - } + engine: Engine256::new(&H224) } } } impl Digest for Sha224 { fn input(&mut self, d: &[u8]) { - self.engine.input_vec(d); + self.engine.input(d); } fn result(&mut self, out: &mut [u8]) { self.engine.finish(); - - from_u32(self.engine.H0, out.mut_slice(0, 4)); - from_u32(self.engine.H1, out.mut_slice(4, 8)); - from_u32(self.engine.H2, out.mut_slice(8, 12)); - from_u32(self.engine.H3, out.mut_slice(12, 16)); - from_u32(self.engine.H4, out.mut_slice(16, 20)); - from_u32(self.engine.H5, out.mut_slice(20, 24)); - from_u32(self.engine.H6, out.mut_slice(24, 28)); + write_u32_be(out.mut_slice(0, 4), self.engine.state.H0); + write_u32_be(out.mut_slice(4, 8), self.engine.state.H1); + write_u32_be(out.mut_slice(8, 12), self.engine.state.H2); + write_u32_be(out.mut_slice(12, 16), self.engine.state.H3); + write_u32_be(out.mut_slice(16, 20), self.engine.state.H4); + write_u32_be(out.mut_slice(20, 24), self.engine.state.H5); + write_u32_be(out.mut_slice(24, 28), self.engine.state.H6); } fn reset(&mut self) { - self.engine.reset(); - - self.engine.H0 = 0xc1059ed8u32; - self.engine.H1 = 0x367cd507u32; - self.engine.H2 = 0x3070dd17u32; - self.engine.H3 = 0xf70e5939u32; - self.engine.H4 = 0xffc00b31u32; - self.engine.H5 = 0x68581511u32; - self.engine.H6 = 0x64f98fa7u32; - self.engine.H7 = 0xbefa4fa4u32; + self.engine.reset(&H224); } fn output_bits(&self) -> uint { 224 } } +static H224: [u32, ..8] = [ + 0xc1059ed8, + 0x367cd507, + 0x3070dd17, + 0xf70e5939, + 0xffc00b31, + 0x68581511, + 0x64f98fa7, + 0xbefa4fa4 +]; + #[cfg(test)] mod tests { diff --git a/src/libextra/extra.rs b/src/libextra/extra.rs index f4fb7bcd76c99..250c3800a5526 100644 --- a/src/libextra/extra.rs +++ b/src/libextra/extra.rs @@ -67,6 +67,8 @@ pub mod dlist; pub mod treemap; // Crypto +#[path="crypto/cryptoutil.rs"] +mod cryptoutil; #[path="crypto/digest.rs"] pub mod digest; #[path="crypto/sha1.rs"] From ccfcb0441b82a58cb4281289632c3feca8ae64b1 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Sat, 27 Jul 2013 14:03:57 -0400 Subject: [PATCH 5/9] Sha2: Re-write the Sha2 compression functions to improve performance. The Sha2 compression functions were re-written to execute the message scheduling calculations in the same loop as the rest of the compression function. The compiler is able to generate much better code. Additionally, innermost part of the compression functions were turned into macros to reduce code duplicate and to make the functions more concise. --- src/libextra/crypto/sha2.rs | 189 +++++++++++++++++------------------- 1 file changed, 89 insertions(+), 100 deletions(-) diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index 0b2a3cb903ea3..1b2fd2e0b1faf 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -15,6 +15,25 @@ use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, FixedBu use digest::Digest; +// Sha-512 and Sha-256 use basically the same calculations which are implemented by these macros. +// Inlining the calculations seems to result in better generated code. +macro_rules! schedule_round( ($t:expr) => ( + W[$t] = sigma1(W[$t - 2]) + W[$t - 7] + sigma0(W[$t - 15]) + W[$t - 16]; + ) +) + +macro_rules! sha2_round( + ($A:ident, $B:ident, $C:ident, $D:ident, + $E:ident, $F:ident, $G:ident, $H:ident, $K:ident, $t:expr) => ( + { + $H += sum1($E) + ch($E, $F, $G) + $K[$t] + W[$t]; + $D += $H; + $H += sum0($A) + maj($A, $B, $C); + } + ) +) + + // BitCounter is a specialized structure intended simply for counting the // number of bits that have been processed by the SHA-2 512 family of functions. // It does very little overflow checking since such checking is not necessary @@ -119,15 +138,6 @@ impl Engine512State { ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6) } - let mut W = [0u64, ..80]; - - read_u64v_be(W.mut_slice(0, 16), data); - - for uint::range(16, 80) |t| { - W[t] = sigma1(W[t - 2]) + W[t - 7] + sigma0(W[t - 15]) + - W[t - 16]; - } - let mut a = self.H0; let mut b = self.H1; let mut c = self.H2; @@ -137,47 +147,41 @@ impl Engine512State { let mut g = self.H6; let mut h = self.H7; - let mut t = 0; - for uint::range(0, 10) |_| { - h += sum1(e) + ch(e, f, g) + K64[t] + W[t]; - d += h; - h += sum0(a) + maj(a, b, c); - t += 1; - - g += sum1(d) + ch(d, e, f) + K64[t] + W[t]; - c += g; - g += sum0(h) + maj(h, a, b); - t += 1; - - f += sum1(c) + ch(c, d, e) + K64[t] + W[t]; - b += f; - f += sum0(g) + maj(g, h, a); - t += 1; - - e += sum1(b) + ch(b, c, d) + K64[t] + W[t]; - a += e; - e += sum0(f) + maj(f, g, h); - t += 1; - - d += sum1(a) + ch(a, b, c) + K64[t] + W[t]; - h += d; - d += sum0(e) + maj(e, f, g); - t += 1; - - c += sum1(h) + ch(h, a, b) + K64[t] + W[t]; - g += c; - c += sum0(d) + maj(d, e, f); - t += 1; - - b += sum1(g) + ch(g, h, a) + K64[t] + W[t]; - f += b; - b += sum0(c) + maj(c, d, e); - t += 1; - - a += sum1(f) + ch(f, g, h) + K64[t] + W[t]; - e += a; - a += sum0(b) + maj(b, c, d); - t += 1; + let mut W = [0u64, ..80]; + + read_u64v_be(W.mut_slice(0, 16), data); + + // Putting the message schedule inside the same loop as the round calculations allows for + // the compiler to generate better code. + for uint::range_step(0, 64, 8) |t| { + schedule_round!(t + 16); + schedule_round!(t + 17); + schedule_round!(t + 18); + schedule_round!(t + 19); + schedule_round!(t + 20); + schedule_round!(t + 21); + schedule_round!(t + 22); + schedule_round!(t + 23); + + sha2_round!(a, b, c, d, e, f, g, h, K64, t); + sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1); + sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2); + sha2_round!(f, g, h, a, b, c, d, e, K64, t + 3); + sha2_round!(e, f, g, h, a, b, c, d, K64, t + 4); + sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5); + sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6); + sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7); + } + + for uint::range_step(64, 80, 8) |t| { + sha2_round!(a, b, c, d, e, f, g, h, K64, t); + sha2_round!(h, a, b, c, d, e, f, g, K64, t + 1); + sha2_round!(g, h, a, b, c, d, e, f, K64, t + 2); + sha2_round!(f, g, h, a, b, c, d, e, K64, t + 3); + sha2_round!(e, f, g, h, a, b, c, d, K64, t + 4); + sha2_round!(d, e, f, g, h, a, b, c, K64, t + 5); + sha2_round!(c, d, e, f, g, h, a, b, K64, t + 6); + sha2_round!(b, c, d, e, f, g, h, a, K64, t + 7); } self.H0 += a; @@ -524,15 +528,6 @@ impl Engine256State { ((x >> 17) | (x << 15)) ^ ((x >> 19) | (x << 13)) ^ (x >> 10) } - let mut W = [0u32, ..80]; - - read_u32v_be(W.mut_slice(0, 16), data); - - for uint::range(16, 64) |t| { - W[t] = sigma1(W[t - 2]) + W[t - 7] + sigma0(W[t - 15]) + - W[t - 16]; - } - let mut a = self.H0; let mut b = self.H1; let mut c = self.H2; @@ -542,47 +537,41 @@ impl Engine256State { let mut g = self.H6; let mut h = self.H7; - let mut t = 0; - for uint::range(0, 8) |_| { - h += sum1(e) + ch(e, f, g) + K32[t] + W[t]; - d += h; - h += sum0(a) + maj(a, b, c); - t += 1; - - g += sum1(d) + ch(d, e, f) + K32[t] + W[t]; - c += g; - g += sum0(h) + maj(h, a, b); - t += 1; - - f += sum1(c) + ch(c, d, e) + K32[t] + W[t]; - b += f; - f += sum0(g) + maj(g, h, a); - t += 1; - - e += sum1(b) + ch(b, c, d) + K32[t] + W[t]; - a += e; - e += sum0(f) + maj(f, g, h); - t += 1; - - d += sum1(a) + ch(a, b, c) + K32[t] + W[t]; - h += d; - d += sum0(e) + maj(e, f, g); - t += 1; - - c += sum1(h) + ch(h, a, b) + K32[t] + W[t]; - g += c; - c += sum0(d) + maj(d, e, f); - t += 1; - - b += sum1(g) + ch(g, h, a) + K32[t] + W[t]; - f += b; - b += sum0(c) + maj(c, d, e); - t += 1; - - a += sum1(f) + ch(f, g, h) + K32[t] + W[t]; - e += a; - a += sum0(b) + maj(b, c, d); - t += 1; + let mut W = [0u32, ..64]; + + read_u32v_be(W.mut_slice(0, 16), data); + + // Putting the message schedule inside the same loop as the round calculations allows for + // the compiler to generate better code. + for uint::range_step(0, 48, 8) |t| { + schedule_round!(t + 16); + schedule_round!(t + 17); + schedule_round!(t + 18); + schedule_round!(t + 19); + schedule_round!(t + 20); + schedule_round!(t + 21); + schedule_round!(t + 22); + schedule_round!(t + 23); + + sha2_round!(a, b, c, d, e, f, g, h, K32, t); + sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1); + sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2); + sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3); + sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4); + sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5); + sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6); + sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7); + } + + for uint::range_step(48, 64, 8) |t| { + sha2_round!(a, b, c, d, e, f, g, h, K32, t); + sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1); + sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2); + sha2_round!(f, g, h, a, b, c, d, e, K32, t + 3); + sha2_round!(e, f, g, h, a, b, c, d, K32, t + 4); + sha2_round!(d, e, f, g, h, a, b, c, K32, t + 5); + sha2_round!(c, d, e, f, g, h, a, b, K32, t + 6); + sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7); } self.H0 += a; From 3714e3ae1cfb466ee9552e2069e95fe9a73915c3 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Sat, 27 Jul 2013 15:12:49 -0400 Subject: [PATCH 6/9] Crypto: Remove DigestUtil and convert to default methods on the Digest trait. --- src/libextra/crypto/digest.rs | 46 +++++++++++++++-------------------- src/libextra/crypto/sha1.rs | 2 +- src/libextra/crypto/sha2.rs | 2 +- src/libextra/workcache.rs | 3 +-- 4 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/libextra/crypto/digest.rs b/src/libextra/crypto/digest.rs index 26e8b80d8e3c2..8e6b11c8ee9b3 100644 --- a/src/libextra/crypto/digest.rs +++ b/src/libextra/crypto/digest.rs @@ -8,10 +8,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use std::uint; use std::vec; + /** * The Digest trait specifies an interface common to digest functions, such as SHA-1 and the SHA-2 * family of digest functions. @@ -28,6 +28,10 @@ pub trait Digest { /** * Retrieve the digest result. This method may be called multiple times. + * + * # Arguments + * + * * out - the vector to hold the result. Must be large enough to contain output_bits(). */ fn result(&mut self, out: &mut [u8]); @@ -41,23 +45,7 @@ pub trait Digest { * Get the output size in bits. */ fn output_bits(&self) -> uint; -} - -fn to_hex(rr: &[u8]) -> ~str { - let mut s = ~""; - for rr.iter().advance() |b| { - let hex = uint::to_str_radix(*b as uint, 16u); - if hex.len() == 1 { - s.push_char('0'); - } - s.push_str(hex); - } - return s; -} -/// Contains utility methods for Digests. -/// FIXME: #7339: Convert to default methods when issues with them are resolved. -pub trait DigestUtil { /** * Convenience functon that feeds a string into a digest * @@ -65,23 +53,29 @@ pub trait DigestUtil { * * * in The string to feed into the digest */ - fn input_str(&mut self, in: &str); + fn input_str(&mut self, in: &str) { + self.input(in.as_bytes()); + } /** * Convenience functon that retrieves the result of a digest as a * ~str in hexadecimal format. */ - fn result_str(&mut self) -> ~str; -} - -impl DigestUtil for D { - fn input_str(&mut self, in: &str) { - self.input(in.as_bytes()); - } - fn result_str(&mut self) -> ~str { let mut buf = vec::from_elem((self.output_bits()+7)/8, 0u8); self.result(buf); return to_hex(buf); } } + +fn to_hex(rr: &[u8]) -> ~str { + let mut s = ~""; + for rr.iter().advance() |b| { + let hex = uint::to_str_radix(*b as uint, 16u); + if hex.len() == 1 { + s.push_char('0'); + } + s.push_str(hex); + } + return s; +} diff --git a/src/libextra/crypto/sha1.rs b/src/libextra/crypto/sha1.rs index dbc65754266dc..f467a7f913c13 100644 --- a/src/libextra/crypto/sha1.rs +++ b/src/libextra/crypto/sha1.rs @@ -241,7 +241,7 @@ impl Digest for Sha1 { #[cfg(test)] mod tests { - use digest::{Digest, DigestUtil}; + use digest::Digest; use sha1::Sha1; #[deriving(Clone)] diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index 1b2fd2e0b1faf..bfc938bd937b5 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -756,7 +756,7 @@ static H224: [u32, ..8] = [ #[cfg(test)] mod tests { - use digest::{Digest, DigestUtil}; + use digest::Digest; use sha2::{Sha512, Sha384, Sha512Trunc256, Sha512Trunc224, Sha256, Sha224}; struct Test { diff --git a/src/libextra/workcache.rs b/src/libextra/workcache.rs index 13a8ad36388d4..9edec0224c172 100644 --- a/src/libextra/workcache.rs +++ b/src/libextra/workcache.rs @@ -10,8 +10,7 @@ #[allow(missing_doc)]; - -use digest::DigestUtil; +use digest::Digest; use json; use sha1::Sha1; use serialize::{Encoder, Encodable, Decoder, Decodable}; From 3dabbcb3b16d5da2032a86b94fbb7f999f2c4177 Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Mon, 29 Jul 2013 21:12:20 -0400 Subject: [PATCH 7/9] Crypto: Add large input tests for all Digests Create a helper function in cryptoutil.rs which feeds 1,000,000 'a's into a Digest with varying input sizes and then checks the result. This is essentially the same as one of Sha1's existing tests, so, that test was re-implemented using this method. New tests were added using this method for Sha512 and Sha256. --- src/libextra/crypto/cryptoutil.rs | 33 +++++++++++++++++++++++++++++++ src/libextra/crypto/sha1.rs | 31 ++++++++++------------------- src/libextra/crypto/sha2.rs | 20 +++++++++++++++++++ 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/src/libextra/crypto/cryptoutil.rs b/src/libextra/crypto/cryptoutil.rs index 71e27a56083b7..02f8074f30617 100644 --- a/src/libextra/crypto/cryptoutil.rs +++ b/src/libextra/crypto/cryptoutil.rs @@ -241,3 +241,36 @@ impl StandardPadding for T { self.zero_until(size - rem); } } + + +#[cfg(test)] +mod test { + use std::rand::IsaacRng; + use std::rand::RngUtil; + use std::vec; + + use digest::Digest; + + /// Feed 1,000,000 'a's into the digest with varying input sizes and check that the result is + /// correct. + pub fn test_digest_1million_random(digest: &mut D, blocksize: uint, expected: &str) { + let total_size = 1000000; + let buffer = vec::from_elem(blocksize * 2, 'a' as u8); + let mut rng = IsaacRng::new_unseeded(); + let mut count = 0; + + digest.reset(); + + while count < total_size { + let next: uint = rng.gen_uint_range(0, 2 * blocksize + 1); + let remaining = total_size - count; + let size = if next > remaining { remaining } else { next }; + digest.input(buffer.slice_to(size)); + count += size; + } + + let result_str = digest.result_str(); + + assert!(expected == result_str); + } +} diff --git a/src/libextra/crypto/sha1.rs b/src/libextra/crypto/sha1.rs index f467a7f913c13..7246b8e351839 100644 --- a/src/libextra/crypto/sha1.rs +++ b/src/libextra/crypto/sha1.rs @@ -240,7 +240,7 @@ impl Digest for Sha1 { #[cfg(test)] mod tests { - + use cryptoutil::test::test_digest_1million_random; use digest::Digest; use sha1::Sha1; @@ -253,15 +253,6 @@ mod tests { #[test] fn test() { - fn a_million_letter_a() -> ~str { - let mut i = 0; - let mut rs = ~""; - while i < 100000 { - rs.push_str("aaaaaaaaaa"); - i += 1; - } - return rs; - } // Test messages from FIPS 180-1 let fips_180_1_tests = ~[ @@ -289,17 +280,6 @@ mod tests { ], output_str: ~"84983e441c3bd26ebaae4aa1f95129e5e54670f1" }, - Test { - input: a_million_letter_a(), - output: ~[ - 0x34u8, 0xAAu8, 0x97u8, 0x3Cu8, - 0xD4u8, 0xC4u8, 0xDAu8, 0xA4u8, - 0xF6u8, 0x1Eu8, 0xEBu8, 0x2Bu8, - 0xDBu8, 0xADu8, 0x27u8, 0x31u8, - 0x65u8, 0x34u8, 0x01u8, 0x6Fu8, - ], - output_str: ~"34aa973cd4c4daa4f61eeb2bdbad27316534016f" - }, ]; // Examples from wikipedia @@ -366,6 +346,15 @@ mod tests { sh.reset(); } } + + #[test] + fn test_1million_random_sha1() { + let mut sh = Sha1::new(); + test_digest_1million_random( + &mut sh, + 64, + "34aa973cd4c4daa4f61eeb2bdbad27316534016f"); + } } #[cfg(test)] diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index bfc938bd937b5..4c81b713b4db5 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -756,6 +756,7 @@ static H224: [u32, ..8] = [ #[cfg(test)] mod tests { + use cryptoutil::test::test_digest_1million_random; use digest::Digest; use sha2::{Sha512, Sha384, Sha512Trunc256, Sha512Trunc224, Sha256, Sha224}; @@ -947,6 +948,25 @@ mod tests { test_hash(sh, tests); } + + #[test] + fn test_1million_random_sha512() { + let mut sh = Sha512::new(); + test_digest_1million_random( + &mut sh, + 128, + "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb" + + "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"); + } + + #[test] + fn test_1million_random_sha256() { + let mut sh = Sha256::new(); + test_digest_1million_random( + &mut sh, + 64, + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + } } From 0b954631ebb247a048a17cb27a131ee958c1569e Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 30 Jul 2013 00:07:51 -0400 Subject: [PATCH 8/9] Crypto: Add overflow checking addition functions. Added functions to cryptoutil.rs that perform an addition after shifting the 2nd parameter by a specified constant. These function fail!() if integer overflow will result. Updated the Sha2 implementation to use these functions. --- src/libextra/crypto/cryptoutil.rs | 51 +++++++++++++++++++++ src/libextra/crypto/sha2.rs | 75 +++++++++---------------------- 2 files changed, 71 insertions(+), 55 deletions(-) diff --git a/src/libextra/crypto/cryptoutil.rs b/src/libextra/crypto/cryptoutil.rs index 02f8074f30617..80f5ddb37db87 100644 --- a/src/libextra/crypto/cryptoutil.rs +++ b/src/libextra/crypto/cryptoutil.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use std::num::One; use std::vec::bytes::{MutableByteVector, copy_memory}; @@ -68,6 +69,56 @@ pub fn read_u32v_be(dst: &mut[u32], in: &[u8]) { } +/// Returns true if adding the two parameters will result in integer overflow +pub fn will_add_overflow(x: T, y: T) -> bool { + // This doesn't handle negative values! Don't copy this code elsewhere without considering if + // negative values are important to you! + let max: T = Bounded::max_value(); + return x > max - y; +} + +/// Shifts the second parameter and then adds it to the first. fails!() if there would be unsigned +/// integer overflow. +pub fn shift_add_check_overflow(x: T, mut y: T, shift: T) -> T { + if y.leading_zeros() < shift { + fail!("Could not add values - integer overflow."); + } + y = y << shift; + + if will_add_overflow(x.clone(), y.clone()) { + fail!("Could not add values - integer overflow."); + } + + return x + y; +} + +/// Shifts the second parameter and then adds it to the first, which is a tuple where the first +/// element is the high order value. fails!() if there would be unsigned integer overflow. +pub fn shift_add_check_overflow_tuple + + (x: (T, T), mut y: T, shift: T) -> (T, T) { + if y.leading_zeros() < shift { + fail!("Could not add values - integer overflow."); + } + y = y << shift; + + match x { + (hi, low) => { + let one: T = One::one(); + if will_add_overflow(low.clone(), y.clone()) { + if will_add_overflow(hi.clone(), one.clone()) { + fail!("Could not add values - integer overflow."); + } else { + return (hi + one, low + y); + } + } else { + return (hi, low + y); + } + } + } +} + + /// A FixedBuffer, likes its name implies, is a fixed size buffer. When the buffer becomes full, it /// must be processed. The input() method takes care of processing and then clearing the buffer /// automatically. However, other methods do not and require the caller to process the buffer. Any diff --git a/src/libextra/crypto/sha2.rs b/src/libextra/crypto/sha2.rs index 4c81b713b4db5..a2802473d645e 100644 --- a/src/libextra/crypto/sha2.rs +++ b/src/libextra/crypto/sha2.rs @@ -10,8 +10,8 @@ use std::uint; -use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, FixedBuffer, - FixedBuffer128, FixedBuffer64, StandardPadding}; +use cryptoutil::{write_u64_be, write_u32_be, read_u64v_be, read_u32v_be, shift_add_check_overflow, + shift_add_check_overflow_tuple, FixedBuffer, FixedBuffer128, FixedBuffer64, StandardPadding}; use digest::Digest; @@ -34,47 +34,6 @@ macro_rules! sha2_round( ) -// BitCounter is a specialized structure intended simply for counting the -// number of bits that have been processed by the SHA-2 512 family of functions. -// It does very little overflow checking since such checking is not necessary -// for how it is used. A more generic structure would have to do this checking. -// So, don't copy this structure and use it elsewhere! -struct BitCounter { - high_bit_count: u64, - low_byte_count: u64 -} - -impl BitCounter { - fn new() -> BitCounter { - return BitCounter { - high_bit_count: 0, - low_byte_count: 0 - }; - } - - fn add_bytes(&mut self, bytes: uint) { - self.low_byte_count += bytes as u64; - if(self.low_byte_count > 0x1fffffffffffffffu64) { - self.high_bit_count += (self.low_byte_count >> 61); - self.low_byte_count &= 0x1fffffffffffffffu64; - } - } - - fn reset(&mut self) { - self.low_byte_count = 0; - self.high_bit_count = 0; - } - - fn get_low_bit_count(&self) -> u64 { - self.low_byte_count << 3 - } - - fn get_high_bit_count(&self) -> u64 { - self.high_bit_count - } -} - - // A structure that represents that state of a digest computation for the SHA-2 512 family of digest // functions struct Engine512State { @@ -223,7 +182,7 @@ static K64: [u64, ..80] = [ // A structure that keeps track of the state of the Sha-512 operation and contains the logic // necessary to perform the final calculations. struct Engine512 { - bit_counter: BitCounter, + length_bits: (u64, u64), buffer: FixedBuffer128, state: Engine512State, finished: bool, @@ -232,7 +191,7 @@ struct Engine512 { impl Engine512 { fn new(h: &[u64, ..8]) -> Engine512 { return Engine512 { - bit_counter: BitCounter::new(), + length_bits: (0, 0), buffer: FixedBuffer128::new(), state: Engine512State::new(h), finished: false @@ -240,7 +199,7 @@ impl Engine512 { } fn reset(&mut self, h: &[u64, ..8]) { - self.bit_counter.reset(); + self.length_bits = (0, 0); self.buffer.reset(); self.state.reset(h); self.finished = false; @@ -248,7 +207,8 @@ impl Engine512 { fn input(&mut self, in: &[u8]) { assert!(!self.finished) - self.bit_counter.add_bytes(in.len()); + // Assumes that in.len() can be converted to u64 without overflow + self.length_bits = shift_add_check_overflow_tuple(self.length_bits, in.len() as u64, 3); self.buffer.input(in, |in: &[u8]| { self.state.process_block(in) }); } @@ -258,8 +218,12 @@ impl Engine512 { } self.buffer.standard_padding(16, |in: &[u8]| { self.state.process_block(in) }); - write_u64_be(self.buffer.next(8), self.bit_counter.get_high_bit_count()); - write_u64_be(self.buffer.next(8), self.bit_counter.get_low_bit_count()); + match self.length_bits { + (hi, low) => { + write_u64_be(self.buffer.next(8), hi); + write_u64_be(self.buffer.next(8), low); + } + } self.state.process_block(self.buffer.full_buffer()); self.finished = true; @@ -608,7 +572,7 @@ static K32: [u32, ..64] = [ // A structure that keeps track of the state of the Sha-256 operation and contains the logic // necessary to perform the final calculations. struct Engine256 { - length: u64, + length_bits: u64, buffer: FixedBuffer64, state: Engine256State, finished: bool, @@ -617,7 +581,7 @@ struct Engine256 { impl Engine256 { fn new(h: &[u32, ..8]) -> Engine256 { return Engine256 { - length: 0, + length_bits: 0, buffer: FixedBuffer64::new(), state: Engine256State::new(h), finished: false @@ -625,7 +589,7 @@ impl Engine256 { } fn reset(&mut self, h: &[u32, ..8]) { - self.length = 0; + self.length_bits = 0; self.buffer.reset(); self.state.reset(h); self.finished = false; @@ -633,7 +597,8 @@ impl Engine256 { fn input(&mut self, in: &[u8]) { assert!(!self.finished) - self.length += in.len() as u64; + // Assumes that in.len() can be converted to u64 without overflow + self.length_bits = shift_add_check_overflow(self.length_bits, in.len() as u64, 3); self.buffer.input(in, |in: &[u8]| { self.state.process_block(in) }); } @@ -643,8 +608,8 @@ impl Engine256 { } self.buffer.standard_padding(8, |in: &[u8]| { self.state.process_block(in) }); - write_u32_be(self.buffer.next(4), (self.length >> 29) as u32 ); - write_u32_be(self.buffer.next(4), (self.length << 3) as u32); + write_u32_be(self.buffer.next(4), (self.length_bits >> 32) as u32 ); + write_u32_be(self.buffer.next(4), self.length_bits as u32); self.state.process_block(self.buffer.full_buffer()); self.finished = true; From 9ff79f69f844d1254a75310677a213f666e96acc Mon Sep 17 00:00:00 2001 From: Palmer Cox Date: Tue, 30 Jul 2013 00:07:59 -0400 Subject: [PATCH 9/9] Sha1: Update Sha1 to use new functionality in cryptoutil.rs --- src/libextra/crypto/sha1.rs | 138 ++++++++++-------------------------- 1 file changed, 37 insertions(+), 101 deletions(-) diff --git a/src/libextra/crypto/sha1.rs b/src/libextra/crypto/sha1.rs index 7246b8e351839..56fba9790f001 100644 --- a/src/libextra/crypto/sha1.rs +++ b/src/libextra/crypto/sha1.rs @@ -23,6 +23,8 @@ */ +use cryptoutil::{write_u32_be, read_u32v_be, shift_add_check_overflow, FixedBuffer, FixedBuffer64, + StandardPadding}; use digest::Digest; /* @@ -33,7 +35,6 @@ use digest::Digest; // Some unexported constants static DIGEST_BUF_LEN: uint = 5u; -static MSG_BLOCK_LEN: uint = 64u; static WORK_BUF_LEN: uint = 80u; static K0: u32 = 0x5A827999u32; static K1: u32 = 0x6ED9EBA1u32; @@ -43,58 +44,38 @@ static K3: u32 = 0xCA62C1D6u32; /// Structure representing the state of a Sha1 computation pub struct Sha1 { priv h: [u32, ..DIGEST_BUF_LEN], - priv len_low: u32, - priv len_high: u32, - priv msg_block: [u8, ..MSG_BLOCK_LEN], - priv msg_block_idx: uint, + priv length_bits: u64, + priv buffer: FixedBuffer64, priv computed: bool, - priv work_buf: [u32, ..WORK_BUF_LEN] } fn add_input(st: &mut Sha1, msg: &[u8]) { assert!((!st.computed)); - for msg.iter().advance |element| { - st.msg_block[st.msg_block_idx] = *element; - st.msg_block_idx += 1; - st.len_low += 8; - if st.len_low == 0 { - st.len_high += 1; - if st.len_high == 0 { - // FIXME: Need better failure mode (#2346) - fail!(); - } - } - if st.msg_block_idx == MSG_BLOCK_LEN { process_msg_block(st); } - } + // Assumes that in.len() can be converted to u64 without overflow + st.length_bits = shift_add_check_overflow(st.length_bits, msg.len() as u64, 3); + st.buffer.input(msg, |d: &[u8]| { process_msg_block(d, &mut st.h); }); } -fn process_msg_block(st: &mut Sha1) { +fn process_msg_block(data: &[u8], h: &mut [u32, ..DIGEST_BUF_LEN]) { let mut t: int; // Loop counter - let mut w = st.work_buf; + + let mut w = [0u32, ..WORK_BUF_LEN]; // Initialize the first 16 words of the vector w - t = 0; - while t < 16 { - let mut tmp; - tmp = (st.msg_block[t * 4] as u32) << 24u32; - tmp = tmp | (st.msg_block[t * 4 + 1] as u32) << 16u32; - tmp = tmp | (st.msg_block[t * 4 + 2] as u32) << 8u32; - tmp = tmp | (st.msg_block[t * 4 + 3] as u32); - w[t] = tmp; - t += 1; - } + read_u32v_be(w.mut_slice(0, 16), data); // Initialize the rest of vector w + t = 16; while t < 80 { let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]; w[t] = circular_shift(1, val); t += 1; } - let mut a = st.h[0]; - let mut b = st.h[1]; - let mut c = st.h[2]; - let mut d = st.h[3]; - let mut e = st.h[4]; + let mut a = h[0]; + let mut b = h[1]; + let mut c = h[2]; + let mut d = h[3]; + let mut e = h[4]; let mut temp: u32; t = 0; while t < 20 { @@ -135,12 +116,11 @@ fn process_msg_block(st: &mut Sha1) { a = temp; t += 1; } - st.h[0] = st.h[0] + a; - st.h[1] = st.h[1] + b; - st.h[2] = st.h[2] + c; - st.h[3] = st.h[3] + d; - st.h[4] = st.h[4] + e; - st.msg_block_idx = 0; + h[0] += a; + h[1] += b; + h[2] += c; + h[3] += d; + h[4] += e; } fn circular_shift(bits: u32, word: u32) -> u32 { @@ -148,60 +128,20 @@ fn circular_shift(bits: u32, word: u32) -> u32 { } fn mk_result(st: &mut Sha1, rs: &mut [u8]) { - if !st.computed { pad_msg(st); st.computed = true; } - let mut i = 0; - for st.h.mut_iter().advance |ptr_hpart| { - let hpart = *ptr_hpart; - rs[i] = (hpart >> 24u32 & 0xFFu32) as u8; - rs[i+1] = (hpart >> 16u32 & 0xFFu32) as u8; - rs[i+2] = (hpart >> 8u32 & 0xFFu32) as u8; - rs[i+3] = (hpart & 0xFFu32) as u8; - i += 4; - } -} + if !st.computed { + st.buffer.standard_padding(8, |d: &[u8]| { process_msg_block(d, &mut st.h) }); + write_u32_be(st.buffer.next(4), (st.length_bits >> 32) as u32 ); + write_u32_be(st.buffer.next(4), st.length_bits as u32); + process_msg_block(st.buffer.full_buffer(), &mut st.h); -/* - * According to the standard, the message must be padded to an even - * 512 bits. The first padding bit must be a '1'. The last 64 bits - * represent the length of the original message. All bits in between - * should be 0. This function will pad the message according to those - * rules by filling the msg_block vector accordingly. It will also - * call process_msg_block() appropriately. When it returns, it - * can be assumed that the message digest has been computed. - */ -fn pad_msg(st: &mut Sha1) { - /* - * Check to see if the current message block is too small to hold - * the initial padding bits and length. If so, we will pad the - * block, process it, and then continue padding into a second block. - */ - if st.msg_block_idx > 55 { - st.msg_block[st.msg_block_idx] = 0x80; - st.msg_block_idx += 1; - while st.msg_block_idx < MSG_BLOCK_LEN { - st.msg_block[st.msg_block_idx] = 0; - st.msg_block_idx += 1; - } - process_msg_block(st); - } else { - st.msg_block[st.msg_block_idx] = 0x80; - st.msg_block_idx += 1; - } - while st.msg_block_idx < 56 { - st.msg_block[st.msg_block_idx] = 0u8; - st.msg_block_idx += 1; + st.computed = true; } - // Store the message length as the last 8 octets - st.msg_block[56] = (st.len_high >> 24u32 & 0xFFu32) as u8; - st.msg_block[57] = (st.len_high >> 16u32 & 0xFFu32) as u8; - st.msg_block[58] = (st.len_high >> 8u32 & 0xFFu32) as u8; - st.msg_block[59] = (st.len_high & 0xFFu32) as u8; - st.msg_block[60] = (st.len_low >> 24u32 & 0xFFu32) as u8; - st.msg_block[61] = (st.len_low >> 16u32 & 0xFFu32) as u8; - st.msg_block[62] = (st.len_low >> 8u32 & 0xFFu32) as u8; - st.msg_block[63] = (st.len_low & 0xFFu32) as u8; - process_msg_block(st); + write_u32_be(rs.mut_slice(0, 4), st.h[0]); + write_u32_be(rs.mut_slice(4, 8), st.h[1]); + write_u32_be(rs.mut_slice(8, 12), st.h[2]); + write_u32_be(rs.mut_slice(12, 16), st.h[3]); + write_u32_be(rs.mut_slice(16, 20), st.h[4]); } impl Sha1 { @@ -209,12 +149,9 @@ impl Sha1 { pub fn new() -> Sha1 { let mut st = Sha1 { h: [0u32, ..DIGEST_BUF_LEN], - len_low: 0u32, - len_high: 0u32, - msg_block: [0u8, ..MSG_BLOCK_LEN], - msg_block_idx: 0, + length_bits: 0u64, + buffer: FixedBuffer64::new(), computed: false, - work_buf: [0u32, ..WORK_BUF_LEN] }; st.reset(); return st; @@ -223,14 +160,13 @@ impl Sha1 { impl Digest for Sha1 { pub fn reset(&mut self) { - self.len_low = 0; - self.len_high = 0; - self.msg_block_idx = 0; + self.length_bits = 0; self.h[0] = 0x67452301u32; self.h[1] = 0xEFCDAB89u32; self.h[2] = 0x98BADCFEu32; self.h[3] = 0x10325476u32; self.h[4] = 0xC3D2E1F0u32; + self.buffer.reset(); self.computed = false; } pub fn input(&mut self, msg: &[u8]) { add_input(self, msg); }