1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00

uuid: Initial import of RFC4122 UUID functions

Provides functions for type 3, 4 and 5 UUID generations.

UUID type 1 is timestamp based and requires an accurate time source. For
this reason it is left out of this implementation. UUID type 2 is not
defined in RFC 4122 and thus also not included here
This commit is contained in:
Koen Zandberg 2018-04-28 11:33:06 +02:00
parent 1df01a482f
commit fc03d6f694
No known key found for this signature in database
GPG Key ID: 0895A893E6D2985B
4 changed files with 265 additions and 0 deletions

View File

@ -728,6 +728,11 @@ ifneq (,$(filter tlsf-malloc,$(USEMODULE)))
USEPKG += tlsf
endif
ifneq (,$(filter uuid,$(USEMODULE)))
USEMODULE += hashes
USEMODULE += random
endif
# always select gpio (until explicit dependencies are sorted out)
FEATURES_OPTIONAL += periph_gpio

147
sys/include/uuid.h Normal file
View File

@ -0,0 +1,147 @@
/*
* Copyright (C) 2018 Freie Universität Berlin
* Copyright (C) 2018 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup sys_uuid RFC 4122 compliant UUID's
* @ingroup sys
* @brief Provides RFC 4122 compliant UUID's
*
* This module provides RFC 4122 compliant UUID generation. The UUID stored in
* @ref uuid_t struct is stored in network byte order.
*
* @{
*
* @file
* @brief [RFC 4122](https://tools.ietf.org/html/rfc4122) UUID functions
*
* @author Koen Zandberg <koen@bergzand.net>
*/
#ifndef UUID_H
#define UUID_H
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "byteorder.h"
#ifdef __cplusplus
extern "C" {
#endif
#define UUID_NODE_LEN (6U) /**< Size of the node identifier in bytes */
/**
* @name UUID version identifiers
* @{
*/
#define UUID_V1 (0x01) /**< Type 1 UUID - timestamp based */
#define UUID_V2 (0x02) /**< Type 2 UUID - DCE Security version */
#define UUID_V3 (0x03) /**< Type 3 UUID - Name based with MD5 */
#define UUID_V4 (0x04) /**< Type 4 UUID - Random generated */
#define UUID_V5 (0x05) /**< Type 5 UUID - Name based with SHA1 */
/** @} */
/**
* @name Version part of the time_hi field
*/
#define UUID_VERSION_MASK (0xF000)
/**
* @brief UUID layout
*
* Directly from [rfc4122](https://tools.ietf.org/html/rfc4122#section-4.1.2)
*/
typedef struct __attribute__((packed)) {
network_uint32_t time_low; /**< The low field of the timestamp */
network_uint16_t time_mid; /**< The middle field of the timestamp */
network_uint16_t time_hi; /**< The high field of the timestamp
* multiplexed with the version number */
uint8_t clk_seq_hi_res; /**< The high field of the clock sequence
* Multiplexed with the variant */
uint8_t clk_seq_low; /**< The low field of the clock sequence */
uint8_t node[UUID_NODE_LEN]; /**< The spatially unique node identifier */
} uuid_t;
/**
* @name Namespace IDs from RFC4122
*
* Copied from [rfc4122 Appendix
* C](https://tools.ietf.org/html/rfc4122#appendix-C)
*
* @{
*/
extern const uuid_t uuid_namespace_dns; /**< DNS namespace UUID */
extern const uuid_t uuid_namespace_url; /**< URL namespace UUID */
extern const uuid_t uuid_namespace_iso; /**< ISO OID namespace UUID */
extern const uuid_t uuid_namespace_x500; /**< X.500 DN namespace UUID */
/** @} */
/**
* Generate a version 3(md5 based) UUID from a namespace and a byte array
*
* @param[out] uuid UUID struct to fill
* @param[in] ns Namespace UUID
* @param[in] name Ptr to byte array to use as name part
* @param[in] len Length of the byte array
*/
void uuid_v3(uuid_t *uuid, const uuid_t *ns, const uint8_t *name, size_t len);
/**
* Generate a version 4(Full random) UUID
*
* @param[out] uuid UUID struct to fill
*/
void uuid_v4(uuid_t *uuid);
/**
* Generate a version 5(sha1 based) UUID from a namespace and a byte array
*
* @param[out] uuid UUID struct to fill
* @param[in] ns Namespace UUID
* @param[in] name Ptr to byte array to use as name part
* @param[in] len Length of the byte array
*/
void uuid_v5(uuid_t *uuid, const uuid_t *ns, const uint8_t *name, size_t len);
/**
* Retrieve the type number of a UUID
*
* @param[in] uuid UUID to retrieve version number from
*
* @return Version number
*/
static inline unsigned uuid_version(uuid_t *uuid)
{
uint16_t time_hi_vers = byteorder_ntohs(uuid->time_hi);
return (time_hi_vers & 0xF000) >> 12;
}
/**
* Compare two UUID's
*
* @param[in] uuid1 First uuid to compare
* @param[in] uuid2 Second uuid to compare
*
* @return True when equal
*/
static inline bool uuid_equal(uuid_t *uuid1, uuid_t *uuid2)
{
return (memcmp(uuid1, uuid2, sizeof(uuid_t)) == 0);
}
#ifdef __cplusplus
}
#endif
#endif /* UUID_H */
/** @} */

