guid: Add V5 GUID support

Signed-off-by: Kevin Parsons <kevpar@microsoft.com>
This commit is contained in:
Kevin Parsons
2019-07-10 15:08:22 -07:00
parent c5294c98c0
commit 177d2ec7ea
2 changed files with 79 additions and 0 deletions
+24
View File
@@ -7,6 +7,7 @@ package guid
import (
"crypto/rand"
"crypto/sha1"
"encoding"
"encoding/binary"
"fmt"
@@ -59,6 +60,29 @@ func NewV4() (GUID, error) {
return g, nil
}
// NewV5 returns a new version 5 (generated from a string via SHA-1 hashing)
// GUID, as defined by RFC 4122. The RFC is unclear on the encoding of the name,
// and the sample code treats it as a series of bytes, so we do the same here.
//
// Some implementations, such as those found on Windows, treat the name as a
// big-endian UTF16 stream of bytes. If that is desired, the string can be
// encoded as such before being passed to this function.
func NewV5(namespace GUID, name []byte) (GUID, error) {
b := sha1.New()
namespaceBytes := namespace.ToArray()
b.Write(namespaceBytes[:])
b.Write(name)
a := [16]byte{}
copy(a[:], b.Sum(nil))
g := FromArray(a)
g.setVersion(5) // Version 5 means generated from a string.
g.setVariant(VariantRFC4122)
return g, nil
}
func fromArray(b [16]byte, order binary.ByteOrder) GUID {
var g GUID
g.Data1 = order.Uint32(b[0:4])
+55
View File
@@ -14,6 +14,14 @@ func mustNewV4(t *testing.T) GUID {
return g
}
func mustNewV5(t *testing.T, namespace GUID, name []byte) GUID {
g, err := NewV5(namespace, name)
if err != nil {
t.Fatal(err)
}
return g
}
func mustFromString(t *testing.T, s string) GUID {
g, err := FromString(s)
if err != nil {
@@ -112,6 +120,53 @@ func Test_V4HasCorrectVersionAndVariant(t *testing.T) {
}
}
func Test_V5HasCorrectVersionAndVariant(t *testing.T) {
namespace := mustFromString(t, "f5cbc1a9-4cba-45a0-bfdd-b6761fc7dcc0")
g := mustNewV5(t, namespace, []byte("Foo"))
if g.Version() != 5 {
t.Fatalf("Version is not 5: %s", g)
}
if g.Variant() != VariantRFC4122 {
t.Fatalf("Variant is not RFC4122: %s", g)
}
}
func Test_V5KnownValues(t *testing.T) {
type testCase struct {
ns GUID
name string
g GUID
}
testCases := []testCase{
{
mustFromString(t, "6ba7b810-9dad-11d1-80b4-00c04fd430c8"),
"www.sample.com",
mustFromString(t, "4e4463eb-b0e8-54fa-8c28-12d1ab1d45b3"),
},
{
mustFromString(t, "6ba7b811-9dad-11d1-80b4-00c04fd430c8"),
"https://www.sample.com/test",
mustFromString(t, "9e44625a-0d85-5e0a-99bc-8e8a77df5ea2"),
},
{
mustFromString(t, "6ba7b812-9dad-11d1-80b4-00c04fd430c8"),
"1.3.6.1.4.1.343",
mustFromString(t, "6aab0456-7392-582a-b92a-ba5a7096945d"),
},
{
mustFromString(t, "6ba7b814-9dad-11d1-80b4-00c04fd430c8"),
"CN=John Smith, ou=People, o=FakeCorp, L=Seattle, S=Washington, C=US",
mustFromString(t, "badff8dd-c869-5b64-a260-00092e66be00"),
},
}
for _, tc := range testCases {
g := mustNewV5(t, tc.ns, []byte(tc.name))
if g != tc.g {
t.Fatalf("GUIDs are not equal.\nExpected: %s\nActual: %s", tc.g, g)
}
}
}
func Test_ToArray(t *testing.T) {
g := mustFromString(t, "73c39589-192e-4c64-9acf-6c5d0aa18528")
b := g.ToArray()