OLD | NEW |
(Empty) | |
| 1 // Copyright 2013 The Go Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style |
| 3 // license that can be found in the LICENSE file. |
| 4 package hkdf |
| 5 |
| 6 import ( |
| 7 "bytes" |
| 8 "crypto/md5" |
| 9 "crypto/sha1" |
| 10 "crypto/sha256" |
| 11 "crypto/sha512" |
| 12 "hash" |
| 13 "io" |
| 14 "testing" |
| 15 ) |
| 16 |
| 17 type hkdfTest struct { |
| 18 hash func() hash.Hash |
| 19 master []byte |
| 20 salt []byte |
| 21 info []byte |
| 22 out []byte |
| 23 } |
| 24 |
| 25 var hkdfTests = []hkdfTest{ |
| 26 // Tests from RFC 5869 |
| 27 { |
| 28 sha256.New, |
| 29 []byte{ |
| 30 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 31 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 32 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 33 }, |
| 34 []byte{ |
| 35 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 36 0x08, 0x09, 0x0a, 0x0b, 0x0c, |
| 37 }, |
| 38 []byte{ |
| 39 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, |
| 40 0xf8, 0xf9, |
| 41 }, |
| 42 []byte{ |
| 43 0x3c, 0xb2, 0x5f, 0x25, 0xfa, 0xac, 0xd5, 0x7a, |
| 44 0x90, 0x43, 0x4f, 0x64, 0xd0, 0x36, 0x2f, 0x2a, |
| 45 0x2d, 0x2d, 0x0a, 0x90, 0xcf, 0x1a, 0x5a, 0x4c, |
| 46 0x5d, 0xb0, 0x2d, 0x56, 0xec, 0xc4, 0xc5, 0xbf, |
| 47 0x34, 0x00, 0x72, 0x08, 0xd5, 0xb8, 0x87, 0x18, |
| 48 0x58, 0x65, |
| 49 }, |
| 50 }, |
| 51 { |
| 52 sha256.New, |
| 53 []byte{ |
| 54 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 55 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 56 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 57 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| 58 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
| 59 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, |
| 60 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
| 61 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, |
| 62 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, |
| 63 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, |
| 64 }, |
| 65 []byte{ |
| 66 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, |
| 67 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, |
| 68 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, |
| 69 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, |
| 70 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, |
| 71 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, |
| 72 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, |
| 73 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, |
| 74 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, |
| 75 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, |
| 76 }, |
| 77 []byte{ |
| 78 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, |
| 79 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, |
| 80 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, |
| 81 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, |
| 82 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, |
| 83 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, |
| 84 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, |
| 85 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, |
| 86 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, |
| 87 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, |
| 88 }, |
| 89 []byte{ |
| 90 0xb1, 0x1e, 0x39, 0x8d, 0xc8, 0x03, 0x27, 0xa1, |
| 91 0xc8, 0xe7, 0xf7, 0x8c, 0x59, 0x6a, 0x49, 0x34, |
| 92 0x4f, 0x01, 0x2e, 0xda, 0x2d, 0x4e, 0xfa, 0xd8, |
| 93 0xa0, 0x50, 0xcc, 0x4c, 0x19, 0xaf, 0xa9, 0x7c, |
| 94 0x59, 0x04, 0x5a, 0x99, 0xca, 0xc7, 0x82, 0x72, |
| 95 0x71, 0xcb, 0x41, 0xc6, 0x5e, 0x59, 0x0e, 0x09, |
| 96 0xda, 0x32, 0x75, 0x60, 0x0c, 0x2f, 0x09, 0xb8, |
| 97 0x36, 0x77, 0x93, 0xa9, 0xac, 0xa3, 0xdb, 0x71, |
| 98 0xcc, 0x30, 0xc5, 0x81, 0x79, 0xec, 0x3e, 0x87, |
| 99 0xc1, 0x4c, 0x01, 0xd5, 0xc1, 0xf3, 0x43, 0x4f, |
| 100 0x1d, 0x87, |
| 101 }, |
| 102 }, |
| 103 { |
| 104 sha256.New, |
| 105 []byte{ |
| 106 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 107 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 108 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 109 }, |
| 110 []byte{}, |
| 111 []byte{}, |
| 112 []byte{ |
| 113 0x8d, 0xa4, 0xe7, 0x75, 0xa5, 0x63, 0xc1, 0x8f, |
| 114 0x71, 0x5f, 0x80, 0x2a, 0x06, 0x3c, 0x5a, 0x31, |
| 115 0xb8, 0xa1, 0x1f, 0x5c, 0x5e, 0xe1, 0x87, 0x9e, |
| 116 0xc3, 0x45, 0x4e, 0x5f, 0x3c, 0x73, 0x8d, 0x2d, |
| 117 0x9d, 0x20, 0x13, 0x95, 0xfa, 0xa4, 0xb6, 0x1a, |
| 118 0x96, 0xc8, |
| 119 }, |
| 120 }, |
| 121 { |
| 122 sha1.New, |
| 123 []byte{ |
| 124 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 125 0x0b, 0x0b, 0x0b, |
| 126 }, |
| 127 []byte{ |
| 128 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 129 0x08, 0x09, 0x0a, 0x0b, 0x0c, |
| 130 }, |
| 131 []byte{ |
| 132 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, |
| 133 0xf8, 0xf9, |
| 134 }, |
| 135 []byte{ |
| 136 0x08, 0x5a, 0x01, 0xea, 0x1b, 0x10, 0xf3, 0x69, |
| 137 0x33, 0x06, 0x8b, 0x56, 0xef, 0xa5, 0xad, 0x81, |
| 138 0xa4, 0xf1, 0x4b, 0x82, 0x2f, 0x5b, 0x09, 0x15, |
| 139 0x68, 0xa9, 0xcd, 0xd4, 0xf1, 0x55, 0xfd, 0xa2, |
| 140 0xc2, 0x2e, 0x42, 0x24, 0x78, 0xd3, 0x05, 0xf3, |
| 141 0xf8, 0x96, |
| 142 }, |
| 143 }, |
| 144 { |
| 145 sha1.New, |
| 146 []byte{ |
| 147 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
| 148 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
| 149 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
| 150 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
| 151 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, |
| 152 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, |
| 153 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, |
| 154 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, |
| 155 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, |
| 156 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, |
| 157 }, |
| 158 []byte{ |
| 159 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, |
| 160 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, |
| 161 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, |
| 162 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, |
| 163 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, |
| 164 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, |
| 165 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, |
| 166 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, |
| 167 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, |
| 168 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, |
| 169 }, |
| 170 []byte{ |
| 171 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, |
| 172 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, |
| 173 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, |
| 174 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, |
| 175 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, |
| 176 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, |
| 177 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, |
| 178 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, |
| 179 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, |
| 180 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, |
| 181 }, |
| 182 []byte{ |
| 183 0x0b, 0xd7, 0x70, 0xa7, 0x4d, 0x11, 0x60, 0xf7, |
| 184 0xc9, 0xf1, 0x2c, 0xd5, 0x91, 0x2a, 0x06, 0xeb, |
| 185 0xff, 0x6a, 0xdc, 0xae, 0x89, 0x9d, 0x92, 0x19, |
| 186 0x1f, 0xe4, 0x30, 0x56, 0x73, 0xba, 0x2f, 0xfe, |
| 187 0x8f, 0xa3, 0xf1, 0xa4, 0xe5, 0xad, 0x79, 0xf3, |
| 188 0xf3, 0x34, 0xb3, 0xb2, 0x02, 0xb2, 0x17, 0x3c, |
| 189 0x48, 0x6e, 0xa3, 0x7c, 0xe3, 0xd3, 0x97, 0xed, |
| 190 0x03, 0x4c, 0x7f, 0x9d, 0xfe, 0xb1, 0x5c, 0x5e, |
| 191 0x92, 0x73, 0x36, 0xd0, 0x44, 0x1f, 0x4c, 0x43, |
| 192 0x00, 0xe2, 0xcf, 0xf0, 0xd0, 0x90, 0x0b, 0x52, |
| 193 0xd3, 0xb4, |
| 194 }, |
| 195 }, |
| 196 { |
| 197 sha1.New, |
| 198 []byte{ |
| 199 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 200 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 201 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, |
| 202 }, |
| 203 []byte{}, |
| 204 []byte{}, |
| 205 []byte{ |
| 206 0x0a, 0xc1, 0xaf, 0x70, 0x02, 0xb3, 0xd7, 0x61, |
| 207 0xd1, 0xe5, 0x52, 0x98, 0xda, 0x9d, 0x05, 0x06, |
| 208 0xb9, 0xae, 0x52, 0x05, 0x72, 0x20, 0xa3, 0x06, |
| 209 0xe0, 0x7b, 0x6b, 0x87, 0xe8, 0xdf, 0x21, 0xd0, |
| 210 0xea, 0x00, 0x03, 0x3d, 0xe0, 0x39, 0x84, 0xd3, |
| 211 0x49, 0x18, |
| 212 }, |
| 213 }, |
| 214 { |
| 215 sha1.New, |
| 216 []byte{ |
| 217 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, |
| 218 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, |
| 219 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, |
| 220 }, |
| 221 nil, |
| 222 []byte{}, |
| 223 []byte{ |
| 224 0x2c, 0x91, 0x11, 0x72, 0x04, 0xd7, 0x45, 0xf3, |
| 225 0x50, 0x0d, 0x63, 0x6a, 0x62, 0xf6, 0x4f, 0x0a, |
| 226 0xb3, 0xba, 0xe5, 0x48, 0xaa, 0x53, 0xd4, 0x23, |
| 227 0xb0, 0xd1, 0xf2, 0x7e, 0xbb, 0xa6, 0xf5, 0xe5, |
| 228 0x67, 0x3a, 0x08, 0x1d, 0x70, 0xcc, 0xe7, 0xac, |
| 229 0xfc, 0x48, |
| 230 }, |
| 231 }, |
| 232 } |
| 233 |
| 234 func TestHKDF(t *testing.T) { |
| 235 for i, tt := range hkdfTests { |
| 236 hkdf := New(tt.hash, tt.master, tt.salt, tt.info) |
| 237 out := make([]byte, len(tt.out)) |
| 238 |
| 239 n, err := io.ReadFull(hkdf, out) |
| 240 if n != len(tt.out) || err != nil { |
| 241 t.Errorf("test %d: not enough output bytes: %d.", i, n) |
| 242 } |
| 243 |
| 244 if !bytes.Equal(out, tt.out) { |
| 245 t.Errorf("test %d: incorrect output: have %v, need %v.",
i, out, tt.out) |
| 246 } |
| 247 } |
| 248 } |
| 249 |
| 250 func TestHKDFMultiRead(t *testing.T) { |
| 251 for i, tt := range hkdfTests { |
| 252 hkdf := New(tt.hash, tt.master, tt.salt, tt.info) |
| 253 out := make([]byte, len(tt.out)) |
| 254 |
| 255 for b := 0; b < len(tt.out); b++ { |
| 256 n, err := io.ReadFull(hkdf, out[b:b+1]) |
| 257 if n != 1 || err != nil { |
| 258 t.Errorf("test %d.%d: not enough output bytes: h
ave %d, need %d .", i, b, n, len(tt.out)) |
| 259 } |
| 260 } |
| 261 |
| 262 if !bytes.Equal(out, tt.out) { |
| 263 t.Errorf("test %d: incorrect output: have %v, need %v.",
i, out, tt.out) |
| 264 } |
| 265 } |
| 266 } |
| 267 |
| 268 func TestHKDFLimit(t *testing.T) { |
| 269 hash := sha1.New |
| 270 master := []byte{0x00, 0x01, 0x02, 0x03} |
| 271 info := []byte{} |
| 272 |
| 273 hkdf := New(hash, master, nil, info) |
| 274 limit := hash().Size() * 255 |
| 275 out := make([]byte, limit) |
| 276 |
| 277 // The maximum output bytes should be extractable |
| 278 n, err := io.ReadFull(hkdf, out) |
| 279 if n != limit || err != nil { |
| 280 t.Errorf("not enough output bytes: %d, %v.", n, err) |
| 281 } |
| 282 |
| 283 // Reading one more should fail |
| 284 n, err = io.ReadFull(hkdf, make([]byte, 1)) |
| 285 if n > 0 || err == nil { |
| 286 t.Errorf("key expansion overflowed: n = %d, err = %v", n, err) |
| 287 } |
| 288 } |
| 289 |
| 290 func Benchmark16ByteMd5Single(b *testing.B) { |
| 291 benchmarkHKDFSingle(md5.New, 16, b) |
| 292 } |
| 293 |
| 294 func Benchmark20ByteSha1Single(b *testing.B) { |
| 295 benchmarkHKDFSingle(sha1.New, 20, b) |
| 296 } |
| 297 |
| 298 func Benchmark32ByteSha256Single(b *testing.B) { |
| 299 benchmarkHKDFSingle(sha256.New, 32, b) |
| 300 } |
| 301 |
| 302 func Benchmark64ByteSha512Single(b *testing.B) { |
| 303 benchmarkHKDFSingle(sha512.New, 64, b) |
| 304 } |
| 305 |
| 306 func Benchmark8ByteMd5Stream(b *testing.B) { |
| 307 benchmarkHKDFStream(md5.New, 8, b) |
| 308 } |
| 309 |
| 310 func Benchmark16ByteMd5Stream(b *testing.B) { |
| 311 benchmarkHKDFStream(md5.New, 16, b) |
| 312 } |
| 313 |
| 314 func Benchmark8ByteSha1Stream(b *testing.B) { |
| 315 benchmarkHKDFStream(sha1.New, 8, b) |
| 316 } |
| 317 |
| 318 func Benchmark20ByteSha1Stream(b *testing.B) { |
| 319 benchmarkHKDFStream(sha1.New, 20, b) |
| 320 } |
| 321 |
| 322 func Benchmark8ByteSha256Stream(b *testing.B) { |
| 323 benchmarkHKDFStream(sha256.New, 8, b) |
| 324 } |
| 325 |
| 326 func Benchmark32ByteSha256Stream(b *testing.B) { |
| 327 benchmarkHKDFStream(sha256.New, 32, b) |
| 328 } |
| 329 |
| 330 func Benchmark8ByteSha512Stream(b *testing.B) { |
| 331 benchmarkHKDFStream(sha512.New, 8, b) |
| 332 } |
| 333 |
| 334 func Benchmark64ByteSha512Stream(b *testing.B) { |
| 335 benchmarkHKDFStream(sha512.New, 64, b) |
| 336 } |
| 337 |
| 338 func benchmarkHKDFSingle(hasher func() hash.Hash, block int, b *testing.B) { |
| 339 master := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07} |
| 340 salt := []byte{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17} |
| 341 info := []byte{0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27} |
| 342 out := make([]byte, block) |
| 343 |
| 344 b.SetBytes(int64(block)) |
| 345 b.ResetTimer() |
| 346 |
| 347 for i := 0; i < b.N; i++ { |
| 348 hkdf := New(hasher, master, salt, info) |
| 349 io.ReadFull(hkdf, out) |
| 350 } |
| 351 } |
| 352 |
| 353 func benchmarkHKDFStream(hasher func() hash.Hash, block int, b *testing.B) { |
| 354 master := []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07} |
| 355 salt := []byte{0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17} |
| 356 info := []byte{0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27} |
| 357 out := make([]byte, block) |
| 358 |
| 359 b.SetBytes(int64(block)) |
| 360 b.ResetTimer() |
| 361 |
| 362 hkdf := New(hasher, master, salt, info) |
| 363 for i := 0; i < b.N; i++ { |
| 364 _, err := io.ReadFull(hkdf, out) |
| 365 if err != nil { |
| 366 hkdf = New(hasher, master, salt, info) |
| 367 i-- |
| 368 } |
| 369 } |
| 370 } |
OLD | NEW |