1// Copyright (c) 2016 Thomas Pornin <pornin@bolet.org> 2// Copyright (c) 2017 Yawning Angel <yawning at schwanenlied dot me> 3// 4// Permission is hereby granted, free of charge, to any person obtaining 5// a copy of this software and associated documentation files (the 6// "Software"), to deal in the Software without restriction, including 7// without limitation the rights to use, copy, modify, merge, publish, 8// distribute, sublicense, and/or sell copies of the Software, and to 9// permit persons to whom the Software is furnished to do so, subject to 10// the following conditions: 11// 12// The above copyright notice and this permission notice shall be 13// included in all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 19// BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 20// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22// SOFTWARE. 23 24package ghash 25 26import ( 27 "bytes" 28 "crypto/rand" 29 "encoding/binary" 30 "encoding/hex" 31 "testing" 32) 33 34// The test vectors are shamelessly stolen from "The Galois/Counter Mode of 35// Operation (GCM)", which is what BearSSL does. 36// 37// http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf 38 39var ghashVectors = []struct { 40 h string 41 a string 42 c string 43 y string 44}{ 45 { 46 "66e94bd4ef8a2c3b884cfa59ca342b2e", 47 "", 48 "", 49 "00000000000000000000000000000000", 50 }, 51 { 52 "66e94bd4ef8a2c3b884cfa59ca342b2e", 53 "", 54 "0388dace60b6a392f328c2b971b2fe78", 55 "f38cbb1ad69223dcc3457ae5b6b0f885", 56 }, 57 { 58 "b83b533708bf535d0aa6e52980d53b78", 59 "", 60 "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985", 61 "7f1b32b81b820d02614f8895ac1d4eac", 62 }, 63 { 64 "b83b533708bf535d0aa6e52980d53b78", 65 "feedfacedeadbeeffeedfacedeadbeefabaddad2", 66 "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091", 67 "698e57f70e6ecc7fd9463b7260a9ae5f", 68 }, 69 { 70 "b83b533708bf535d0aa6e52980d53b78", 71 "feedfacedeadbeeffeedfacedeadbeefabaddad2", 72 "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598", 73 "df586bb4c249b92cb6922877e444d37b", 74 }, 75 { 76 "b83b533708bf535d0aa6e52980d53b78", 77 "feedfacedeadbeeffeedfacedeadbeefabaddad2", 78 "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5", 79 "1c5afe9760d3932f3c9a878aac3dc3de", 80 }, 81} 82 83func gcmGHASH(y, h *[blockSize]byte, a, c []byte) { 84 var p [blockSize]byte 85 Ghash(y, h, a) 86 Ghash(y, h, c) 87 binary.BigEndian.PutUint32(p[4:], uint32(len(a))<<3) 88 binary.BigEndian.PutUint32(p[12:], uint32(len(c))<<3) 89 Ghash(y, h, p[:]) 90} 91 92func TestGHASH(t *testing.T) { 93 for i, vec := range ghashVectors { 94 hh, err := hex.DecodeString(vec.h[:]) 95 if err != nil { 96 t.Fatal(err) 97 } 98 a, err := hex.DecodeString(vec.a[:]) 99 if err != nil { 100 t.Fatal(err) 101 } 102 c, err := hex.DecodeString(vec.c[:]) 103 if err != nil { 104 t.Fatal(err) 105 } 106 yy, err := hex.DecodeString(vec.y[:]) 107 if err != nil { 108 t.Fatal(err) 109 } 110 111 var h, y [blockSize]byte 112 copy(h[:], hh) 113 114 gcmGHASH(&y, &h, a, c) 115 assertEqual(t, i, yy[:], y[:]) 116 } 117} 118 119func assertEqual(t *testing.T, idx int, expected, actual []byte) { 120 if !bytes.Equal(expected, actual) { 121 for i, v := range actual { 122 if expected[i] != v { 123 t.Errorf("[%d] first mismatch at offset: %d (%02x != %02x)", idx, i, expected[i], v) 124 break 125 } 126 } 127 t.Errorf("expected: %s", hex.Dump(expected)) 128 t.Errorf("actual: %s", hex.Dump(actual)) 129 t.FailNow() 130 } 131} 132 133var ghashBenchOutput [blockSize]byte 134 135func BenchmarkGHASH(b *testing.B) { 136 var y, h [blockSize]byte 137 var buf [8192]byte 138 139 if _, err := rand.Read(buf[:]); err != nil { 140 b.Error(err) 141 b.Fail() 142 } 143 if _, err := rand.Read(h[:]); err != nil { 144 b.Error(err) 145 b.Fail() 146 } 147 148 b.SetBytes(int64(len(buf))) 149 b.ResetTimer() 150 for i := 0; i < b.N; i++ { 151 Ghash(&y, &h, buf[:]) 152 } 153 b.StopTimer() 154 copy(ghashBenchOutput[:], y[:]) 155} 156