2011-02-20 23:56:09 -06:00
|
|
|
/*
|
|
|
|
* A SHA-1 implementation derived from Paul E. Jones's reference
|
|
|
|
* implementation, which is written for clarity, not speed. At some
|
|
|
|
* point this will want to be rewritten.
|
|
|
|
*/
|
|
|
|
export sha1;
|
|
|
|
export mk_sha1;
|
|
|
|
|
2011-09-02 17:34:58 -05:00
|
|
|
type sha1 =
|
2011-07-27 07:19:39 -05:00
|
|
|
// Provide message input as bytes
|
|
|
|
// Provide message input as string
|
2011-08-23 15:22:44 -05:00
|
|
|
// Read the digest as a vector of 20 bytes. After calling this no further
|
|
|
|
// input may provided until reset is called
|
2011-07-27 07:19:39 -05:00
|
|
|
// Same as above, just a hex-string version.
|
|
|
|
// Reset the sha1 state for reuse. This is called
|
|
|
|
// automatically during construction
|
2011-09-02 17:34:58 -05:00
|
|
|
obj {
|
2011-09-12 04:27:30 -05:00
|
|
|
fn input([u8]);
|
|
|
|
fn input_str(str);
|
2011-09-02 17:34:58 -05:00
|
|
|
fn result() -> [u8];
|
|
|
|
fn result_str() -> str;
|
|
|
|
fn reset();
|
|
|
|
};
|
2011-03-26 19:36:08 -05:00
|
|
|
|
2011-02-20 23:56:09 -06:00
|
|
|
|
|
|
|
// Some unexported constants
|
2011-07-27 07:19:39 -05:00
|
|
|
const digest_buf_len: uint = 5u;
|
|
|
|
const msg_block_len: uint = 64u;
|
|
|
|
const work_buf_len: uint = 80u;
|
|
|
|
const k0: u32 = 0x5A827999u32;
|
|
|
|
const k1: u32 = 0x6ED9EBA1u32;
|
|
|
|
const k2: u32 = 0x8F1BBCDCu32;
|
|
|
|
const k3: u32 = 0xCA62C1D6u32;
|
2011-05-11 00:02:27 -05:00
|
|
|
|
2011-06-15 13:19:50 -05:00
|
|
|
|
2011-02-20 23:56:09 -06:00
|
|
|
// Builds a sha1 object
|
|
|
|
fn mk_sha1() -> sha1 {
|
2011-06-15 13:19:50 -05:00
|
|
|
type sha1state =
|
2011-08-04 19:24:54 -05:00
|
|
|
{h: [mutable u32],
|
2011-07-27 07:19:39 -05:00
|
|
|
mutable len_low: u32,
|
|
|
|
mutable len_high: u32,
|
2011-08-04 19:24:54 -05:00
|
|
|
msg_block: [mutable u8],
|
2011-07-27 07:19:39 -05:00
|
|
|
mutable msg_block_idx: uint,
|
|
|
|
mutable computed: bool,
|
2011-08-04 19:24:54 -05:00
|
|
|
work_buf: [mutable u32]};
|
2011-07-27 07:19:39 -05:00
|
|
|
|
2011-09-12 04:27:30 -05:00
|
|
|
fn add_input(st: sha1state, msg: [u8]) {
|
2011-02-20 23:56:09 -06:00
|
|
|
// FIXME: Should be typestate precondition
|
2011-06-15 13:19:50 -05:00
|
|
|
assert (!st.computed);
|
2011-08-15 23:54:52 -05:00
|
|
|
for element: u8 in msg {
|
2011-08-19 17:16:48 -05:00
|
|
|
st.msg_block[st.msg_block_idx] = element;
|
2011-02-20 23:56:09 -06:00
|
|
|
st.msg_block_idx += 1u;
|
|
|
|
st.len_low += 8u32;
|
2011-07-27 07:19:39 -05:00
|
|
|
if st.len_low == 0u32 {
|
2011-02-20 23:56:09 -06:00
|
|
|
st.len_high += 1u32;
|
2011-07-27 07:19:39 -05:00
|
|
|
if st.len_high == 0u32 {
|
2011-02-20 23:56:09 -06:00
|
|
|
// FIXME: Need better failure mode
|
2011-06-15 13:19:50 -05:00
|
|
|
|
2011-02-20 23:56:09 -06:00
|
|
|
fail;
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
if st.msg_block_idx == msg_block_len { process_msg_block(st); }
|
2011-02-20 23:56:09 -06:00
|
|
|
}
|
|
|
|
}
|
2011-09-12 04:27:30 -05:00
|
|
|
fn process_msg_block(st: sha1state) {
|
2011-02-20 23:56:09 -06:00
|
|
|
// FIXME: Make precondition
|
2011-08-15 18:38:23 -05:00
|
|
|
assert (vec::len(st.h) == digest_buf_len);
|
|
|
|
assert (vec::len(st.work_buf) == work_buf_len);
|
2011-07-27 07:19:39 -05:00
|
|
|
let t: int; // Loop counter
|
|
|
|
let w = st.work_buf;
|
2011-06-15 13:19:50 -05:00
|
|
|
|
2011-08-23 15:22:44 -05:00
|
|
|
// Initialize the first 16 words of the vector w
|
2011-02-20 23:56:09 -06:00
|
|
|
t = 0;
|
2011-07-27 07:19:39 -05:00
|
|
|
while t < 16 {
|
|
|
|
let tmp;
|
2011-08-19 17:16:48 -05:00
|
|
|
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;
|
2011-02-20 23:56:09 -06:00
|
|
|
t += 1;
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
2011-08-23 15:22:44 -05:00
|
|
|
// Initialize the rest of vector w
|
2011-07-27 07:19:39 -05:00
|
|
|
while t < 80 {
|
2011-08-19 17:16:48 -05:00
|
|
|
let val = w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16];
|
|
|
|
w[t] = circular_shift(1u32, val);
|
2011-02-20 23:56:09 -06:00
|
|
|
t += 1;
|
|
|
|
}
|
2011-08-19 17:16:48 -05:00
|
|
|
let a = st.h[0];
|
|
|
|
let b = st.h[1];
|
|
|
|
let c = st.h[2];
|
|
|
|
let d = st.h[3];
|
|
|
|
let e = st.h[4];
|
2011-07-27 07:19:39 -05:00
|
|
|
let temp: u32;
|
2011-02-20 23:56:09 -06:00
|
|
|
t = 0;
|
2011-07-27 07:19:39 -05:00
|
|
|
while t < 20 {
|
2011-08-19 17:16:48 -05:00
|
|
|
temp = circular_shift(5u32, a) + (b & c | !b & d) + e + w[t] + k0;
|
2011-02-20 23:56:09 -06:00
|
|
|
e = d;
|
|
|
|
d = c;
|
|
|
|
c = circular_shift(30u32, b);
|
|
|
|
b = a;
|
|
|
|
a = temp;
|
|
|
|
t += 1;
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
while t < 40 {
|
2011-08-19 17:16:48 -05:00
|
|
|
temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w[t] + k1;
|
2011-02-20 23:56:09 -06:00
|
|
|
e = d;
|
|
|
|
d = c;
|
|
|
|
c = circular_shift(30u32, b);
|
|
|
|
b = a;
|
|
|
|
a = temp;
|
|
|
|
t += 1;
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
while t < 60 {
|
2011-06-15 13:19:50 -05:00
|
|
|
temp =
|
2011-08-19 17:16:48 -05:00
|
|
|
circular_shift(5u32, a) + (b & c | b & d | c & d) + e + w[t] +
|
|
|
|
k2;
|
2011-02-20 23:56:09 -06:00
|
|
|
e = d;
|
|
|
|
d = c;
|
|
|
|
c = circular_shift(30u32, b);
|
|
|
|
b = a;
|
|
|
|
a = temp;
|
|
|
|
t += 1;
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
while t < 80 {
|
2011-08-19 17:16:48 -05:00
|
|
|
temp = circular_shift(5u32, a) + (b ^ c ^ d) + e + w[t] + k3;
|
2011-02-20 23:56:09 -06:00
|
|
|
e = d;
|
|
|
|
d = c;
|
|
|
|
c = circular_shift(30u32, b);
|
|
|
|
b = a;
|
|
|
|
a = temp;
|
|
|
|
t += 1;
|
|
|
|
}
|
2011-08-19 17:16:48 -05:00
|
|
|
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;
|
2011-02-20 23:56:09 -06:00
|
|
|
st.msg_block_idx = 0u;
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
fn circular_shift(bits: u32, word: u32) -> u32 {
|
2011-06-19 22:31:53 -05:00
|
|
|
ret word << bits | word >> 32u32 - bits;
|
2011-02-20 23:56:09 -06:00
|
|
|
}
|
2011-09-12 04:27:30 -05:00
|
|
|
fn mk_result(st: sha1state) -> [u8] {
|
2011-07-27 07:19:39 -05:00
|
|
|
if !st.computed { pad_msg(st); st.computed = true; }
|
2011-08-19 17:16:48 -05:00
|
|
|
let rs: [u8] = [];
|
2011-08-15 23:54:52 -05:00
|
|
|
for hpart: u32 in st.h {
|
2011-07-27 07:19:39 -05:00
|
|
|
let a = hpart >> 24u32 & 0xFFu32 as u8;
|
|
|
|
let b = hpart >> 16u32 & 0xFFu32 as u8;
|
|
|
|
let c = hpart >> 8u32 & 0xFFu32 as u8;
|
|
|
|
let d = hpart & 0xFFu32 as u8;
|
2011-08-19 17:16:48 -05:00
|
|
|
rs += [a, b, c, d];
|
2011-02-20 23:56:09 -06:00
|
|
|
}
|
2011-06-24 10:55:02 -05:00
|
|
|
ret rs;
|
2011-02-20 23:56:09 -06:00
|
|
|
}
|
2011-08-23 15:22:44 -05:00
|
|
|
|
2011-02-20 23:56:09 -06:00
|
|
|
/*
|
|
|
|
* 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
|
2011-02-22 17:50:39 -06:00
|
|
|
* rules by filling the msg_block vector accordingly. It will also
|
|
|
|
* call process_msg_block() appropriately. When it returns, it
|
2011-02-20 23:56:09 -06:00
|
|
|
* can be assumed that the message digest has been computed.
|
|
|
|
*/
|
2011-09-12 04:27:30 -05:00
|
|
|
fn pad_msg(st: sha1state) {
|
2011-02-20 23:56:09 -06:00
|
|
|
// FIXME: Should be a precondition
|
2011-08-15 18:38:23 -05:00
|
|
|
assert (vec::len(st.msg_block) == msg_block_len);
|
2011-08-23 15:22:44 -05:00
|
|
|
|
2011-02-20 23:56:09 -06:00
|
|
|
/*
|
|
|
|
* 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.
|
|
|
|
*/
|
2011-07-27 07:19:39 -05:00
|
|
|
if st.msg_block_idx > 55u {
|
2011-08-19 17:16:48 -05:00
|
|
|
st.msg_block[st.msg_block_idx] = 0x80u8;
|
2011-02-20 23:56:09 -06:00
|
|
|
st.msg_block_idx += 1u;
|
2011-07-27 07:19:39 -05:00
|
|
|
while st.msg_block_idx < msg_block_len {
|
2011-08-19 17:16:48 -05:00
|
|
|
st.msg_block[st.msg_block_idx] = 0u8;
|
2011-02-20 23:56:09 -06:00
|
|
|
st.msg_block_idx += 1u;
|
|
|
|
}
|
|
|
|
process_msg_block(st);
|
|
|
|
} else {
|
2011-08-19 17:16:48 -05:00
|
|
|
st.msg_block[st.msg_block_idx] = 0x80u8;
|
2011-02-20 23:56:09 -06:00
|
|
|
st.msg_block_idx += 1u;
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
while st.msg_block_idx < 56u {
|
2011-08-19 17:16:48 -05:00
|
|
|
st.msg_block[st.msg_block_idx] = 0u8;
|
2011-02-20 23:56:09 -06:00
|
|
|
st.msg_block_idx += 1u;
|
|
|
|
}
|
2011-06-15 13:19:50 -05:00
|
|
|
|
2011-08-23 15:22:44 -05:00
|
|
|
// Store the message length as the last 8 octets
|
2011-08-19 17:16:48 -05:00
|
|
|
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;
|
2011-02-20 23:56:09 -06:00
|
|
|
process_msg_block(st);
|
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
obj sha1(st: sha1state) {
|
2011-02-20 23:56:09 -06:00
|
|
|
fn reset() {
|
|
|
|
// FIXME: Should be typestate precondition
|
2011-08-15 18:38:23 -05:00
|
|
|
assert (vec::len(st.h) == digest_buf_len);
|
2011-02-20 23:56:09 -06:00
|
|
|
st.len_low = 0u32;
|
|
|
|
st.len_high = 0u32;
|
|
|
|
st.msg_block_idx = 0u;
|
2011-08-19 17:16:48 -05:00
|
|
|
st.h[0] = 0x67452301u32;
|
|
|
|
st.h[1] = 0xEFCDAB89u32;
|
|
|
|
st.h[2] = 0x98BADCFEu32;
|
|
|
|
st.h[3] = 0x10325476u32;
|
|
|
|
st.h[4] = 0xC3D2E1F0u32;
|
2011-02-20 23:56:09 -06:00
|
|
|
st.computed = false;
|
|
|
|
}
|
2011-09-12 04:27:30 -05:00
|
|
|
fn input(msg: [u8]) { add_input(st, msg); }
|
|
|
|
fn input_str(msg: str) { add_input(st, str::bytes(msg)); }
|
2011-08-12 01:54:26 -05:00
|
|
|
fn result() -> [u8] { ret mk_result(st); }
|
2011-09-02 17:34:58 -05:00
|
|
|
fn result_str() -> str {
|
2011-07-27 07:19:39 -05:00
|
|
|
let r = mk_result(st);
|
2011-09-02 17:34:58 -05:00
|
|
|
let s = "";
|
|
|
|
for b: u8 in r { s += uint::to_str(b as uint, 16u); }
|
2011-03-26 19:36:08 -05:00
|
|
|
ret s;
|
|
|
|
}
|
2011-02-20 23:56:09 -06:00
|
|
|
}
|
2011-07-27 07:19:39 -05:00
|
|
|
let st =
|
2011-08-12 12:56:57 -05:00
|
|
|
{h: vec::init_elt_mut::<u32>(0u32, digest_buf_len),
|
2011-07-27 07:19:39 -05:00
|
|
|
mutable len_low: 0u32,
|
|
|
|
mutable len_high: 0u32,
|
2011-08-12 12:56:57 -05:00
|
|
|
msg_block: vec::init_elt_mut::<u8>(0u8, msg_block_len),
|
2011-07-27 07:19:39 -05:00
|
|
|
mutable msg_block_idx: 0u,
|
|
|
|
mutable computed: false,
|
2011-08-12 12:56:57 -05:00
|
|
|
work_buf: vec::init_elt_mut::<u32>(0u32, work_buf_len)};
|
2011-07-27 07:19:39 -05:00
|
|
|
let sh = sha1(st);
|
2011-02-20 23:56:09 -06:00
|
|
|
sh.reset();
|
|
|
|
ret sh;
|
|
|
|
}
|
2011-08-23 15:22:44 -05:00
|
|
|
|
2011-02-20 23:56:09 -06:00
|
|
|
// Local Variables:
|
|
|
|
// mode: rust;
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
2011-06-15 14:01:19 -05:00
|
|
|
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
|
2011-02-20 23:56:09 -06:00
|
|
|
// End:
|