crypto.hmac: implement hmac.equal/2 too
							parent
							
								
									9355c60b4d
								
							
						
					
					
						commit
						d1e52620c7
					
				|  | @ -2,6 +2,8 @@ | |||
| // implementation based on https://tools.ietf.org/html/rfc2104
 | ||||
| module hmac | ||||
| 
 | ||||
| import crypto.internal.subtle | ||||
| 
 | ||||
| const ( | ||||
| 	ipad = []byte{len: 256, init: 0x36} // TODO is 256 enough??
 | ||||
| 	opad = []byte{len: 256, init: 0x5C} | ||||
|  | @ -33,3 +35,10 @@ pub fn new(key, data []byte, hash_func fn (bytes []byte) []byte, blocksize int) | |||
| 	digest := hash_func(outer) | ||||
| 	return digest | ||||
| } | ||||
| 
 | ||||
| // equal compares 2 MACs for equality, without leaking timing info
 | ||||
| // NB: if the lengths of the 2 MACs are different, probably a completely different
 | ||||
| // hash function was used to generate them => no useful timing information.
 | ||||
| pub fn equal(mac1, mac2 []byte) bool { | ||||
| 	return subtle.constant_time_compare(mac1, mac2) == 1 | ||||
| } | ||||
|  |  | |||
|  | @ -152,6 +152,17 @@ fn test_hmac_sha512() { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn test_hmac_equal() { | ||||
| 	mac1_1 := '7641c48a3b4aa8f887c07b3e83f96affb89c978fed8c96fcbbf4ad596eebfe496f9f16da6cd080ba393c6f365ad72b50d15c71bfb1d6b81f66a911786c6ce932'.bytes() | ||||
| 	mac1_2 := '7641c48a3b4aa8f887c07b3e83f96affb89c978fed8c96fcbbf4ad596eebfe496f9f16da6cd080ba393c6f365ad72b50d15c71bfb1d6b81f66a911786c6ce932'.bytes() | ||||
| 	mac2_1 := '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737'.bytes() | ||||
| 	mac2_2 := '164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737'.bytes() | ||||
| 	assert hmac.equal(mac1_1, mac1_2) | ||||
| 	assert hmac.equal(mac2_1, mac2_2) | ||||
| 	assert !hmac.equal(mac1_1, mac2_1) | ||||
| 	assert !hmac.equal(mac1_1, mac2_2) | ||||
| } | ||||
| 
 | ||||
| // not yet supported by crypto module
 | ||||
| // sha3_224_expected_results  := [
 | ||||
| // 'f68da7f7bf577de799bb1224b7acfef9e8de015a63475ed5904a4693'
 | ||||
|  |  | |||
|  | @ -0,0 +1,53 @@ | |||
| module subtle | ||||
| 
 | ||||
| // constant_time_byte_eq returns 1 when x == y.
 | ||||
| pub fn constant_time_byte_eq(x, y byte) int { | ||||
| 	return int((u32(x ^ y) - 1) >> 31) | ||||
| } | ||||
| 
 | ||||
| // constant_time_eq returns 1 when x == y.
 | ||||
| pub fn constant_time_eq(x, y int) int { | ||||
| 	return int((u64(u32(x ^ y)) - 1) >> 63) | ||||
| } | ||||
| 
 | ||||
| // constant_time_select returns x when v == 1, and y when v == 0.
 | ||||
| // it is undefined when v is any other value
 | ||||
| pub fn constant_time_select(v, x, y int) int { | ||||
| 	return (~(v - 1) & x) | ((v - 1) & y) | ||||
| } | ||||
| 
 | ||||
| // constant_time_compare returns 1 when x and y have equal contents.
 | ||||
| // The runtime of this function is proportional of the length of x and y.
 | ||||
| // It is *NOT* dependent on their content.
 | ||||
| pub fn constant_time_compare(x, y []byte) int { | ||||
| 	if x.len != y.len { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	mut v := byte(0) | ||||
| 	for i in 0 .. x.len { | ||||
| 		v |= x[i] ^ y[i] | ||||
| 	} | ||||
| 	return constant_time_byte_eq(v, 0) | ||||
| } | ||||
| 
 | ||||
| // constant_time_copy copies the contents of y into x, when v == 1.
 | ||||
| // When v == 0, x is left unchanged. this function is undefined, when
 | ||||
| // v takes any other value
 | ||||
| pub fn constant_time_copy(v int, mut x []byte, y []byte) { | ||||
| 	if x.len != y.len { | ||||
| 		panic('subtle: arrays have different lengths') | ||||
| 	} | ||||
| 	xmask := byte(v - 1) | ||||
| 	ymask := byte(~(v - 1)) | ||||
| 	for i := 0; i < x.len; i++ { | ||||
| 		x[i] = x[i] & xmask | y[i] & ymask | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // constant_time_less_or_eq returns 1 if x <= y, and 0 otherwise.
 | ||||
| // it is undefined when x or y are negative, or > (2^32 - 1)
 | ||||
| pub fn constant_time_less_or_eq(x, y int) int { | ||||
| 	x32 := int(x) | ||||
| 	y32 := int(y) | ||||
| 	return int(((x32 - y32 - 1) >> 31) & 1) | ||||
| } | ||||
|  | @ -0,0 +1,65 @@ | |||
| module subtle | ||||
| 
 | ||||
| fn test_constant_time_byte_eq() { | ||||
| 	assert constant_time_byte_eq(0, 0) == 1 | ||||
| 	assert constant_time_byte_eq(1, 1) == 1 | ||||
| 	assert constant_time_byte_eq(255, 255) == 1 | ||||
| 	assert constant_time_byte_eq(255, 1) == 0 | ||||
| 	assert constant_time_byte_eq(1, 255) == 0 | ||||
| 	assert constant_time_byte_eq(2, 1) == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_constant_time_eq() { | ||||
| 	assert constant_time_eq(0, 0) == 1 | ||||
| 	assert constant_time_eq(255, 255) == 1 | ||||
| 	assert constant_time_eq(65536, 65536) == 1 | ||||
| 	assert constant_time_eq(-1, -1) == 1 | ||||
| 	assert constant_time_eq(-256, -256) == 1 | ||||
| 	assert constant_time_eq(0, 1) == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_constant_time_select() { | ||||
| 	assert constant_time_select(1, 1, 0) == 1 | ||||
| 	assert constant_time_select(1, 1, 255) == 1 | ||||
| 	assert constant_time_select(1, 1, 255 * 255) == 1 | ||||
| 	assert constant_time_select(1, 2, 0) == 2 | ||||
| 	assert constant_time_select(1, 2, 255) == 2 | ||||
| 	assert constant_time_select(1, 2, 255 * 255) == 2 | ||||
| 	//
 | ||||
| 	assert constant_time_select(0, 1, 0) == 0 | ||||
| 	assert constant_time_select(0, 1, 255) == 255 | ||||
| 	assert constant_time_select(0, 1, 255 * 255) == 255 * 255 | ||||
| 	assert constant_time_select(0, 2, 0) == 0 | ||||
| 	assert constant_time_select(0, 2, 255) == 255 | ||||
| 	assert constant_time_select(0, 2, 255 * 255) == 255 * 255 | ||||
| } | ||||
| 
 | ||||
| fn test_constant_time_compare() { | ||||
| 	assert constant_time_compare([byte(1), 2, 3], [byte(1), 2, 3]) == 1 | ||||
| 	assert constant_time_compare([byte(1), 2, 3], [byte(1), 2, 9]) == 0 | ||||
| 	assert constant_time_compare([byte(1), 2, 3], [byte(1), 2, 3, 4]) == 0 | ||||
| 	assert constant_time_compare([byte(1), 2, 3], [byte(1), 2]) == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_constant_time_copy() { | ||||
| 	y := [byte(3), 4, 5] | ||||
| 	mut x := [byte(0), 0, 0] | ||||
| 	constant_time_copy(0, mut x, y) | ||||
| 	assert x == [byte(0), 0, 0] | ||||
| 	constant_time_copy(1, mut x, y) | ||||
| 	assert x == y | ||||
| 	assert x == [byte(3), 4, 5] | ||||
| } | ||||
| 
 | ||||
| fn test_constant_time_less_or_eq() { | ||||
| 	assert constant_time_less_or_eq(1, 1) == 1 | ||||
| 	assert constant_time_less_or_eq(1, 2) == 1 | ||||
| 	assert constant_time_less_or_eq(1, 3) == 1 | ||||
| 	assert constant_time_less_or_eq(255, 255) == 1 | ||||
| 	assert constant_time_less_or_eq(255, 256) == 1 | ||||
| 	assert constant_time_less_or_eq(255, 257) == 1 | ||||
| 	assert constant_time_less_or_eq(1, 0) == 0 | ||||
| 	assert constant_time_less_or_eq(2, 1) == 0 | ||||
| 	assert constant_time_less_or_eq(3, 2) == 0 | ||||
| 	assert constant_time_less_or_eq(255, 3) == 0 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue