Skip to content

Instantly share code, notes, and snippets.

@mhavrlent
Created April 12, 2021 17:07
Show Gist options
  • Save mhavrlent/e9a8f8407b1dbf0346b3f740a22997d5 to your computer and use it in GitHub Desktop.
Save mhavrlent/e9a8f8407b1dbf0346b3f740a22997d5 to your computer and use it in GitHub Desktop.
Decrypt Chrome (>=80) cookies on Windows OS using Java and use them in REST API calls (Spring RestTemplate)
package test;
import com.sun.jna.platform.win32.Crypt32Util;
import org.json.JSONObject;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.sql.*;
import java.util.Arrays;
import java.util.Base64;
/*
* The encrypted data start with the ASCII encoding of v10 (i.e. 0x763130),
* followed by the 12 bytes nonce, the actual ciphertext
* and finally the 16 bytes authentication tag.
*
* Since in Java ciphertext and tag are processed in concatenated form,
* only a separation of nonce and ciphertext/tag is necessary.
*/
public class App {
public static void main(String[] args) {
Connection conn = null;
try {
String cookieDbPath = "C:/Users/user/AppData/Local/Google/Chrome/User Data/Profile 1/Cookies";
String keyFilePath = "C:/Users/user/AppData/Local/Google/Chrome/User Data/Local State";
// we need to copy cookie database because it's locked by Chrome
String cookieDbCopyPath = "cookie_copy";
Files.copy(new File(cookieDbPath).toPath(),
new File(cookieDbCopyPath).toPath(),
StandardCopyOption.REPLACE_EXISTING);
// read cookies from the copied cookie database
String url = "jdbc:sqlite:cookie_copy";
conn = DriverManager.getConnection(url);
String domain = "%jira.example.com";
PreparedStatement preparedStatement = conn.prepareStatement("SELECT host_key, path, is_secure, expires_utc, name, value, encrypted_value FROM cookies WHERE host_key like ?;");
preparedStatement.setString(1, domain);
ResultSet rs = preparedStatement.executeQuery();
HttpHeaders requestHeaders = new HttpHeaders();
// loop through the DB result set, decrypt cookies and add them to the request header
while (rs.next()) {
String host_key = rs.getString("host_key");
System.out.println(String.format("Host key: %s", host_key));
String name = rs.getString("name");
System.out.println(String.format("Name: %s", name));
byte[] encryptedValue = rs.getBytes("encrypted_value");
// skip v10 at the beginning
if (new String(encryptedValue).startsWith("v10")) {
encryptedValue = Arrays.copyOfRange(encryptedValue, 3, encryptedValue.length);
}
// decrypt key
byte[] nonce = Arrays.copyOfRange(encryptedValue, 0, 12);
byte[] cipherTextWithTag = Arrays.copyOfRange(encryptedValue, 12, encryptedValue.length);
String text = new String(Files.readAllBytes(Paths.get(keyFilePath)), StandardCharsets.UTF_8);
JSONObject obj = new JSONObject(text);
String key64 = obj.getJSONObject("os_crypt").getString("encrypted_key");
byte[] keyDpapi = Base64.getDecoder().decode(key64);
keyDpapi = Arrays.copyOfRange(keyDpapi, 5, keyDpapi.length);
byte[] decryptedKeyBytes = Crypt32Util.cryptUnprotectData(keyDpapi);
// decrypt value
GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(128, nonce);
Cipher aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec aesKey = new SecretKeySpec(decryptedKeyBytes, "AES");
aesCipher.init(Cipher.DECRYPT_MODE, aesKey, gcmParameterSpec);
byte[] decryptedBytes = aesCipher.doFinal(cipherTextWithTag);
String decryptedValue = new String(decryptedBytes);
System.out.println(String.format("Decrypted value: %s", decryptedValue));
System.out.println();
// add decrypted cookie to the request header
requestHeaders.add("Cookie", String.format("%s=%s", name, decryptedValue));
}
// send request with cookies in the header
RestTemplate restTemplate = new RestTemplate();
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity response = restTemplate.exchange(
"https://jira.example.com/rest/api/latest/search?jql={jql}&maxResults=1",
HttpMethod.GET,
requestEntity,
String.class,
"project=PROJECT1");
if (response.getStatusCode() == HttpStatus.OK) {
Object responseBody = response.getBody();
System.out.println(responseBody.toString());
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException ex) {
System.out.println(ex.getMessage());
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment