1/* guuid.c - UUID functions
2 *
3 * Copyright (C) 2013-2015, 2017 Red Hat, Inc.
4 *
5 * This library is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as
7 * published by the Free Software Foundation; either version 2.1 of the
8 * licence, or (at your option) any later version.
9 *
10 * This is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
13 * License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
18 * USA.
19 *
20 * Authors: Marc-André Lureau <marcandre.lureau@redhat.com>
21 */
22
23#include "config.h"
24#include <string.h>
25
26#include "gi18n.h"
27#include "gstrfuncs.h"
28#include "grand.h"
29#include "gmessages.h"
30#include "gchecksum.h"
31
32#include "guuid.h"
33
34typedef struct {
35 guint8 bytes[16];
36} GUuid;
37
38/**
39 * SECTION:uuid
40 * @title: GUuid
41 * @short_description: a universally unique identifier
42 *
43 * A UUID, or Universally unique identifier, is intended to uniquely
44 * identify information in a distributed environment. For the
45 * definition of UUID, see [RFC 4122](https://tools.ietf.org/html/rfc4122.html).
46 *
47 * The creation of UUIDs does not require a centralized authority.
48 *
49 * UUIDs are of relatively small size (128 bits, or 16 bytes). The
50 * common string representation (ex:
51 * 1d6c0810-2bd6-45f3-9890-0268422a6f14) needs 37 bytes.
52 *
53 * The UUID specification defines 5 versions, and calling
54 * g_uuid_string_random() will generate a unique (or rather random)
55 * UUID of the most common version, version 4.
56 *
57 * Since: 2.52
58 */
59
60/*
61 * g_uuid_to_string:
62 * @uuid: a #GUuid
63 *
64 * Creates a string representation of @uuid, of the form
65 * 06e023d5-86d8-420e-8103-383e4566087a (no braces nor urn:uuid:
66 * prefix).
67 *
68 * Returns: (transfer full): A string that should be freed with g_free().
69 * Since: STATIC
70 */
71static gchar *
72g_uuid_to_string (const GUuid *uuid)
73{
74 const guint8 *bytes;
75
76 g_return_val_if_fail (uuid != NULL, NULL);
77
78 bytes = uuid->bytes;
79
80 return g_strdup_printf (format: "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x"
81 "-%02x%02x%02x%02x%02x%02x",
82 bytes[0], bytes[1], bytes[2], bytes[3],
83 bytes[4], bytes[5], bytes[6], bytes[7],
84 bytes[8], bytes[9], bytes[10], bytes[11],
85 bytes[12], bytes[13], bytes[14], bytes[15]);
86}
87
88static gboolean
89uuid_parse_string (const gchar *str,
90 GUuid *uuid)
91{
92 GUuid tmp;
93 guint8 *bytes = tmp.bytes;
94 gint i, j, hi, lo;
95 guint expected_len = 36;
96
97 if (strlen (s: str) != expected_len)
98 return FALSE;
99
100 for (i = 0, j = 0; i < 16;)
101 {
102 if (j == 8 || j == 13 || j == 18 || j == 23)
103 {
104 if (str[j++] != '-')
105 return FALSE;
106
107 continue;
108 }
109
110 hi = g_ascii_xdigit_value (c: str[j++]);
111 lo = g_ascii_xdigit_value (c: str[j++]);
112
113 if (hi == -1 || lo == -1)
114 return FALSE;
115
116 bytes[i++] = hi << 8 | lo;
117 }
118
119 if (uuid != NULL)
120 *uuid = tmp;
121
122 return TRUE;
123}
124
125/**
126 * g_uuid_string_is_valid:
127 * @str: a string representing a UUID
128 *
129 * Parses the string @str and verify if it is a UUID.
130 *
131 * The function accepts the following syntax:
132 *
133 * - simple forms (e.g. `f81d4fae-7dec-11d0-a765-00a0c91e6bf6`)
134 *
135 * Note that hyphens are required within the UUID string itself,
136 * as per the aforementioned RFC.
137 *
138 * Returns: %TRUE if @str is a valid UUID, %FALSE otherwise.
139 * Since: 2.52
140 */
141gboolean
142g_uuid_string_is_valid (const gchar *str)
143{
144 g_return_val_if_fail (str != NULL, FALSE);
145
146 return uuid_parse_string (str, NULL);
147}
148
149static void
150uuid_set_version (GUuid *uuid, guint version)
151{
152 guint8 *bytes = uuid->bytes;
153
154 /*
155 * Set the four most significant bits (bits 12 through 15) of the
156 * time_hi_and_version field to the 4-bit version number from
157 * Section 4.1.3.
158 */
159 bytes[6] &= 0x0f;
160 bytes[6] |= version << 4;
161 /*
162 * Set the two most significant bits (bits 6 and 7) of the
163 * clock_seq_hi_and_reserved to zero and one, respectively.
164 */
165 bytes[8] &= 0x3f;
166 bytes[8] |= 0x80;
167}
168
169/*
170 * g_uuid_generate_v4:
171 * @uuid: a #GUuid
172 *
173 * Generates a random UUID (RFC 4122 version 4).
174 * Since: STATIC
175 */
176static void
177g_uuid_generate_v4 (GUuid *uuid)
178{
179 int i;
180 guint8 *bytes;
181 guint32 *ints;
182
183 g_return_if_fail (uuid != NULL);
184
185 bytes = uuid->bytes;
186 ints = (guint32 *) bytes;
187 for (i = 0; i < 4; i++)
188 ints[i] = g_random_int ();
189
190 uuid_set_version (uuid, version: 4);
191}
192
193/**
194 * g_uuid_string_random:
195 *
196 * Generates a random UUID (RFC 4122 version 4) as a string. It has the same
197 * randomness guarantees as #GRand, so must not be used for cryptographic
198 * purposes such as key generation, nonces, salts or one-time pads.
199 *
200 * Returns: (transfer full): A string that should be freed with g_free().
201 * Since: 2.52
202 */
203gchar *
204g_uuid_string_random (void)
205{
206 GUuid uuid;
207
208 g_uuid_generate_v4 (uuid: &uuid);
209
210 return g_uuid_to_string (uuid: &uuid);
211}
212

source code of gtk/subprojects/glib/glib/guuid.c