// bdlb_guidutil.h -*-C++-*- #ifndef INCLUDED_BDLB_GUIDUTIL #define INCLUDED_BDLB_GUIDUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide functions that produce Globally Unique Identifiers. // //@CLASSES: // bdlb::GuidUtil: namespace for methods for creating GUIDs // //@SEE_ALSO: bdlb_guid // //@DESCRIPTION: This component provides a 'struct', 'bdlb::GuidUtil', that // serves as a namespace for utility functions that create and work with // Globally Unique Identifiers (GUIDs). // // Note that all the GUIDs generated by this component are actually Universally // Unique Identifiers (UUIDs), which are a type of GUID. The two terms will be // used interchangeably in the documentation below. // ///Grammar for GUIDs Used in 'guidFromString' ///------------------------------------------ // This conversion performed by 'guidFromString' is intended to be used for // GUIDs generated by external sources that have a variety of formats. // ///GUID String Format ///------------------ //.. // <SPEC> ::= <BRACED GUID> | <GUID> // // <BRACED GUID> ::= '[' <GUID> ']' | '[ ' <GUID> ' ]' // '{' <GUID> '}' | '{ ' <GUID> ' }' // // <GUID> ::= <FORMATTED GUID> | <UNFORMATTED GUID> // // <FORMATTED GUID> ::= <X>{4} '-' <X>{2} '-' <X>{2} '-' <X>{2} '-' <X>{6} // // <UNFORMATTED GUID> ::= <X>{16} // // <X> ::= [0123456789ABCDEFabcdef]{2} // // // EXAMPLES: // --------- // { 87654321-AAAA-BBBB-CCCC-012345654321 } // 00010203-0405-0607-0809-101112131415 // [00112233445566778899aAbBcCdDeEfF] //.. // ///Cryptographic Security ///---------------------- // 'GuidUtil' provides three families of functions for generating GUIDs: // 'generate', 'generateNonSecure', and 'generateFromName'. The 'generate' and // 'generateNonSecure' methods use random number generators, with the slower // 'generate' methods aiming to produce cryptographically secure UUIDs by // accessing underlying system resources to obtain truly random numbers, and // the faster 'generateNonSecure' methods using a fast high-quality (but not // strictly cryptographically secure) in-process random-number generator. // // The 'generateFromName' method does not use random numbers, but produces a // UUID deterministically based on a given name and namespace. The user should // heed the following admonition in RFC 4122: "Do not assume that UUIDs are // hard to guess; they should not be used as security capabilities (identifiers // whose mere possession grants access), for example." In addition, // applications that generate name-based UUIDs from untrusted inputs must not // assume that such UUIDs will be unique, since collision attacks are already // known against the SHA-1 hash algorithm. // ///Usage ///----- // Suppose we are building a system for managing records for employees in a // large international firm. These records have no natural field which can be // used as a unique ID, so a GUID must be created for each employee. // // First let us define a value-type for employees. //.. // class MyEmployee { // // This class provides a value-semantic type to represent an employee // // record. These records are for internal use only. //.. // For the sake of brevity, we provide a limited amount of data in each record. // We additionally show a very limited scope of functionality. //.. // // DATA // bsl::string d_name; // name of the employee // double d_salary; // salary in some common currency // bdlb::Guid d_guid; // a GUID for the employee // // public: // // CREATORS // MyEmployee(const string& name, double salary); // // Create an object with the specified 'name' and specified // //'salary', generating a new GUID to represent the employee. // // // ... // // // ACCESSORS // const bdlb::Guid& Guid() const; // // Return the 'guid' of this object. // // const bsl::string& name() const; // // Return the 'name' of this object. // // double salary() const; // // Return the 'salary' of this object. // // ... // }; //.. // Next, we create free functions 'operator<' and 'operator==' to allow // comparison of 'MyEmployee' objects. We take advantage of the monotonically // increasing nature of sequential GUIDs to implement these methods. //.. // // bool operator== (const MyEmployee& lhs, const MyEmployee& rhs); // // Return 'true' if the specified 'lhs' object has the same value as // // the specified 'rhs' object, and 'false' otherwise. Note that two // // 'MyEmployee' objects have the same value if they have the same // // guid. // // bool operator< (const MyEmployee& lhs, const MyEmployee& rhs); // // Return 'true' if the value of the specified 'lhs' MyEmployee object // // is less than the value of the specified 'rhs' MyEmployee object, // // and 'false' otherwise. A MyEmployee object is less than another if // // the guid is less than the other. // ... // // // CREATORS // MyEmployee::MyEmployee(const string& name, double salary) // : d_name(name) // , d_salary(salary) // { // bdlb::GuidUtil::generate(&d_guid); // } // // // ACCESSORS // const bdlb::Guid& MyEmployee::Guid() const // { // return d_guid; // } // // const bsl::string& MyEmployee::name() const // { // return d_name; // } // // double MyEmployee::salary() const // { // return d_salary; // } // // // FREE FUNCTIONS // bool operator==(const MyEmployee& lhs, const MyEmployee& rhs) // { // return lhs.Guid() == rhs.Guid(); // } // // bool operator<(const MyEmployee& lhs, const MyEmployee& rhs) // { // return lhs.Guid() < rhs.Guid(); // } //.. // Next, we create some employees: //.. // MyEmployee e1("Foo Bar" , 1011970); // MyEmployee e2("John Doe" , 12345); // MyEmployee e3("Joe Six-pack", 1); //.. // Finally, we verify that the generated GUIDs are unique. //.. // assert(e1 < e2 || e2 < e1); // assert(e2 < e3 || e3 < e2); // assert(e1 < e3 || e3 < e1); //.. #include <bdlscm_version.h> #include <bdlb_guid.h> #include <bdlb_pcgrandomgenerator.h> #include <bslmf_assert.h> #include <bsls_assert.h> #include <bsls_libraryfeatures.h> #include <bsls_types.h> #include <bsl_array.h> #include <bsl_cstddef.h> #include <bsl_cstdint.h> #include <bsl_string.h> #include <string> #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR #include <memory_resource> #endif namespace BloombergLP { namespace bdlb { // =================== // class GuidState_Imp // =================== class GuidState_Imp { // This component-private 'class' describes holds the PCG generators and // generation functions for use by 'GuidUtil'. public: // PUBLIC CLASS CONSTANTS enum { k_GENERATOR_COUNT = 4 }; private: // DATA bsl::array<bdlb::PcgRandomGenerator, k_GENERATOR_COUNT> d_generators; public: // MANIPULATORS void generateRandomBits( bsl::uint32_t (*out)[GuidState_Imp::k_GENERATOR_COUNT]); // Populate the specified 'out' with the results of calling 'generate' // on the internal random generators. void seed(const bsl::array<bsl::uint64_t, k_GENERATOR_COUNT>& state); // Seed the internal generators based on the specified 'state' values. }; // =============== // struct GuidUtil // =============== struct GuidUtil { // This 'struct' provides a namespace for functions that create Universally // Unique Identifiers per RFC 4122 (http://www.ietf.org/rfc/rfc4122.txt). // CLASS METHODS static void generate(Guid *result, bsl::size_t numGuids = 1); // Generate a sequence of GUIDs meeting the RFC 4122 version 4 // specification, and load the resulting GUIDs into the array referred // to by the specified 'result'. Optionally specify 'numGuids', // indicating the number of GUIDs to load into the 'result' array. If // 'numGuids' is not supplied, a default of 1 is used. An RFC 4122 // version 4 GUID consists of 122 randomly generated bits, two // "variant" bits set to '10', and four "version" bits set to '0100'. // The behavior is undefined unless 'result' refers to a contiguous // sequence of at least 'numGuids' 'Guid' objects. static Guid generate(); // Generate and return a single GUID meeting the RFC 4122 version 4 // specification, consisting of 122 randomly generated bits, two // "variant" bits set to '10', and four "version" bits set to '0100'. static void generateNonSecure(Guid *result, bsl::size_t numGuids = 1); // Generate a sequence of GUIDs meeting the RFC 4122 version 4 // specification, and load the resulting GUIDs into the array referred // to by the specified 'result'. Optionally specify 'numGuids', // indicating the number of GUIDs to load into the 'result' array. If // 'numGuids' is not supplied, a default of 1 is used. An RFC 4122 // version 4 GUID consists of 122 randomly generated bits, two // "variant" bits set to '10', and four "version" bits set to '0100'. // The behavior is undefined unless 'result' refers to a contiguous // sequence of at least 'numGuids' 'Guid' objects. Note that this // function generates high quality, albeit not cryptographically // secure, random numbers for GUIDs. static Guid generateNonSecure(); // Generate and return a single GUID meeting the RFC 4122 version 4 // specification, consisting of 122 randomly generated bits, two // "variant" bits set to '10', and four "version" bits set to '0100'. // Note that this function generates high quality, albeit not // cryptographically secure, random numbers for GUIDs. static Guid generateFromName(const Guid& namespaceId, const bsl::string_view& name); // Generate and return a single GUID meeting the RFC 4122 version 5 // specification from the specified 'namespaceId' and 'name'. // 'namespaceId' may (but need not) be one of the pre-defined namespace // IDs. Note that this method is a pure function of its arguments. static Guid dnsNamespace(); // Return the pre-defined namespace ID for the DNS namespace from // Appendix C of RFC 4122, for use with the 'generateFromName' method // when the name string is a fully-qualified domain name. static Guid urlNamespace(); // Return the pre-defined namespace ID for the URL namespace from // Appendix C of RFC 4122, for use with the 'generateFromName' method // when the name string is a URL. static Guid oidNamespace(); // Return the pre-defined namespace ID for the OID namespace from // Appendix C of RFC 4122, for use with the 'generateFromName' method // when the name string is an ISO Object ID (OID). static Guid x500Namespace(); // Return the pre-defined namespace ID for the X500 namespace from // Appendix C of RFC 4122, for use with the 'generateFromName' method // when the name string is an X.500 Distinguished Name. static int guidFromString(Guid *result, const bsl::string_view& guidString); // Parse the specified 'guidString' (in {GUID String Format}) and load // its value into the specified 'result'. Return 0 if 'result' // successfully loaded, and a non-zero value otherwise. static Guid guidFromString(const bsl::string_view& guidString); // Parse the specified 'guidString' (in {GUID String Format}) and // return the converted GUID, or a default-constructed 'Guid' if the // string is improperly formatted. static void guidToString(bsl::string *result, const Guid& guid); static void guidToString(std::string *result, const Guid& guid); #ifdef BSLS_LIBRARYFEATURES_HAS_CPP17_PMR static void guidToString(std::pmr::string *result, const Guid& guid); #endif // Serialize the specified 'guid' into the specified 'result'. The // 'result' string will be in a format suitable for 'guidFromString'. static bsl::string guidToString(const Guid& guid); // Convert the specified 'guid' into a string suitable for // 'guidFromString', and return the string. static int getVersion(const bdlb::Guid& guid); // Return the version of the specified 'guid' object. The behavior is // undefined unless the contents of the 'guid' object are compliant // with RFC 4122. static bsls::Types::Uint64 getMostSignificantBits(const Guid& guid); // Return the most significant 8 bytes of the specified 'guid'. static bsls::Types::Uint64 getLeastSignificantBits(const Guid& guid); // Return the least significant 8 bytes of the specified 'guid'. // DEPRECATED CLASS METHODS static void generate(unsigned char *result, bsl::size_t numGuids = 1); // !DEPRECATED!: Use 'generate(Guid *, size_t)' instead. // // Generate a sequence of GUIDs meeting the RFC 4122 version 4 // specification, and load the bytes of the resulting GUIDs into the // array referred to by the specified 'result'. Optionally specify // 'numGuids', indicating the number of GUIDs to load into the 'result' // array. If 'numGuids' is not supplied, a default of 1 is used. An // RFC 4122 version 4 GUID consists of 122 randomly generated bits, two // "variant" bits set to '10', and four "version" bits set to '0100'. // The behavior is undefined unless 'result' refers to a contiguous // sequence of at least '16 * numGuids' bytes. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ------------------- // class GuidState_Imp // ------------------- // MANIPULATORS inline void GuidState_Imp::generateRandomBits( bsl::uint32_t (*out)[GuidState_Imp::k_GENERATOR_COUNT]) { for (int i = 0; i < GuidState_Imp::k_GENERATOR_COUNT; i++) { (*out)[i] = d_generators[i].generate(); } } // --------------- // struct GuidUtil // --------------- // CLASS METHODS inline void GuidUtil::generate(Guid *result, bsl::size_t numGuids) { generate(reinterpret_cast<unsigned char *>(result), numGuids); } inline int GuidUtil::getVersion(const Guid& guid) { return (guid[6] & 0xF0) >> 4; } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2015 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------