Minimal object containing this commit
Commit Diff
commit f37388f483735fcaee943ebcff82d187e4bc9e27655fa6cbfe9d57dd79bcd1ce
Author: yihanwu1024 <yihanwu1024>
Date: Sun Oct 30 00:00:00 2022 +0000
create memo about a method to migrate Chromium browser data on Windows
diff --git a/0dd0b00991b62df340f5cdfb40c6a90e6e43ff2749a363a9ae924f9a4868867f b/0dd0b00991b62df340f5cdfb40c6a90e6e43ff2749a363a9ae924f9a4868867f
new file mode 100644
index 0000000..3d999c8
--- /dev/null
+++ b/0dd0b00991b62df340f5cdfb40c6a90e6e43ff2749a363a9ae924f9a4868867f
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="0dd0b00991b62df340f5cdfb40c6a90e6e43ff2749a363a9ae924f9a4868867f">
+<title>Edit <literal>Local State</literal> with new <literal>encrypted_key</literal> value</title>
+<para>Now you can close Chromium, copy your data, and change the <literal>encrypted_key</literal> value to what you got in the previous step.</para>
+<para>Chromium migration is complete.</para>
+</section>
diff --git a/1e73bf4502a9de1eee0055fa410b5649c8adc9b2bf07b782f730b0c7f59e635a b/1e73bf4502a9de1eee0055fa410b5649c8adc9b2bf07b782f730b0c7f59e635a
new file mode 100644
index 0000000..02b68a5
--- /dev/null
+++ b/1e73bf4502a9de1eee0055fa410b5649c8adc9b2bf07b782f730b0c7f59e635a
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="1e73bf4502a9de1eee0055fa410b5649c8adc9b2bf07b782f730b0c7f59e635a">
+<title>Transform the <literal>encrypted_key</literal> value</title>
+<para>Your <literal>encrypted_key</literal> value is in base64 and has an extra header inside.
+Turn it into a raw byte array and remove the header with</para>
+<programlisting>$encrypted_key_data = [Convert]::FromBase64String($encrypted_key)[5..9999]</programlisting>
+</section>
diff --git a/3123d5e4feb6b716fa9131aabbb6f20fa748475d9d9c4a50be48cc167b00d12e b/3123d5e4feb6b716fa9131aabbb6f20fa748475d9d9c4a50be48cc167b00d12e
new file mode 100644
index 0000000..f24efd5
--- /dev/null
+++ b/3123d5e4feb6b716fa9131aabbb6f20fa748475d9d9c4a50be48cc167b00d12e
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="3123d5e4feb6b716fa9131aabbb6f20fa748475d9d9c4a50be48cc167b00d12e">
+<title>Get the <literal>encrypted_key</literal> value from Chromium <literal>Local State</literal> file</title>
+<para>Navigate to your Chromium user data directory.
+For example, Chrome is at <literal>%USERPROFILE%\AppData\Local\Google\Chrome\User Data\</literal>.
+Open <literal>Local State</literal> with a text editor.
+This file is a giant JSON.
+Search for the <literal>encrypted_key</literal> key, and copy down its value (from after the colon and double quote to before the next double quote.)</para>
+</section>
diff --git a/37434c01fc3e2a32bd83a1b5d632ef9919bfe323dd7b38914e5d044d0eec88d5 b/37434c01fc3e2a32bd83a1b5d632ef9919bfe323dd7b38914e5d044d0eec88d5
new file mode 100644
index 0000000..c3a4454
--- /dev/null
+++ b/37434c01fc3e2a32bd83a1b5d632ef9919bfe323dd7b38914e5d044d0eec88d5
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="37434c01fc3e2a32bd83a1b5d632ef9919bfe323dd7b38914e5d044d0eec88d5">
+<title>TL; DR; Copy; Paste</title>
+<para>You still need to import <literal>ProtectedData</literal>.
+Then, in your Chromium User Data directory (where there are <literal>Local State</literal> and <literal>Local State Unprotected Key</literal> files created in the previous step):</para>
+<programlisting>$unprotected_key = [byte[]] (Get-Content '.\Local State Unprotected Key'); $encrypted_key_data = [System.Security.Cryptography.ProtectedData]::Protect($unprotected_key, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser); $encrypted_key_data = [byte]68,80,65,80,73 + $encrypted_key_data; $encrypted_key = [Convert]::ToBase64String($encrypted_key_data); $json = (Get-Content '.\Local State' -Encoding UTF8 | ConvertFrom-Json); $json.os_crypt.encrypted_key = $encrypted_key; ConvertTo-Json -InputObject $json -Depth 8 -Compress | Out-File 'Local State' -Encoding utf8</programlisting>
+<para>You might want to delete the migration file <literal>Local State Unprotected Key</literal>.</para>
+<para>The individual steps are below.</para>
+</section>
diff --git a/ab4ce424e032db1cbf19b4fa86588bf76da1268e78ff02ab88dc53490d93f06a b/ab4ce424e032db1cbf19b4fa86588bf76da1268e78ff02ab88dc53490d93f06a
new file mode 100644
index 0000000..812c2e4
--- /dev/null
+++ b/ab4ce424e032db1cbf19b4fa86588bf76da1268e78ff02ab88dc53490d93f06a
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="ab4ce424e032db1cbf19b4fa86588bf76da1268e78ff02ab88dc53490d93f06a">
+<title>Unprotect the data</title>
+<para>Now the data is ready to be processed with DPAPI.
+Do this:</para>
+<programlisting>$unprotected_key = [System.Security.Cryptography.ProtectedData]::Unprotect($encrypted_key_data, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)</programlisting>
+<para>It should be 128 bits (32 bytes) as of Chromium 107.</para>
+<para>Somehow note down the value of<literal>$unprotected_key</literal>.</para>
+</section>
diff --git a/af4fe462c85e030cac8c15a33b77f9b9894ec332999b2bf7afbd1f1862949ee2 b/af4fe462c85e030cac8c15a33b77f9b9894ec332999b2bf7afbd1f1862949ee2
new file mode 100644
index 0000000..2d27777
--- /dev/null
+++ b/af4fe462c85e030cac8c15a33b77f9b9894ec332999b2bf7afbd1f1862949ee2
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="af4fe462c85e030cac8c15a33b77f9b9894ec332999b2bf7afbd1f1862949ee2">
+<title>Import <literal>ProtectedData</literal> to PowerShell</title>
+<para>Yeah, you have to do it again.</para>
+</section>
diff --git a/bdf7c009a1bb58620061b5aeb8aa4ea5b11eab76497a379eda978546628e9631 b/bdf7c009a1bb58620061b5aeb8aa4ea5b11eab76497a379eda978546628e9631
new file mode 100644
index 0000000..5d23aa4
--- /dev/null
+++ b/bdf7c009a1bb58620061b5aeb8aa4ea5b11eab76497a379eda978546628e9631
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="bdf7c009a1bb58620061b5aeb8aa4ea5b11eab76497a379eda978546628e9631">
+<title>Protect the data</title>
+<para>I believe you have typed your <literal>$unprotected_key</literal> carefully into PowerShell.
+Make sure it is a byte array.
+Then, do this:</para>
+<programlisting>$encrypted_key_data = [System.Security.Cryptography.ProtectedData]::Protect($unprotected_key, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser)</programlisting>
+</section>
diff --git a/c277e9b50383e6cfd0791518bb1b271be702febdb9eee1144751b03203f8d83b b/c277e9b50383e6cfd0791518bb1b271be702febdb9eee1144751b03203f8d83b
new file mode 100644
index 0000000..8137f23
--- /dev/null
+++ b/c277e9b50383e6cfd0791518bb1b271be702febdb9eee1144751b03203f8d83b
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="c277e9b50383e6cfd0791518bb1b271be702febdb9eee1144751b03203f8d83b">
+<title>On the target computer</title>
+<include xmlns="http://www.w3.org/2001/XInclude" href="37434c01fc3e2a32bd83a1b5d632ef9919bfe323dd7b38914e5d044d0eec88d5"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="af4fe462c85e030cac8c15a33b77f9b9894ec332999b2bf7afbd1f1862949ee2"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="bdf7c009a1bb58620061b5aeb8aa4ea5b11eab76497a379eda978546628e9631"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="cc494678e68ffeffbdd41b10d47e24f0bd8dd40d03b05de48f5e633ea0b70a33"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="0dd0b00991b62df340f5cdfb40c6a90e6e43ff2749a363a9ae924f9a4868867f"/>
+</section>
diff --git a/c29e58a3d7f243fd0987926ea625adfd04bd58253b96b2ae6f197191510a26b2 b/c29e58a3d7f243fd0987926ea625adfd04bd58253b96b2ae6f197191510a26b2
new file mode 100644
index 0000000..613791c
--- /dev/null
+++ b/c29e58a3d7f243fd0987926ea625adfd04bd58253b96b2ae6f197191510a26b2
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="c29e58a3d7f243fd0987926ea625adfd04bd58253b96b2ae6f197191510a26b2">
+<title>On the source computer</title>
+<include xmlns="http://www.w3.org/2001/XInclude" href="dc775bf57f268e573a34292ffc21ae6f67e49871b4354c2895684bd05cfc91a1"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="cb2e2322bf0be91012f68c13938576af51b2d0542ede39c9dd166653be7f57a3"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="3123d5e4feb6b716fa9131aabbb6f20fa748475d9d9c4a50be48cc167b00d12e"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="1e73bf4502a9de1eee0055fa410b5649c8adc9b2bf07b782f730b0c7f59e635a"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="ab4ce424e032db1cbf19b4fa86588bf76da1268e78ff02ab88dc53490d93f06a"/>
+</section>
diff --git a/c8d4ce49e7b92556278b2c33d05bfbe70a401def0ec93d1b585fe2d18fe4ea82 b/c8d4ce49e7b92556278b2c33d05bfbe70a401def0ec93d1b585fe2d18fe4ea82
new file mode 100644
index 0000000..b002364
--- /dev/null
+++ b/c8d4ce49e7b92556278b2c33d05bfbe70a401def0ec93d1b585fe2d18fe4ea82
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<article xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xml:id="c8d4ce49e7b92556278b2c33d05bfbe70a401def0ec93d1b585fe2d18fe4ea82">
+<title>Chromium Browser Data Migration on Windows</title>
+<para>Modern Chromium utilizes the Windows Data Protection API (DPAPI), specifically <literal>CryptProtectData()</literal>.
+Data migration cannot be done by simply copying the data directory to another computer, because the data would be encrypted with a key only available on the source computer.
+Fortunately, it turns out to be fairly simple to migrate Chromium user data, thanks to the design that Chromium envelops the encryption mechanism by one layer.
+The function <literal>CryptProtectData()</literal> does not encrypt the data directly, but rather a standalone AES key in the <literal>Local State</literal> file, and this key is in turn used to encrypt confidential data such as cookies and website credentials.
+Therefore, one easy way to migrate Chromium is to decrypt this Local State key and reencrypt it within the new environment.
+The process is simple enough to perform manually.</para>
+<include xmlns="http://www.w3.org/2001/XInclude" href="c29e58a3d7f243fd0987926ea625adfd04bd58253b96b2ae6f197191510a26b2"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="c277e9b50383e6cfd0791518bb1b271be702febdb9eee1144751b03203f8d83b"/>
+<include xmlns="http://www.w3.org/2001/XInclude" href="cfa9cc64db910311cd27b0129f0155d58d0a278b46231cd3d409dda99793e74f"/>
+</article>
diff --git a/cb2e2322bf0be91012f68c13938576af51b2d0542ede39c9dd166653be7f57a3 b/cb2e2322bf0be91012f68c13938576af51b2d0542ede39c9dd166653be7f57a3
new file mode 100644
index 0000000..d273766
--- /dev/null
+++ b/cb2e2322bf0be91012f68c13938576af51b2d0542ede39c9dd166653be7f57a3
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="cb2e2322bf0be91012f68c13938576af51b2d0542ede39c9dd166653be7f57a3">
+<title>Import <literal>ProtectedData</literal> to PowerShell</title>
+<para><literal>System.Security.Cryptography.ProtectedData</literal> is a Microsoft .NET Core library that handles DPAPI calls.
+You can <link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="https://www.nuget.org/packages/System.Security.Cryptography.ProtectedData/4.7.0">download it from NuGet</link>.
+The following procedure has been tested with version 4.6.1 of the library.</para>
+<para>.nupkg packages are zip files.
+Change the extension and extract a <literal>System.Security.Cryptography.ProtectedData.dll</literal> file.</para>
+<para>Then, open a Windows PowerShell window and use the following command to import the library to the current session.
+You may need to change your PowerShell execution policy and unblock the downloaded file for this step.</para>
+<programlisting>Add-Type -Path <Path to library></programlisting>
+</section>
diff --git a/cc494678e68ffeffbdd41b10d47e24f0bd8dd40d03b05de48f5e633ea0b70a33 b/cc494678e68ffeffbdd41b10d47e24f0bd8dd40d03b05de48f5e633ea0b70a33
new file mode 100644
index 0000000..56b1a01
--- /dev/null
+++ b/cc494678e68ffeffbdd41b10d47e24f0bd8dd40d03b05de48f5e633ea0b70a33
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="cc494678e68ffeffbdd41b10d47e24f0bd8dd40d03b05de48f5e633ea0b70a33">
+<title>Transform to an <literal>encrypted_key</literal> value</title>
+<para>The following command adds that header back:</para>
+<programlisting>$encrypted_key_data = [byte]68,80,65,80,73 + $encrypted_key_data</programlisting>
+<para>And this one converts it to base64:</para>
+<programlisting>$encrypted_key = [Convert]::ToBase64String($encrypted_key_data)</programlisting>
+</section>
diff --git a/cfa9cc64db910311cd27b0129f0155d58d0a278b46231cd3d409dda99793e74f b/cfa9cc64db910311cd27b0129f0155d58d0a278b46231cd3d409dda99793e74f
new file mode 100644
index 0000000..22b9b08
--- /dev/null
+++ b/cfa9cc64db910311cd27b0129f0155d58d0a278b46231cd3d409dda99793e74f
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="cfa9cc64db910311cd27b0129f0155d58d0a278b46231cd3d409dda99793e74f">
+<title>Wait, does this mean my Chromium (Electron) data is available to all programs running as the current user?</title>
+<para>Yes.</para>
+</section>
diff --git a/dc775bf57f268e573a34292ffc21ae6f67e49871b4354c2895684bd05cfc91a1 b/dc775bf57f268e573a34292ffc21ae6f67e49871b4354c2895684bd05cfc91a1
new file mode 100644
index 0000000..e770942
--- /dev/null
+++ b/dc775bf57f268e573a34292ffc21ae6f67e49871b4354c2895684bd05cfc91a1
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<section xmlns="http://docbook.org/ns/docbook" xml:id="dc775bf57f268e573a34292ffc21ae6f67e49871b4354c2895684bd05cfc91a1">
+<title>TL; DR; Copy; Paste</title>
+<para>First, import <literal>ProtectedData</literal> to PowerShell as described in the immediate next section.
+Next, in your Chromium User Data directory (where there is a <literal>Local State</literal> file):</para>
+<programlisting>$json = (Get-Content '.\Local State' -Encoding UTF8 | ConvertFrom-Json); $encrypted_key = $json.os_crypt.encrypted_key; $encrypted_key_data = [Convert]::FromBase64String($encrypted_key)[5..9999]; [System.Security.Cryptography.ProtectedData]::Unprotect($encrypted_key_data, $null, [System.Security.Cryptography.DataProtectionScope]::CurrentUser) | Out-File '.\Local State Unprotected Key'</programlisting>
+<para>The individual steps for the emigration are below.
+After you are done with emigration, go to the next section to perform immigration.</para>
+</section>