From 69ce4ca584fb26d0bdad9d5183acf892cd904468 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sat, 7 Jun 2025 02:58:12 +0800 Subject: [PATCH 01/13] Update uuid.py --- Lib/uuid.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 06f81a7c338372..e4a87b674ddf11 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -666,8 +666,8 @@ def _random_getnode(): # counting from 1 being the least significant bit, or 1<<40. # # See https://en.wikipedia.org/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit) - import random - return random.getrandbits(48) | (1 << 40) + import secrets + return secrets.randbits(48) | (1 << 40) # _OS_GETTERS, when known, are targeted for a specific OS or platform. @@ -746,8 +746,8 @@ def uuid1(node=None, clock_seq=None): timestamp = _last_timestamp + 1 _last_timestamp = timestamp if clock_seq is None: - import random - clock_seq = random.getrandbits(14) # instead of stable storage + import secrets + clock_seq = secrets.randbits(14) # instead of stable storage time_low = timestamp & 0xffffffff time_mid = (timestamp >> 32) & 0xffff time_hi_version = (timestamp >> 48) & 0x0fff @@ -809,8 +809,8 @@ def uuid6(node=None, clock_seq=None): timestamp = _last_timestamp_v6 + 1 _last_timestamp_v6 = timestamp if clock_seq is None: - import random - clock_seq = random.getrandbits(14) # instead of stable storage + import secrets + clock_seq = secrets.randbits(14) # instead of stable storage time_hi_and_mid = (timestamp >> 12) & 0xffff_ffff_ffff time_lo = timestamp & 0x0fff # keep 12 bits and clear version bits clock_s = clock_seq & 0x3fff # keep 14 bits and clear variant bits @@ -913,14 +913,14 @@ def uuid8(a=None, b=None, c=None): When a value is not specified, a pseudo-random value is generated. """ if a is None: - import random - a = random.getrandbits(48) + import secrets + a = secrets.randbits(48) if b is None: - import random - b = random.getrandbits(12) + import secrets + b = secrets.randbits(48) if c is None: - import random - c = random.getrandbits(62) + import secrets + c = secrets.randbits(48) int_uuid_8 = (a & 0xffff_ffff_ffff) << 80 int_uuid_8 |= (b & 0xfff) << 64 int_uuid_8 |= c & 0x3fff_ffff_ffff_ffff From bc83fa10b71bc309a5c575ebd5237b5d9bfbfa21 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 17:49:52 +0800 Subject: [PATCH 02/13] Update uuid.py --- Lib/uuid.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index e4a87b674ddf11..87a8c48043d1f4 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -746,8 +746,8 @@ def uuid1(node=None, clock_seq=None): timestamp = _last_timestamp + 1 _last_timestamp = timestamp if clock_seq is None: - import secrets - clock_seq = secrets.randbits(14) # instead of stable storage + import random + clock_seq = random.getrandbits(14) # instead of stable storage time_low = timestamp & 0xffffffff time_mid = (timestamp >> 32) & 0xffff time_hi_version = (timestamp >> 48) & 0x0fff @@ -809,8 +809,8 @@ def uuid6(node=None, clock_seq=None): timestamp = _last_timestamp_v6 + 1 _last_timestamp_v6 = timestamp if clock_seq is None: - import secrets - clock_seq = secrets.randbits(14) # instead of stable storage + import random + clock_seq = random.getrandbits(14) # instead of stable storage time_hi_and_mid = (timestamp >> 12) & 0xffff_ffff_ffff time_lo = timestamp & 0x0fff # keep 12 bits and clear version bits clock_s = clock_seq & 0x3fff # keep 14 bits and clear variant bits @@ -913,14 +913,14 @@ def uuid8(a=None, b=None, c=None): When a value is not specified, a pseudo-random value is generated. """ if a is None: - import secrets - a = secrets.randbits(48) + import random + a = random.getrandbits(48) if b is None: - import secrets - b = secrets.randbits(48) + import random + b = random.getrandbits(48) if c is None: - import secrets - c = secrets.randbits(48) + import random + c = random.getrandbits(48) int_uuid_8 = (a & 0xffff_ffff_ffff) << 80 int_uuid_8 |= (b & 0xfff) << 64 int_uuid_8 |= c & 0x3fff_ffff_ffff_ffff From e52954668476377333d49c1f1c25050d12f58ccf Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 17:51:25 +0800 Subject: [PATCH 03/13] Update uuid.py --- Lib/uuid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 87a8c48043d1f4..947dd329fb1c61 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -917,10 +917,10 @@ def uuid8(a=None, b=None, c=None): a = random.getrandbits(48) if b is None: import random - b = random.getrandbits(48) + b = random.getrandbits(12) if c is None: import random - c = random.getrandbits(48) + c = random.getrandbits(62) int_uuid_8 = (a & 0xffff_ffff_ffff) << 80 int_uuid_8 |= (b & 0xfff) << 64 int_uuid_8 |= c & 0x3fff_ffff_ffff_ffff From 4e68299a2fbb3684cc38c2fa9221f8db8181fd82 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 17:59:22 +0800 Subject: [PATCH 04/13] Update uuid.rst --- Doc/library/uuid.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 8cce6b98cbcdb3..59dd16ee770b9d 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -255,7 +255,8 @@ The :mod:`uuid` module defines the following functions: positive integers of 48, 12 and 62 bits respectively. If they exceed their expected bit count, only their least significant bits are kept; non-specified arguments are substituted for a pseudo-random integer of - appropriate size. + appropriate size. Note that *a*, *b* and *c* are generated by PRNG (not CSPRNG) + so use UUIDv4 if you are generating a token or verification code. .. versionadded:: 3.14 From c225ab82c49fdd42d3b1d43cd72c8128452c0120 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 18:06:37 +0800 Subject: [PATCH 05/13] Update uuid.py --- Lib/uuid.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 947dd329fb1c61..6842514ae5a302 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -666,8 +666,8 @@ def _random_getnode(): # counting from 1 being the least significant bit, or 1<<40. # # See https://en.wikipedia.org/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit) - import secrets - return secrets.randbits(48) | (1 << 40) + + return (int.from_bytes(__import__('os').urandom(6), 'big')) | (1 << 40) # _OS_GETTERS, when known, are targeted for a specific OS or platform. From 5006c19724e3c0edc6a886afeebf0529f79597d1 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 18:12:31 +0800 Subject: [PATCH 06/13] Update Doc/library/uuid.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Doc/library/uuid.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Doc/library/uuid.rst b/Doc/library/uuid.rst index 59dd16ee770b9d..747ee3ee0e1951 100644 --- a/Doc/library/uuid.rst +++ b/Doc/library/uuid.rst @@ -255,8 +255,11 @@ The :mod:`uuid` module defines the following functions: positive integers of 48, 12 and 62 bits respectively. If they exceed their expected bit count, only their least significant bits are kept; non-specified arguments are substituted for a pseudo-random integer of - appropriate size. Note that *a*, *b* and *c* are generated by PRNG (not CSPRNG) - so use UUIDv4 if you are generating a token or verification code. + appropriate size. + + By default, *a*, *b* and *c* are generated by a non-cryptographically + secure pseudo-random number generator (CSPRNG). Use :func:`uuid4` when + a UUID needs to be used in a security-sensitive context. .. versionadded:: 3.14 From b11ea0588892a2877a06c5915e00f25ed1424019 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 18:15:20 +0800 Subject: [PATCH 07/13] Update uuid.py --- Lib/uuid.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 6842514ae5a302..b5e22c7a3be758 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -667,7 +667,7 @@ def _random_getnode(): # # See https://en.wikipedia.org/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit) - return (int.from_bytes(__import__('os').urandom(6), 'big')) | (1 << 40) + return (int.from_bytes(os.urandom(6), 'big')) | (1 << 40) # _OS_GETTERS, when known, are targeted for a specific OS or platform. From 99bedcc56266031df72beb8acf38c8cd600bad80 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 18:19:07 +0800 Subject: [PATCH 08/13] Update Lib/uuid.py MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- Lib/uuid.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index b5e22c7a3be758..e39aa839659f4b 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -666,8 +666,7 @@ def _random_getnode(): # counting from 1 being the least significant bit, or 1<<40. # # See https://en.wikipedia.org/w/index.php?title=MAC_address&oldid=1128764812#Universal_vs._local_(U/L_bit) - - return (int.from_bytes(os.urandom(6), 'big')) | (1 << 40) + return int.from_bytes(os.urandom(6)) | (1 << 40) # _OS_GETTERS, when known, are targeted for a specific OS or platform. From 0500d0643361411eeaee3784c061ea358e278598 Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Sun, 8 Jun 2025 10:22:24 +0000 Subject: [PATCH 09/13] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20b?= =?UTF-8?q?lurb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst diff --git a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst new file mode 100644 index 00000000000000..8612079e2a23d0 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst @@ -0,0 +1,2 @@ +Python used to generare random Node ID of UUID when it failed to get the MAC address by PRNG. +the random Node ID is now generated by a CSPRNG for security reasons. From 4b8a59e669ee3359150676b98cf9b804520543f0 Mon Sep 17 00:00:00 2001 From: LamentXU <108666168+LamentXU123@users.noreply.github.com> Date: Sun, 8 Jun 2025 19:07:33 +0800 Subject: [PATCH 10/13] Update Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> --- .../Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst index 8612079e2a23d0..93ca4c37ae14eb 100644 --- a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst +++ b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst @@ -1,2 +1,4 @@ -Python used to generare random Node ID of UUID when it failed to get the MAC address by PRNG. -the random Node ID is now generated by a CSPRNG for security reasons. +:mod:`uuid`: when the MAC address cannot be determined, the 48-bit node +ID is now generated with a cryptographically-secure pseudo-random number +generator (CSPRNG) as per :rfc:`RFC 9562, §6.10 <9562#section-6.10>`. +This affects :func:`~uuid.uuid1` and :func:`~uuid.uuid6`. From c5249d4c405dd066889a634e0af5fe9bcae1771c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 8 Jun 2025 13:15:56 +0200 Subject: [PATCH 11/13] update historical note --- Lib/uuid.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index e39aa839659f4b..73c5b3db227fd6 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -656,10 +656,13 @@ def _windll_getnode(): def _random_getnode(): """Get a random node ID.""" - # RFC 4122, $4.1.6 says "For systems with no IEEE address, a randomly or - # pseudo-randomly generated value may be used; see Section 4.5. The - # multicast bit must be set in such addresses, in order that they will - # never conflict with addresses obtained from network cards." + # RFC 9562, §6.10 says that + # + # Implementations MAY elect to obtain a 48-bit cryptographic-quality + # random number as per Section 6.9 to use as the Node ID. [...] [and] + # implementations MUST set the least significant bit of the first octet + # of the Node ID to 1. This bit is the unicast or multicast bit, which + # will never be set in IEEE 802 addresses obtained from network cards. # # The "multicast bit" of a MAC address is defined to be "the least # significant bit of the first octet". This works out to be the 41st bit From ffe0074ae3003e0f26e95d77f7b2ef0789286220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 8 Jun 2025 13:18:35 +0200 Subject: [PATCH 12/13] Apply suggestions from code review --- Lib/uuid.py | 2 +- .../Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Lib/uuid.py b/Lib/uuid.py index 73c5b3db227fd6..313f2fc46cb346 100644 --- a/Lib/uuid.py +++ b/Lib/uuid.py @@ -656,7 +656,7 @@ def _windll_getnode(): def _random_getnode(): """Get a random node ID.""" - # RFC 9562, §6.10 says that + # RFC 9562, §6.10-3 says that # # Implementations MAY elect to obtain a 48-bit cryptographic-quality # random number as per Section 6.9 to use as the Node ID. [...] [and] diff --git a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst index 93ca4c37ae14eb..58d792260ac959 100644 --- a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst +++ b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst @@ -1,4 +1,5 @@ :mod:`uuid`: when the MAC address cannot be determined, the 48-bit node ID is now generated with a cryptographically-secure pseudo-random number -generator (CSPRNG) as per :rfc:`RFC 9562, §6.10 <9562#section-6.10>`. +generator (CSPRNG) as per :rfc:`RFC 9562, §6.10.3 <9562#section-6.10-3>`. + This affects :func:`~uuid.uuid1` and :func:`~uuid.uuid6`. From 6241d9979fd4b35c7979609e6b0855f15d216be3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A9n=C3=A9dikt=20Tran?= <10796600+picnixz@users.noreply.github.com> Date: Sun, 8 Jun 2025 13:19:00 +0200 Subject: [PATCH 13/13] Update Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst --- .../next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst index 58d792260ac959..1f70358e64e2a0 100644 --- a/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst +++ b/Misc/NEWS.d/next/Library/2025-06-08-10-22-22.gh-issue-135244.Y2SOTJ.rst @@ -1,5 +1,4 @@ :mod:`uuid`: when the MAC address cannot be determined, the 48-bit node ID is now generated with a cryptographically-secure pseudo-random number generator (CSPRNG) as per :rfc:`RFC 9562, §6.10.3 <9562#section-6.10-3>`. - This affects :func:`~uuid.uuid1` and :func:`~uuid.uuid6`.