1
sys/uuid/Makefile Normal file
View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

112
sys/uuid/uuid.c Normal file
View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2018 Freie Universität Berlin
* Copyright (C) 2018 Inria
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_uuid
* @{
* @file
* @brief Function implementations to create RFC 4122 UUID objects
*
* @author Koen Zandberg <koen@bergzand.net>
* @}
*/
#include <string.h>
#include "byteorder.h"
#include "hashes/md5.h"
#include "hashes/sha1.h"
#include "random.h"
#include "uuid.h"
const uuid_t uuid_namespace_dns = { /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */
.time_low.u8 = { 0x6b, 0xa7, 0xb8, 0x10 },
.time_mid.u8 = { 0x9d, 0xad },
.time_hi.u8 = { 0x11, 0xd1 },
.clk_seq_hi_res = 0x80,
.clk_seq_low = 0xb4,
.node = { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
};
const uuid_t uuid_namespace_url = { /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */
.time_low.u8 = { 0x6b, 0xa7, 0xb8, 0x11 },
.time_mid.u8 = { 0x9d, 0xad },
.time_hi.u8 = { 0x11, 0xd1 },
.clk_seq_hi_res = 0x80,
.clk_seq_low = 0xb4,
.node = { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
};
/* Name string is an ISO OID */
const uuid_t uuid_namespace_iso = { /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */
.time_low.u8 = { 0x6b, 0xa7, 0xb8, 0x12 },
.time_mid.u8 = { 0x9d, 0xad },
.time_hi.u8 = { 0x11, 0xd1 },
.clk_seq_hi_res = 0x80,
.clk_seq_low = 0xb4,
.node = { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
};
const uuid_t uuid_namespace_x500 = { /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */
.time_low.u8 = { 0x6b, 0xa7, 0xb8, 0x14 },
.time_mid.u8 = { 0x9d, 0xad },
.time_hi.u8 = { 0x11, 0xd1 },
.clk_seq_hi_res = 0x80,
.clk_seq_low = 0xb4,
.node = { 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8 }
};
static inline void _set_version(uuid_t *uuid, unsigned version)
{
uint16_t time_hi = byteorder_ntohs(uuid->time_hi) & 0x0fff;
time_hi |= (version << 12);
uuid->time_hi = byteorder_htons(time_hi);
}
static inline void _set_reserved(uuid_t *uuid)
{
uuid->clk_seq_hi_res = (uuid->clk_seq_hi_res & 0x3f) | 0x80;
}
void uuid_v3(uuid_t *uuid, const uuid_t *ns, const uint8_t *name, size_t len)
{
/* Digest calculation */
md5_ctx_t ctx;
md5_init(&ctx);
md5_update(&ctx, ns, sizeof(uuid_t));
md5_update(&ctx, name, len);
md5_final(&ctx, uuid);
_set_version(uuid, UUID_V3);
_set_reserved(uuid);
}
void uuid_v4(uuid_t *uuid)
{
random_bytes((uint8_t *)uuid, sizeof(uuid_t));
_set_version(uuid, UUID_V4);
_set_reserved(uuid);
}
void uuid_v5(uuid_t *uuid, const uuid_t *ns, const uint8_t *name, size_t len)
{
uint8_t digest[20];
sha1_context ctx;
sha1_init(&ctx);
sha1_update(&ctx, ns, sizeof(uuid_t));
sha1_update(&ctx, name, len);
sha1_final(&ctx, digest);
memcpy(uuid, digest, sizeof(uuid_t));
_set_version(uuid, UUID_V5);
_set_reserved(uuid);
}