Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 76 additions & 11 deletions src/platforms/win32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,17 @@ import { run, sudo } from '../utils';
import UI from '../user-interface';

const debug = createDebug('devcert:platforms:windows');
const ALG_NAME = 'aes-256-gcm';
const ALG_SIZES = {
NONCE: 16,
TAG: 16,
KEY: 16,
};
const PBKDF2 = {
NAME: 'sha256',
SALT_SIZE: 16,
ITER: 32767,
};

let encryptionKey: string;

Expand Down Expand Up @@ -44,7 +55,7 @@ export default class WindowsPlatform implements Platform {
debug('Error opening Firefox, most likely Firefox is not installed');
}
}

removeFromTrustStores(certificatePath: string) {
debug('removing devcert root from Windows OS trust store');
try {
Expand All @@ -61,7 +72,7 @@ export default class WindowsPlatform implements Platform {
await sudo(`echo 127.0.0.1 ${ domain } >> ${ this.HOST_FILE_PATH }`);
}
}

deleteProtectedFiles(filepath: string) {
assertNotTouchingFiles(filepath, 'delete');
rimraf(filepath);
Expand Down Expand Up @@ -94,14 +105,68 @@ export default class WindowsPlatform implements Platform {
write(filepath, encryptedContents);
}

private encrypt(text: string, key: string) {
let cipher = crypto.createCipher('aes256', new Buffer(key));
return cipher.update(text, 'utf8', 'hex') + cipher.final('hex');
}
private getPbkdf2 = (password: string, salt: Buffer): Buffer => {
return crypto.pbkdf2Sync(
Buffer.from(password, 'utf8'),
salt,
PBKDF2.ITER,
ALG_SIZES.KEY,
PBKDF2.NAME
);
};

private decrypt(encrypted: string, key: string) {
let decipher = crypto.createDecipher('aes256', new Buffer(key));
return decipher.update(encrypted, 'hex', 'utf8') + decipher.final('utf8');
}
private getCryptoKey = (key: Buffer) =>
crypto.createHash('sha256').update(key).digest();

private encrypt = (plainText: string, password: string): string => {
// Generate a 128-bit salt using a PBKDF2.
const salt = crypto.randomBytes(PBKDF2.SALT_SIZE);

// Derive a key using PBKDF2.
const key = this.getCryptoKey(this.getPbkdf2(password, salt));

// Generate a 128-bit nonce using a CSPRNG.
const nonce = crypto.randomBytes(ALG_SIZES.NONCE);

// Create the cipher instance.
const cipher = crypto.createCipheriv(ALG_NAME, key, nonce);

// Encrypt and prepend salt.
return Buffer.concat([
salt,
nonce,
cipher.update(plainText, 'utf8'),
cipher.final(),
cipher.getAuthTag(),
]).toString('base64');
};

private decrypt = (
base64EncryptedContent: string,
password: string
): string => {
// Decode the base64.
const encCipher = Buffer.from(base64EncryptedContent, 'base64');

// Create buffers of salt, nonce, encryption cipher, and auth tag
let position = 0;
const salt = encCipher.slice(position, (position += PBKDF2.SALT_SIZE));
const nonce = encCipher.slice(position, (position += ALG_SIZES.NONCE));
const encContent = encCipher.slice(
position,
encCipher.length - ALG_SIZES.TAG
);
const tag = encCipher.slice(encCipher.length - ALG_SIZES.TAG);

// Derive the key using PBKDF2.
const key = this.getCryptoKey(this.getPbkdf2(password, salt));

const decipher = crypto.createDecipheriv(ALG_NAME, key, nonce);
decipher.setAuthTag(tag);

}
return Buffer.concat([
decipher.update(encContent),
decipher.final(),
]).toString('utf8');
};
}