1// This package provides immutable UUID structs and the functions 2// NewV3, NewV4, NewV5 and Parse() for generating versions 3, 4 3// and 5 UUIDs as specified in RFC 4122. 4// 5// Copyright (C) 2011 by Krzysztof Kowalik <chris@nu7hat.ch> 6package uuid 7 8import ( 9 "crypto/md5" 10 "crypto/rand" 11 "crypto/sha1" 12 "encoding/hex" 13 "errors" 14 "fmt" 15 "hash" 16 "regexp" 17) 18 19// The UUID reserved variants. 20const ( 21 ReservedNCS byte = 0x80 22 ReservedRFC4122 byte = 0x40 23 ReservedMicrosoft byte = 0x20 24 ReservedFuture byte = 0x00 25) 26 27// The following standard UUIDs are for use with NewV3() or NewV5(). 28var ( 29 NamespaceDNS, _ = ParseHex("6ba7b810-9dad-11d1-80b4-00c04fd430c8") 30 NamespaceURL, _ = ParseHex("6ba7b811-9dad-11d1-80b4-00c04fd430c8") 31 NamespaceOID, _ = ParseHex("6ba7b812-9dad-11d1-80b4-00c04fd430c8") 32 NamespaceX500, _ = ParseHex("6ba7b814-9dad-11d1-80b4-00c04fd430c8") 33) 34 35// Pattern used to parse hex string representation of the UUID. 36// FIXME: do something to consider both brackets at one time, 37// current one allows to parse string with only one opening 38// or closing bracket. 39const hexPattern = "^(urn\\:uuid\\:)?\\{?([a-z0-9]{8})-([a-z0-9]{4})-" + 40 "([1-5][a-z0-9]{3})-([a-z0-9]{4})-([a-z0-9]{12})\\}?$" 41 42var re = regexp.MustCompile(hexPattern) 43 44// A UUID representation compliant with specification in 45// RFC 4122 document. 46type UUID [16]byte 47 48// ParseHex creates a UUID object from given hex string 49// representation. Function accepts UUID string in following 50// formats: 51// 52// uuid.ParseHex("6ba7b814-9dad-11d1-80b4-00c04fd430c8") 53// uuid.ParseHex("{6ba7b814-9dad-11d1-80b4-00c04fd430c8}") 54// uuid.ParseHex("urn:uuid:6ba7b814-9dad-11d1-80b4-00c04fd430c8") 55// 56func ParseHex(s string) (u *UUID, err error) { 57 md := re.FindStringSubmatch(s) 58 if md == nil { 59 err = errors.New("Invalid UUID string") 60 return 61 } 62 hash := md[2] + md[3] + md[4] + md[5] + md[6] 63 b, err := hex.DecodeString(hash) 64 if err != nil { 65 return 66 } 67 u = new(UUID) 68 copy(u[:], b) 69 return 70} 71 72// Parse creates a UUID object from given bytes slice. 73func Parse(b []byte) (u *UUID, err error) { 74 if len(b) != 16 { 75 err = errors.New("Given slice is not valid UUID sequence") 76 return 77 } 78 u = new(UUID) 79 copy(u[:], b) 80 return 81} 82 83// Generate a UUID based on the MD5 hash of a namespace identifier 84// and a name. 85func NewV3(ns *UUID, name []byte) (u *UUID, err error) { 86 if ns == nil { 87 err = errors.New("Invalid namespace UUID") 88 return 89 } 90 u = new(UUID) 91 // Set all bits to MD5 hash generated from namespace and name. 92 u.setBytesFromHash(md5.New(), ns[:], name) 93 u.setVariant(ReservedRFC4122) 94 u.setVersion(3) 95 return 96} 97 98// Generate a random UUID. 99func NewV4() (u *UUID, err error) { 100 u = new(UUID) 101 // Set all bits to randomly (or pseudo-randomly) chosen values. 102 _, err = rand.Read(u[:]) 103 if err != nil { 104 return 105 } 106 u.setVariant(ReservedRFC4122) 107 u.setVersion(4) 108 return 109} 110 111// Generate a UUID based on the SHA-1 hash of a namespace identifier 112// and a name. 113func NewV5(ns *UUID, name []byte) (u *UUID, err error) { 114 u = new(UUID) 115 // Set all bits to truncated SHA1 hash generated from namespace 116 // and name. 117 u.setBytesFromHash(sha1.New(), ns[:], name) 118 u.setVariant(ReservedRFC4122) 119 u.setVersion(5) 120 return 121} 122 123// Generate a MD5 hash of a namespace and a name, and copy it to the 124// UUID slice. 125func (u *UUID) setBytesFromHash(hash hash.Hash, ns, name []byte) { 126 hash.Write(ns[:]) 127 hash.Write(name) 128 copy(u[:], hash.Sum([]byte{})[:16]) 129} 130 131// Set the two most significant bits (bits 6 and 7) of the 132// clock_seq_hi_and_reserved to zero and one, respectively. 133func (u *UUID) setVariant(v byte) { 134 switch v { 135 case ReservedNCS: 136 u[8] = (u[8] | ReservedNCS) & 0xBF 137 case ReservedRFC4122: 138 u[8] = (u[8] | ReservedRFC4122) & 0x7F 139 case ReservedMicrosoft: 140 u[8] = (u[8] | ReservedMicrosoft) & 0x3F 141 } 142} 143 144// Variant returns the UUID Variant, which determines the internal 145// layout of the UUID. This will be one of the constants: RESERVED_NCS, 146// RFC_4122, RESERVED_MICROSOFT, RESERVED_FUTURE. 147func (u *UUID) Variant() byte { 148 if u[8]&ReservedNCS == ReservedNCS { 149 return ReservedNCS 150 } else if u[8]&ReservedRFC4122 == ReservedRFC4122 { 151 return ReservedRFC4122 152 } else if u[8]&ReservedMicrosoft == ReservedMicrosoft { 153 return ReservedMicrosoft 154 } 155 return ReservedFuture 156} 157 158// Set the four most significant bits (bits 12 through 15) of the 159// time_hi_and_version field to the 4-bit version number. 160func (u *UUID) setVersion(v byte) { 161 u[6] = (u[6] & 0xF) | (v << 4) 162} 163 164// Version returns a version number of the algorithm used to 165// generate the UUID sequence. 166func (u *UUID) Version() uint { 167 return uint(u[6] >> 4) 168} 169 170// Returns unparsed version of the generated UUID sequence. 171func (u *UUID) String() string { 172 return fmt.Sprintf("%x-%x-%x-%x-%x", u[0:4], u[4:6], u[6:8], u[8:10], u[10:]) 173} 174