gk-encrypt and gk-decrypt
These packages are used to encrypt and decrypt GitKraken's secFiles, which contain sensitive data such as access tokens.
They are primarily intended for use by the gk-login package, but can also be used independently.
Although their execution is considered safe (since they only read the secFiles and output results to stdout), they are provided as-is, with no warranty.
Usage
gk-encrypt
txt
usage: gk-encrypt [-h] -o FILE [-v]
Encrypt JSON data as GitKraken secret.
options:
-h, --help show this help message and exit
-o, --output FILE write encrypted output to FILE (e.g.,
$HOME/.gitkraken/secFile)
-v, --version show program's version number and exit
Example: cat data.json | gk-encrypt -o ~/.gitkraken/secFilegk-decrypt
txt
usage: gk-decrypt [-h] [-o FILE] [-p] [-v] SECRET_FILE
Decrypt GitKraken secret files.
positional arguments:
SECRET_FILE path to the secret file to decrypt (e.g.,
$HOME/.gitkraken/secFile)
options:
-h, --help show this help message and exit
-o, --output FILE write output to FILE instead of stdout
-p, --pretty pretty print JSON output with indentation
-v, --version show program's version number and exit
Example: gk-decrypt ~/.gitkraken/secFile -o decrypted.json --prettyHow to Run
sh
# Using the raw Bash script
$ ./pkgs/encrypt/script.sh
$ ./pkgs/decrypt/script.shsh
# ...or using new Nix commands
$ nix run '.#encrypt'
$ nix run '.#decrypt'sh
# ...or using classic Nix commands
$ nix-build ./pkgs -A encrypt && ./result/bin/gk-encrypt
$ nix-build ./pkgs -A decrypt && ./result/bin/gk-decryptsh
# ...or from the Nix development shell (nix develop / nix-shell)
$ gk-encrypt
$ gk-decryptFor further details, refer to the actual scripts code:
Encryption / Decryption Methods
The encryption and decryption methods are adapted from GitKraken's original code, reimplemented using Python modules.
The reference implementation below is stripped from irrelevant code, prettified from main.bundle.js and enhanced with comments.
TL;DR
The secrets are JSON data encrypted with the appId as the passphrase.
js
class Ae {
data = {};
/**
* Represents secure data.
* @param {string} re - Path to secret file
* @param {string} ne - Secret file password (appId)
* @param {string} se - Cryptography algorithm
*/
constructor(re, ne, se) {
(this.secPath = re),
(this.password = ne),
(this.algorithm = se),
(this.cryptoHack = le.default), // This is Node's crypto module
this.loadData();
}
/**
* Loads data from a secret file (decryption).
*/
async loadData() {
try {
// Create a decipher with the password key
const re = this.cryptoHack.createDecipher(
this.algorithm,
this.password,
),
// Read the entire secret file as a Buffer
ne = await pe.promises.readFile(this.secPath),
// Decrypt data, verify authentication tag and convert decrypted Buffer to string
se = Buffer.concat([re.update(ne), re.final()]).toString();
// Parse decrypted data as JSON
this.data = JSON.parse(se);
} catch {
this.data = {};
}
}
/**
* Saves data into a secret file (encryption).
*/
async saveData() {
try {
// Create a cipher with the password key
const re = this.cryptoHack.createCipher(
this.algorithm,
this.password,
),
// Encrypt JSON data as string with authentication tag into a Buffer
ne = Buffer.concat([
re.update(Buffer.from(JSON.stringify(this.data))),
re.final(),
]);
// Replace entire content of secret file with encrypted data
await pe.promises.writeFile(this.secPath, ne);
} catch {}
}
}