uuid4.cpp 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. /**
  2. * Copyright (c) 2018 rxi
  3. *
  4. * This library is free software; you can redistribute it and/or modify it
  5. * under the terms of the MIT license. See LICENSE for details.
  6. */
  7. #include <stdio.h>
  8. #include <stdint.h>
  9. #if defined(_WIN32)
  10. #include <windows.h>
  11. #include <wincrypt.h>
  12. #pragma comment(lib, "Advapi32.lib")
  13. #endif
  14. #include "uuid4.h"
  15. #include "SpBase.h"
  16. static uint64_t seed[2];
  17. static uint64_t xorshift128plus(uint64_t *s) {
  18. /* http://xorshift.di.unimi.it/xorshift128plus.c */
  19. uint64_t s1 = s[0];
  20. const uint64_t s0 = s[1];
  21. s[0] = s0;
  22. s1 ^= s1 << 23;
  23. s[1] = s1 ^ s0 ^ (s1 >> 18) ^ (s0 >> 5);
  24. return s[1] + s0;
  25. }
  26. int uuid4_init(void) {
  27. #if defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__)
  28. int res;
  29. FILE *fp = fopen("/dev/urandom", "rb");
  30. if (!fp) {
  31. return UUID4_EFAILURE;
  32. }
  33. res = fread(seed, 1, sizeof(seed), fp);
  34. fclose(fp);
  35. if ( res != sizeof(seed) ) {
  36. return UUID4_EFAILURE;
  37. }
  38. #elif defined(_WIN32)
  39. int res;
  40. HCRYPTPROV hCryptProv;
  41. res = CryptAcquireContext(
  42. &hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
  43. if (!res) {
  44. return UUID4_EFAILURE;
  45. }
  46. res = CryptGenRandom(hCryptProv, (DWORD) sizeof(seed), (PBYTE) seed);
  47. CryptReleaseContext(hCryptProv, 0);
  48. if (!res) {
  49. return UUID4_EFAILURE;
  50. }
  51. #else
  52. #error "unsupported platform"
  53. #endif
  54. return UUID4_ESUCCESS;
  55. }
  56. void uuid4_generate(char *dst) {
  57. static const char *template1 = "xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx";
  58. static const char *chars = "0123456789abcdef";
  59. union { unsigned char b[16]; uint64_t word[2]; } s;
  60. const char *p;
  61. int i, n;
  62. /* get random */
  63. s.word[0] = xorshift128plus(seed);
  64. s.word[1] = xorshift128plus(seed);
  65. /* build string */
  66. p = template1;
  67. i = 0;
  68. while (*p) {
  69. n = s.b[i >> 1];
  70. n = (i & 1) ? (n >> 4) : (n & 0xf);
  71. switch (*p) {
  72. case 'x' : *dst = chars[n]; i++; break;
  73. case 'y' : *dst = chars[(n & 0x3) + 8]; i++; break;
  74. default : *dst = *p;
  75. }
  76. dst++, p++;
  77. }
  78. *dst = '\0';
  79. }
  80. std::string uuid4_generate(int len)
  81. {
  82. char buf[UUID4_LEN];
  83. uuid4_init();
  84. uuid4_generate(buf);
  85. std::string result = buf;
  86. if (len > 0 && len <= 32)
  87. return result.substr(0, len);
  88. else
  89. return "";
  90. }
  91. CSimpleStringA uuid4_generateStr(int len)
  92. {
  93. auto ret = uuid4_generate(len);
  94. return ret.c_str();
  95. }