Rev 68 | Rev 70 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 68 | Rev 69 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | <?php |
1 | <?php |
2 | 2 | ||
3 | /* |
3 | /* |
4 | * UUID utils for PHP |
4 | * UUID utils for PHP |
5 | * Copyright 2011 - 2023 Daniel Marschall, ViaThinkSoft |
5 | * Copyright 2011 - 2023 Daniel Marschall, ViaThinkSoft |
6 | * Version 2023-09-07 |
6 | * Version 2023-09-23 |
7 | * |
7 | * |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
8 | * Licensed under the Apache License, Version 2.0 (the "License"); |
9 | * you may not use this file except in compliance with the License. |
9 | * you may not use this file except in compliance with the License. |
10 | * You may obtain a copy of the License at |
10 | * You may obtain a copy of the License at |
11 | * |
11 | * |
Line 970... | Line 970... | ||
970 | $tp['usec'] = gmp_init($tp['usec'],10); |
970 | $tp['usec'] = gmp_init($tp['usec'],10); |
971 | $time = gmp_add(gmp_add(gmp_mul($tp['sec'], gmp_init('10000000',10)),gmp_mul($tp['usec'], gmp_init('10',10))),gmp_init('01B21DD213814000',16)); |
971 | $time = gmp_add(gmp_add(gmp_mul($tp['sec'], gmp_init('10000000',10)),gmp_mul($tp['usec'], gmp_init('10',10))),gmp_init('01B21DD213814000',16)); |
972 | $uuid['time_low'] = gmp_and($time, gmp_init('ffffffff',16)); |
972 | $uuid['time_low'] = gmp_and($time, gmp_init('ffffffff',16)); |
973 | $high = gmp_shiftr($time,32); |
973 | $high = gmp_shiftr($time,32); |
974 | $uuid['time_mid'] = gmp_and($high, gmp_init('ffff',16)); |
974 | $uuid['time_mid'] = gmp_and($high, gmp_init('ffff',16)); |
975 | $uuid['time_hi'] = intval(gmp_and(gmp_shiftr($high,16),gmp_init('fff',16)),10) | (1/*TimeBased*/ << 12); |
975 | $uuid['time_hi'] = gmp_intval(gmp_and(gmp_shiftr($high,16),gmp_init('fff',16))) | (1/*TimeBased*/ << 12); |
976 | } else { |
976 | } else { |
977 | $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) + 0x01B21DD213814000; |
977 | $time = ($tp['sec'] * 10000000) + ($tp['usec'] * 10) + 0x01B21DD213814000; |
978 | $uuid['time_low'] = $time & 0xffffffff; |
978 | $uuid['time_low'] = $time & 0xffffffff; |
979 | /* Work around PHP 32-bit bit-operation limits */ |
979 | /* Work around PHP 32-bit bit-operation limits */ |
980 | $high = intval($time / 0xffffffff); |
980 | $high = intval($time / 0xffffffff); |
Line 1272... | Line 1272... | ||
1272 | $block4[0] = dechex(hexdec($block4[0]) & 0b0011 | 0b1000); // Variant 0b10__ = RFC4122 |
1272 | $block4[0] = dechex(hexdec($block4[0]) & 0b0011 | 0b1000); // Variant 0b10__ = RFC4122 |
1273 | 1273 | ||
1274 | return strtolower($block1.'-'.$block2.'-'.$block3.'-'.$block4.'-'.$block5); |
1274 | return strtolower($block1.'-'.$block2.'-'.$block3.'-'.$block4.'-'.$block5); |
1275 | } |
1275 | } |
1276 | 1276 | ||
1277 | function gen_uuid_v8_namebased($hash_uuid, $namespace_uuid, $name) { |
1277 | function gen_uuid_v8_namebased($hash_algo, $namespace_uuid, $name) { |
1278 | if (($hash_uuid ?? '') === '') throw new Exception("Hash space UUID missing"); |
1278 | if (($hash_algo ?? '') === '') throw new Exception("Hash algorithm argument missing"); |
1279 | if (!uuid_valid($hash_uuid)) throw new Exception("Invalid hash space ID '$hash_uuid'"); |
- | |
1280 | 1279 | ||
1281 | if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing"); |
1280 | if (($namespace_uuid ?? '') === '') throw new Exception("Namespace UUID missing"); |
1282 | if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'"); |
1281 | if (!uuid_valid($namespace_uuid)) throw new Exception("Invalid namespace UUID '$namespace_uuid'"); |
1283 | 1282 | ||
1284 | $uuid1 = hex2bin(str_replace('-','',uuid_canonize($hash_uuid))); |
1283 | $uuid1 = uuid_valid($hash_algo) ? hex2bin(str_replace('-','',uuid_canonize($hash_algo))) : ''; |
1285 | $uuid2 = hex2bin(str_replace('-','',uuid_canonize($namespace_uuid))); |
1284 | $uuid2 = hex2bin(str_replace('-','',uuid_canonize($namespace_uuid))); |
1286 | $payload = $uuid1 . $uuid2 . $name; |
1285 | $payload = $uuid1 . $uuid2 . $name; |
1287 | 1286 | ||
1288 | $hash = null; |
1287 | if (uuid_valid($hash_algo)) { |
1289 | foreach (get_uuidv8_hash_space_ids() as list($algo,$space,$friendlyName,$author,$available)) { |
1288 | foreach (get_uuidv8_hash_space_ids() as list($algo,$space,$friendlyName,$author,$available)) { |
1290 | if (uuid_equal($hash_uuid,$space)) { |
1289 | if (uuid_equal($hash_algo,$space)) { |
1291 | if (!$available) { |
1290 | if (!$available) { |
1292 | throw new Exception("Algorithm $algo is not available on this system (PHP version too old)"); |
1291 | throw new Exception("Algorithm $algo is not available on this system (PHP version too old)"); |
1293 | } |
1292 | } |
1294 | - | ||
1295 | if ($algo == 'shake128') $hash = shake128($payload, 16/*min. required bytes*/, false); |
- | |
1296 | else if ($algo == 'shake256') $hash = shake256($payload, 16/*min. required bytes*/, false); |
- | |
1297 | else $hash = hash($algo, $payload, false); |
1293 | $hash_algo = $algo; |
1298 | break; |
1294 | break; |
1299 | } |
1295 | } |
1300 | } |
1296 | } |
- | 1297 | } |
|
- | 1298 | ||
- | 1299 | if ($hash_algo == 'shake128') $hash = shake128($payload, 16/*min. required bytes*/, false); |
|
- | 1300 | else if ($hash_algo == 'shake256') $hash = shake256($payload, 16/*min. required bytes*/, false); |
|
- | 1301 | else $hash = hash($hash_algo, $payload, false); |
|
- | 1302 | ||
- | 1303 | $hash = str_pad($hash, 32, '0', STR_PAD_RIGHT); // fill short hashes with zeros to the right |
|
1301 | 1304 | ||
1302 | if ($hash == null) { |
1305 | if ($hash == null) { |
1303 | throw new Exception("Unknown Hash Space UUID $hash_uuid"); |
1306 | throw new Exception("Unknown Hash Algorithm $hash_algo"); |
1304 | } |
1307 | } |
1305 | 1308 | ||
1306 | $hash[12] = '8'; // Set version: 8 = Custom |
1309 | $hash[12] = '8'; // Set version: 8 = Custom |
1307 | $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "0b10__" (RFC4122/DCE1.1) |
1310 | $hash[16] = dechex(hexdec($hash[16]) & 0b0011 | 0b1000); // Set variant to "0b10__" (RFC4122/DCE1.1) |
1308 | 1311 | ||
Line 1313... | Line 1316... | ||
1313 | substr($hash, 20, 12); |
1316 | substr($hash, 20, 12); |
1314 | } |
1317 | } |
1315 | 1318 | ||
1316 | /** |
1319 | /** |
1317 | * Collection of Namebased UUIDv8 Hash Space IDs |
1320 | * Collection of Namebased UUIDv8 Hash Space IDs |
1318 | * @return array An array containing tuples of [PHP Algo Name, Hash Space UUID, Human friendly name, Hash Space Author, Available, AlgorithmOID] |
1321 | * @return array An array containing tuples of [PHP Algo Name, Hash Space UUID, Human friendly name, Hash Space Author, Available] |
1319 | */ |
1322 | */ |
1320 | function get_uuidv8_hash_space_ids(): array { |
1323 | function get_uuidv8_hash_space_ids(): array { |
1321 | $out = array(); |
1324 | $out = array(); |
1322 | 1325 | ||
1323 | // The following Hash Space UUIDs are defined in draft-ietf-uuidrev-rfc4122bis-11 as Example for Namebased UUIDv8 |
1326 | // The following Hash Space UUIDs are defined in draft-ietf-uuidrev-rfc4122bis-11 as Example for Namebased UUIDv8 |
1324 | $category = 'Internet Draft 11, Appendix B'; |
1327 | $category = 'Internet Draft 11, Appendix B'; |
1325 | $out[] = ['sha224', '59031ca3-fbdb-47fb-9f6c-0f30e2e83145', 'SHA-224', $category, PHP_VERSION_ID >= 70100, null]; |
1328 | $out[] = ['sha224', '59031ca3-fbdb-47fb-9f6c-0f30e2e83145', 'SHA-224', $category, PHP_VERSION_ID >= 70100]; |
1326 | $out[] = ['sha256', '3fb32780-953c-4464-9cfd-e85dbbe9843d', 'SHA-256', $category, PHP_VERSION_ID >= 70100, null]; |
1329 | $out[] = ['sha256', '3fb32780-953c-4464-9cfd-e85dbbe9843d', 'SHA-256', $category, PHP_VERSION_ID >= 70100]; |
1327 | $out[] = ['sha384', 'e6800581-f333-484b-8778-601ff2b58da8', 'SHA-384', $category, PHP_VERSION_ID >= 70100, null]; |
1330 | $out[] = ['sha384', 'e6800581-f333-484b-8778-601ff2b58da8', 'SHA-384', $category, PHP_VERSION_ID >= 70100]; |
1328 | $out[] = ['sha512', '0fde22f2-e7ba-4fd1-9753-9c2ea88fa3f9', 'SHA-512', $category, PHP_VERSION_ID >= 70100, null]; |
1331 | $out[] = ['sha512', '0fde22f2-e7ba-4fd1-9753-9c2ea88fa3f9', 'SHA-512', $category, PHP_VERSION_ID >= 70100]; |
1329 | $out[] = ['sha512/224', '003c2038-c4fe-4b95-a672-0c26c1b79542', 'SHA-512/224', $category, PHP_VERSION_ID >= 70100, null]; |
1332 | $out[] = ['sha512/224', '003c2038-c4fe-4b95-a672-0c26c1b79542', 'SHA-512/224', $category, PHP_VERSION_ID >= 70100]; |
1330 | $out[] = ['sha512/256', '9475ad00-3769-4c07-9642-5e7383732306', 'SHA-512/256', $category, PHP_VERSION_ID >= 70100, null]; |
1333 | $out[] = ['sha512/256', '9475ad00-3769-4c07-9642-5e7383732306', 'SHA-512/256', $category, PHP_VERSION_ID >= 70100]; |
1331 | $out[] = ['sha3-224', '9768761f-ac5a-419e-a180-7ca239e8025a', 'SHA3-224', $category, PHP_VERSION_ID >= 70100, null]; |
1334 | $out[] = ['sha3-224', '9768761f-ac5a-419e-a180-7ca239e8025a', 'SHA3-224', $category, PHP_VERSION_ID >= 70100]; |
1332 | $out[] = ['sha3-256', '2034d66b-4047-4553-8f80-70e593176877', 'SHA3-256', $category, PHP_VERSION_ID >= 70100, null]; |
1335 | $out[] = ['sha3-256', '2034d66b-4047-4553-8f80-70e593176877', 'SHA3-256', $category, PHP_VERSION_ID >= 70100]; |
1333 | $out[] = ['sha3-384', '872fb339-2636-4bdd-bda6-b6dc2a82b1b3', 'SHA3-384', $category, PHP_VERSION_ID >= 70100, null]; |
1336 | $out[] = ['sha3-384', '872fb339-2636-4bdd-bda6-b6dc2a82b1b3', 'SHA3-384', $category, PHP_VERSION_ID >= 70100]; |
1334 | $out[] = ['sha3-512', 'a4920a5d-a8a6-426c-8d14-a6cafbe64c7b', 'SHA3-512', $category, PHP_VERSION_ID >= 70100, null]; |
1337 | $out[] = ['sha3-512', 'a4920a5d-a8a6-426c-8d14-a6cafbe64c7b', 'SHA3-512', $category, PHP_VERSION_ID >= 70100]; |
1335 | $out[] = ['shake128'/*Currently no PHP core algorithm!*/, '7ea218f6-629a-425f-9f88-7439d63296bb', 'SHAKE128', $category, file_exists(__DIR__.'/SHA3.php'), null]; |
1338 | $out[] = ['shake128'/*Currently no PHP core algorithm!*/, '7ea218f6-629a-425f-9f88-7439d63296bb', 'SHAKE128', $category, file_exists(__DIR__.'/SHA3.php')]; |
1336 | $out[] = ['shake256'/*Currently no PHP core algorithm!*/, '2e7fc6a4-2919-4edc-b0ba-7d7062ce4f0a', 'SHAKE256', $category, file_exists(__DIR__.'/SHA3.php'), null]; |
1339 | $out[] = ['shake256'/*Currently no PHP core algorithm!*/, '2e7fc6a4-2919-4edc-b0ba-7d7062ce4f0a', 'SHAKE256', $category, file_exists(__DIR__.'/SHA3.php')]; |
1337 | - | ||
1338 | // --- |
- | |
1339 | - | ||
1340 | // Proposal https://github.com/ietf-wg-uuidrev/rfc4122bis/issues/143#issuecomment-1709117798 , probably to be put into Draft 12 |
- | |
1341 | $category = 'Internet Draft 12 Proposal'; |
- | |
1342 | $out[] = ['sha224', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.4'), 'SHA-224', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1343 | $out[] = ['sha256', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.1'), 'SHA-256', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1344 | $out[] = ['sha384', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.2'), 'SHA-384', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1345 | $out[] = ['sha512', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.3'), 'SHA-512', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1346 | $out[] = ['sha512/224', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.5'), 'SHA-512/224', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1347 | $out[] = ['sha512/256', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.6'), 'SHA-512/256', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1348 | $out[] = ['sha3-224', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.7'), 'SHA3-224', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1349 | $out[] = ['sha3-256', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.8'), 'SHA3-256', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1350 | $out[] = ['sha3-384', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.9'), 'SHA3-384', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1351 | $out[] = ['sha3-512', gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.10'), 'SHA3-512', $category, PHP_VERSION_ID >= 70100, $oid]; |
- | |
1352 | $out[] = ['shake128'/*Currently no PHP core algorithm!*/, gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.11'), 'SHAKE128', $category, file_exists(__DIR__.'/SHA3.php'), $oid]; |
- | |
1353 | $out[] = ['shake256'/*Currently no PHP core algorithm!*/, gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid='2.16.840.1.101.3.4.2.12'), 'SHAKE256', $category, file_exists(__DIR__.'/SHA3.php'), $oid]; |
- | |
1354 | - | ||
1355 | // --- |
- | |
1356 | - | ||
1357 | // The following Hash Space UUIDs are defined by ViaThinkSoft |
- | |
1358 | // UUIDv8_NamebasedViaThinkSoft := <HashAlgo>_AsUUIDv8( BinaryHashSpaceUUID + BinaryNamespaceUUID + Data ) |
- | |
1359 | // Algorithms which have an OID get defined as follows: |
- | |
1360 | // BinaryHashSpaceUUID := SHA1_AsUUIDv5( hex2bin(NS_OID) + AlgorithmOID ) |
- | |
1361 | // If no OID can be found, the hash space is constructed using a custom namespace and the PHP name as payload: |
- | |
1362 | // BinaryHashSpaceUUID := SHA1_AsUUIDv5( hex2bin('1ee317e2-1853-64b2-8fe9-3c4a92df8582') + PhpHashAlgoName ) |
- | |
1363 | $available_algos = hash_algos(); |
- | |
1364 | $unavailable_algos = []; |
- | |
1365 | if (PHP_VERSION_ID < 80100/*8.1.0*/) { |
- | |
1366 | $unavailable_algos[] = 'murmur3c'; // length: 16 bytes |
- | |
1367 | $unavailable_algos[] = 'murmur3f'; // length: 16 bytes |
- | |
1368 | $unavailable_algos[] = 'xxh128'; // length: 16 bytes |
- | |
1369 | } |
- | |
1370 | if (PHP_VERSION_ID < 99999) { |
- | |
1371 | // How to update this list $unavailable_algos: |
- | |
1372 | // 1. Look if new hashes are listed in the PHP documentation: https://www.php.net/manual/de/function.hash-algos.php |
- | |
1373 | // 2. If the required version is lower than our server version, then you don't need to do anything |
- | |
1374 | // 3. Otherwise, run this command on a different machine (where the algorithms are implemented) to check if the hashes have the correct length |
- | |
1375 | // foreach (hash_algos() as $algo) { |
- | |
1376 | // $len = strlen(hash($algo, '', false)); |
- | |
1377 | // if ($len >= 32) echo "$algo, length $len\n"; |
- | |
1378 | // } |
- | |
1379 | // 4. Then, include all fitting hashes here |
- | |
1380 | // 5. Please publish the new hash space IDs here: https://oidplus.viathinksoft.com/oidplus/?goto=guid%3Auuid_mac_utils%2Fuuidv8_hash_space_vts |
- | |
1381 | } |
- | |
1382 | $all_algos = array_merge($available_algos, $unavailable_algos); |
- | |
1383 | - | ||
1384 | foreach ($all_algos as $algo) { |
- | |
1385 | if ($algo == 'md5') continue; // MD5 is already used in UUIDv3 |
- | |
1386 | if ($algo == 'sha1') continue; // SHA1 is already used in UUIDv5 |
- | |
1387 | foreach ($out as list($algo2,$space,$friendlyName,$author)) { |
- | |
1388 | if ($algo == $algo2) continue 2; // UUID is already defined by RFC, don't need a VTS Hash Space UUID |
- | |
1389 | } |
- | |
1390 | if (in_array($algo,$available_algos) && (strlen(hash($algo,'',false)) < 32)) continue; // Hash too short (needs at least 16 bytes) |
- | |
1391 | - | ||
1392 | // List of OIDs here: https://github.com/ietf-wg-uuidrev/rfc4122bis/issues/143#issuecomment-1709117798 |
- | |
1393 | $oid = null; |
- | |
1394 | if ($algo == 'gost') $oid = '1.2.643.2.2.30.0'; |
- | |
1395 | if ($algo == 'gost-crypto') $oid = '1.2.643.2.2.30.1'; |
- | |
1396 | if ($algo == 'haval128,3') $oid = '1.3.6.1.4.1.18105.2.1.1.1'; |
- | |
1397 | if ($algo == 'haval160,3') $oid = '1.3.6.1.4.1.18105.2.1.1.2'; |
- | |
1398 | if ($algo == 'haval192,3') $oid = '1.3.6.1.4.1.18105.2.1.1.3'; |
- | |
1399 | if ($algo == 'haval224,3') $oid = '1.3.6.1.4.1.18105.2.1.1.4'; |
- | |
1400 | if ($algo == 'haval256,3') $oid = '1.3.6.1.4.1.18105.2.1.1.5'; |
- | |
1401 | if ($algo == 'haval128,4') $oid = '1.3.6.1.4.1.18105.2.1.1.6'; |
- | |
1402 | if ($algo == 'haval160,4') $oid = '1.3.6.1.4.1.18105.2.1.1.7'; |
- | |
1403 | if ($algo == 'haval192,4') $oid = '1.3.6.1.4.1.18105.2.1.1.8'; |
- | |
1404 | if ($algo == 'haval224,4') $oid = '1.3.6.1.4.1.18105.2.1.1.9'; |
- | |
1405 | if ($algo == 'haval256,4') $oid = '1.3.6.1.4.1.18105.2.1.1.10'; |
- | |
1406 | if ($algo == 'haval128,5') $oid = '1.3.6.1.4.1.18105.2.1.1.11'; |
- | |
1407 | if ($algo == 'haval160,5') $oid = '1.3.6.1.4.1.18105.2.1.1.12'; |
- | |
1408 | if ($algo == 'haval192,5') $oid = '1.3.6.1.4.1.18105.2.1.1.13'; |
- | |
1409 | if ($algo == 'haval224,5') $oid = '1.3.6.1.4.1.18105.2.1.1.14'; |
- | |
1410 | if ($algo == 'haval256,5') $oid = '1.3.6.1.4.1.18105.2.1.1.15'; |
- | |
1411 | if ($algo == 'md2') $oid = '1.2.840.113549.2.2'; |
- | |
1412 | if ($algo == 'md4') $oid = '1.2.840.113549.2.4'; |
- | |
1413 | if ($algo == 'ripemd128') $oid = '1.3.36.3.2.2'; // or 1.0.10118.3.0.50 |
- | |
1414 | if ($algo == 'ripemd160') $oid = '1.3.36.3.2.1'; // or 1.0.10118.3.0.49 |
- | |
1415 | if ($algo == 'ripemd256') $oid = '1.3.36.3.2.3'; |
- | |
1416 | if ($algo == 'whirlpool') $oid = '1.0.10118.3.0.55'; |
- | |
1417 | - | ||
1418 | if ($oid == null) { |
- | |
1419 | $out[] = [$algo, gen_uuid_v5('1ee317e2-1853-64b2-8fe9-3c4a92df8582', $algo), strtoupper($algo), 'ViaThinkSoft by PHP name', in_array($algo,$available_algos), $oid]; |
- | |
1420 | } else { |
- | |
1421 | $out[] = [$algo, gen_uuid_v5(UUID_NAMEBASED_NS_OID, $oid), strtoupper($algo), 'ViaThinkSoft by OID', in_array($algo,$available_algos), $oid]; |
- | |
1422 | } |
- | |
1423 | } |
- | |
1424 | 1340 | ||
1425 | return $out; |
1341 | return $out; |
1426 | } |
1342 | } |
1427 | 1343 | ||
1428 | # -------------------------------------- |
1344 | # -------------------------------------- |