Index: components/history/core/browser/download_database.cc |
diff --git a/components/history/core/browser/download_database.cc b/components/history/core/browser/download_database.cc |
index 93b707c9fe22f76c0bfbac30ce721b4710e40289..cc4508746cdc215105af6e3bfe131c799e5fc470 100644 |
--- a/components/history/core/browser/download_database.cc |
+++ b/components/history/core/browser/download_database.cc |
@@ -192,27 +192,61 @@ bool DownloadDatabase::MigrateHashHttpMethodAndGenerateGuids() { |
!EnsureColumnExists("http_method", "VARCHAR NOT NULL DEFAULT ''")) |
return false; |
- // Generate GUIDs for each download. The GUID is generated thusly: |
+ // Generate GUIDs for each download. GUIDs based on random data should conform |
+ // with RFC 4122 section 4.4. Given the following field layout (based on RFC |
+ // 4122): |
// |
- // XXXXXXXX-RRRR-RRRR-RRRR-RRRRRRRRRRRR |
+ // 0 1 2 3 |
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ // | time_low | |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ // | time_mid | time_hi_and_version | |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ // |clk_seq_hi_res | clk_seq_low | node (0-1) | |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ // | node (2-5) | |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ // |
+ // * Bits 4-7 of time_hi_and_version should be set to 0b0100 == 4 |
+ // * Bits 6-7 of clk_seq_hi_res should be set to 0b10 |
+ // * All other bits should be random or pseudorandom. |
+ // |
+ // We are going to take the liberty of setting time_low to the 32-bit download |
+ // ID. That will guarantee that no two randomly generated GUIDs will collide |
+ // even if the 90 bits of entropy doesn't save us. |
+ // |
+ // Translated to the canonical string representation, the GUID is generated |
+ // thusly: |
+ // |
+ // XXXXXXXX-RRRR-4RRR-yRRR-RRRRRRRRRRRR |
// \__ __/ \___________ ____________/ |
// \/ \/ |
- // | Random hex digits |
+ // | R = random hex digit. |
+ // | y = one of {'8','9','A','B'} selected randomly. |
+ // | 4 = the character '4'. |
// | |
// Hex representation of 32-bit download ID. |
// |
- // The 96 random bits provide entropy while the 32-bits from the download ID |
- // ensure that the generated identifiers will at least be unique amongst the |
- // download rows in the unlikely event there's a collision in the 96 entropy |
- // bits. |
- // |
// This GUID generation scheme is only used for migrated download rows and |
// assumes that the likelihood of a collision with a GUID generated via |
// base::GenerateGUID() will be vanishingly small. |
+ // |
+ // A previous version of this code generated GUIDs that used random bits for |
+ // all but the first 32-bits. I.e. the scheme didn't respect the 6 fixed bits |
+ // as prescribed for type 4 GUIDs. The resulting GUIDs are not believed to |
+ // have an elevated risk of collision with GUIDs generated via |
+ // base::GenerateGUID() and are considered valid by all known consumers. Hence |
+ // no additional migration logic is being introduced to fix those GUIDs. |
const char kMigrateGuidsQuery[] = |
"UPDATE downloads SET guid = printf" |
- "(\"%08X-%s-%s-%s-%s\", id, hex(randomblob(2)), hex(randomblob(2))," |
- " hex(randomblob(2)), hex(randomblob(6)))"; |
+ "(\"%08X-%s-4%s-%01X%s-%s\"," |
+ " id," |
+ " hex(randomblob(2))," |
+ " substr(hex(randomblob(2)),2)," |
+ " (8 | (random() & 3))," |
+ " substr(hex(randomblob(2)),2)," |
+ " hex(randomblob(6)))"; |
return GetDB().Execute(kMigrateGuidsQuery); |
} |