Skip to content

Commit ce5cb03

Browse files
committed
runtime: use some startup randomness in the fallback hashes
Fold in some startup randomness to make the hash vary across different runs. This helps prevent attackers from choosing keys that all map to the same bucket. Also, reorganize the hash a bit. Move the *m1 multiply to after the xor of the current hash and the message. For hash quality it doesn't really matter, but for DDOS resistance it helps a lot (any processing done to the message before it is merged with the random seed is useless, as it is easily inverted by an attacker). Update #9365 Change-Id: Ib19968168e1bbc541d1d28be2701bb83e53f1e24 Reviewed-on: https://go-review.googlesource.com/2344 Reviewed-by: Ian Lance Taylor <[email protected]>
1 parent 31775c5 commit ce5cb03

File tree

3 files changed

+75
-82
lines changed

3 files changed

+75
-82
lines changed

src/runtime/alg.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -285,20 +285,21 @@ func memclrBytes(b []byte) {
285285
memclr(s.array, uintptr(s.len))
286286
}
287287

288-
// used in asm_{386,amd64}.s
289288
const hashRandomBytes = ptrSize / 4 * 64
290289

290+
// used in asm_{386,amd64}.s to seed the hash function
291291
var aeskeysched [hashRandomBytes]byte
292292

293-
func init() {
294-
if GOOS == "nacl" {
295-
return
296-
}
293+
// used in hash{32,64}.go to seed the hash function
294+
var hashkey [4]uintptr
297295

296+
func init() {
298297
// Install aes hash algorithm if we have the instructions we need
299-
if (cpuid_ecx&(1<<25)) != 0 && // aes (aesenc)
300-
(cpuid_ecx&(1<<9)) != 0 && // sse3 (pshufb)
301-
(cpuid_ecx&(1<<19)) != 0 { // sse4.1 (pinsr{d,q})
298+
if (GOARCH == "386" || GOARCH == "amd64") &&
299+
GOOS != "nacl" &&
300+
cpuid_ecx&(1<<25) != 0 && // aes (aesenc)
301+
cpuid_ecx&(1<<9) != 0 && // sse3 (pshufb)
302+
cpuid_ecx&(1<<19) != 0 { // sse4.1 (pinsr{d,q})
302303
useAeshash = true
303304
algarray[alg_MEM].hash = aeshash
304305
algarray[alg_MEM8].hash = aeshash
@@ -309,5 +310,8 @@ func init() {
309310
algarray[alg_STRING].hash = aeshashstr
310311
// Initialize with random data so hash collisions will be hard to engineer.
311312
getRandomData(aeskeysched[:])
313+
return
312314
}
315+
getRandomData((*[len(hashkey) * ptrSize]byte)(unsafe.Pointer(&hashkey))[:])
316+
hashkey[0] |= 1 // make sure this number is odd
313317
}

src/runtime/hash32.go

Lines changed: 31 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,54 +24,53 @@ func memhash(p unsafe.Pointer, s, seed uintptr) uintptr {
2424
if GOARCH == "386" && GOOS != "nacl" && useAeshash {
2525
return aeshash(p, s, seed)
2626
}
27-
h := uint32(seed + s)
27+
h := uint32(seed + s*hashkey[0])
2828
tail:
2929
switch {
3030
case s == 0:
3131
case s < 4:
32-
w := uint32(*(*byte)(p))
33-
w += uint32(*(*byte)(add(p, s>>1))) << 8
34-
w += uint32(*(*byte)(add(p, s-1))) << 16
35-
h ^= w * m1
32+
h ^= uint32(*(*byte)(p))
33+
h ^= uint32(*(*byte)(add(p, s>>1))) << 8
34+
h ^= uint32(*(*byte)(add(p, s-1))) << 16
35+
h = rotl_15(h*m1) * m2
3636
case s == 4:
37-
h ^= readUnaligned32(p) * m1
37+
h ^= readUnaligned32(p)
38+
h = rotl_15(h*m1) * m2
3839
case s <= 8:
39-
h ^= readUnaligned32(p) * m1
40-
h = rotl_15(h) * m2
41-
h = rotl_11(h)
42-
h ^= readUnaligned32(add(p, s-4)) * m1
40+
h ^= readUnaligned32(p)
41+
h = rotl_15(h*m1) * m2
42+
h ^= readUnaligned32(add(p, s-4))
43+
h = rotl_15(h*m1) * m2
4344
case s <= 16:
44-
h ^= readUnaligned32(p) * m1
45-
h = rotl_15(h) * m2
46-
h = rotl_11(h)
47-
h ^= readUnaligned32(add(p, 4)) * m1
48-
h = rotl_15(h) * m2
49-
h = rotl_11(h)
50-
h ^= readUnaligned32(add(p, s-8)) * m1
51-
h = rotl_15(h) * m2
52-
h = rotl_11(h)
53-
h ^= readUnaligned32(add(p, s-4)) * m1
45+
h ^= readUnaligned32(p)
46+
h = rotl_15(h*m1) * m2
47+
h ^= readUnaligned32(add(p, 4))
48+
h = rotl_15(h*m1) * m2
49+
h ^= readUnaligned32(add(p, s-8))
50+
h = rotl_15(h*m1) * m2
51+
h ^= readUnaligned32(add(p, s-4))
52+
h = rotl_15(h*m1) * m2
5453
default:
5554
v1 := h
56-
v2 := h + m1
57-
v3 := h + m2
58-
v4 := h + m3
55+
v2 := uint32(hashkey[1])
56+
v3 := uint32(hashkey[2])
57+
v4 := uint32(hashkey[3])
5958
for s >= 16 {
60-
v1 ^= readUnaligned32(p) * m1
61-
v1 = rotl_15(v1) * m2
59+
v1 ^= readUnaligned32(p)
60+
v1 = rotl_15(v1*m1) * m2
6261
p = add(p, 4)
63-
v2 ^= readUnaligned32(p) * m1
64-
v2 = rotl_15(v2) * m2
62+
v2 ^= readUnaligned32(p)
63+
v2 = rotl_15(v2*m2) * m3
6564
p = add(p, 4)
66-
v3 ^= readUnaligned32(p) * m1
67-
v3 = rotl_15(v3) * m2
65+
v3 ^= readUnaligned32(p)
66+
v3 = rotl_15(v3*m3) * m4
6867
p = add(p, 4)
69-
v4 ^= readUnaligned32(p) * m1
70-
v4 = rotl_15(v4) * m2
68+
v4 ^= readUnaligned32(p)
69+
v4 = rotl_15(v4*m4) * m1
7170
p = add(p, 4)
7271
s -= 16
7372
}
74-
h = rotl_11(v1)*m1 + rotl_11(v2)*m2 + rotl_11(v3)*m3 + rotl_11(v4)*m4
73+
h = v1 ^ v2 ^ v3 ^ v4
7574
goto tail
7675
}
7776
h ^= h >> 17
@@ -88,6 +87,3 @@ tail:
8887
func rotl_15(x uint32) uint32 {
8988
return (x << 15) | (x >> (32 - 15))
9089
}
91-
func rotl_11(x uint32) uint32 {
92-
return (x << 11) | (x >> (32 - 11))
93-
}

src/runtime/hash64.go

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -24,61 +24,57 @@ func memhash(p unsafe.Pointer, s, seed uintptr) uintptr {
2424
if GOARCH == "amd64" && GOOS != "nacl" && useAeshash {
2525
return aeshash(p, s, seed)
2626
}
27-
h := uint64(seed + s)
27+
h := uint64(seed + s*hashkey[0])
2828
tail:
2929
switch {
3030
case s == 0:
3131
case s < 4:
32-
w := uint64(*(*byte)(p))
33-
w += uint64(*(*byte)(add(p, s>>1))) << 8
34-
w += uint64(*(*byte)(add(p, s-1))) << 16
35-
h ^= w * m1
32+
h ^= uint64(*(*byte)(p))
33+
h ^= uint64(*(*byte)(add(p, s>>1))) << 8
34+
h ^= uint64(*(*byte)(add(p, s-1))) << 16
35+
h = rotl_31(h*m1) * m2
3636
case s <= 8:
37-
w := uint64(readUnaligned32(p))
38-
w += uint64(readUnaligned32(add(p, s-4))) << 32
39-
h ^= w * m1
37+
h ^= uint64(readUnaligned32(p))
38+
h ^= uint64(readUnaligned32(add(p, s-4))) << 32
39+
h = rotl_31(h*m1) * m2
4040
case s <= 16:
41-
h ^= readUnaligned64(p) * m1
42-
h = rotl_31(h) * m2
43-
h = rotl_27(h)
44-
h ^= readUnaligned64(add(p, s-8)) * m1
41+
h ^= readUnaligned64(p)
42+
h = rotl_31(h*m1) * m2
43+
h ^= readUnaligned64(add(p, s-8))
44+
h = rotl_31(h*m1) * m2
4545
case s <= 32:
46-
h ^= readUnaligned64(p) * m1
47-
h = rotl_31(h) * m2
48-
h = rotl_27(h)
49-
h ^= readUnaligned64(add(p, 8)) * m1
50-
h = rotl_31(h) * m2
51-
h = rotl_27(h)
52-
h ^= readUnaligned64(add(p, s-16)) * m1
53-
h = rotl_31(h) * m2
54-
h = rotl_27(h)
55-
h ^= readUnaligned64(add(p, s-8)) * m1
46+
h ^= readUnaligned64(p)
47+
h = rotl_31(h*m1) * m2
48+
h ^= readUnaligned64(add(p, 8))
49+
h = rotl_31(h*m1) * m2
50+
h ^= readUnaligned64(add(p, s-16))
51+
h = rotl_31(h*m1) * m2
52+
h ^= readUnaligned64(add(p, s-8))
53+
h = rotl_31(h*m1) * m2
5654
default:
5755
v1 := h
58-
v2 := h + m1
59-
v3 := h + m2
60-
v4 := h + m3
56+
v2 := uint64(hashkey[1])
57+
v3 := uint64(hashkey[2])
58+
v4 := uint64(hashkey[3])
6159
for s >= 32 {
62-
v1 ^= readUnaligned64(p) * m1
63-
v1 = rotl_31(v1) * m2
60+
v1 ^= readUnaligned64(p)
61+
v1 = rotl_31(v1*m1) * m2
6462
p = add(p, 8)
65-
v2 ^= readUnaligned64(p) * m1
66-
v2 = rotl_31(v2) * m2
63+
v2 ^= readUnaligned64(p)
64+
v2 = rotl_31(v2*m2) * m3
6765
p = add(p, 8)
68-
v3 ^= readUnaligned64(p) * m1
69-
v3 = rotl_31(v3) * m2
66+
v3 ^= readUnaligned64(p)
67+
v3 = rotl_31(v3*m3) * m4
7068
p = add(p, 8)
71-
v4 ^= readUnaligned64(p) * m1
72-
v4 = rotl_31(v4) * m2
69+
v4 ^= readUnaligned64(p)
70+
v4 = rotl_31(v4*m4) * m1
7371
p = add(p, 8)
7472
s -= 32
7573
}
76-
h = rotl_27(v1)*m1 + rotl_27(v2)*m2 + rotl_27(v3)*m3 + rotl_27(v4)*m4
74+
h = v1 ^ v2 ^ v3 ^ v4
7775
goto tail
7876
}
7977

80-
h ^= h >> 33
81-
h *= m2
8278
h ^= h >> 29
8379
h *= m3
8480
h ^= h >> 32
@@ -91,6 +87,3 @@ tail:
9187
func rotl_31(x uint64) uint64 {
9288
return (x << 31) | (x >> (64 - 31))
9389
}
94-
func rotl_27(x uint64) uint64 {
95-
return (x << 27) | (x >> (64 - 27))
96-
}

0 commit comments

Comments
 (0)