Subversion Repositories uuid_mac_utils

Rev

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
# --------------------------------------