relv-space3 / src /crypto /password.ts
relv-dev's picture
Deploy latest verified Turnitin worker
9e212e3 verified
Raw
History Blame Contribute Delete
2.1 kB
import * as crypto from 'crypto';
import { config } from '../config';
const ALGORITHM = 'aes-256-gcm';
const IV_LENGTH = 16;
const AUTH_TAG_LENGTH = 16;
/**
* Derive a 32-byte key from the encryption key string.
* Uses SHA-256 so any length passphrase works.
*/
function deriveKey(): Buffer {
return crypto.createHash('sha256').update(config.credentialEncryptionKey).digest();
}
/**
* Encrypt a plaintext password.
* Returns base64 string: iv(16) + authTag(16) + ciphertext
*/
export function encryptPassword(plaintext: string): string {
const key = deriveKey();
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
const encrypted = Buffer.concat([
cipher.update(plaintext, 'utf8'),
cipher.final(),
]);
const authTag = cipher.getAuthTag();
// Format: iv + authTag + ciphertext
const combined = Buffer.concat([iv, authTag, encrypted]);
return combined.toString('base64');
}
/**
* Decrypt an encrypted password string.
* Input is base64 string: iv(16) + authTag(16) + ciphertext
*/
export function decryptPassword(encrypted: string): string {
const key = deriveKey();
const combined = Buffer.from(encrypted, 'base64');
const iv = combined.subarray(0, IV_LENGTH);
const authTag = combined.subarray(IV_LENGTH, IV_LENGTH + AUTH_TAG_LENGTH);
const ciphertext = combined.subarray(IV_LENGTH + AUTH_TAG_LENGTH);
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
decipher.setAuthTag(authTag);
const decrypted = Buffer.concat([
decipher.update(ciphertext),
decipher.final(),
]);
return decrypted.toString('utf8');
}
/**
* Get the Turnitin password for an account.
* If encryption key is set, tries to decrypt. Otherwise uses shared password.
*/
export function getAccountPassword(encryptedPassword?: string | null): string {
if (encryptedPassword && config.credentialEncryptionKey) {
try {
return decryptPassword(encryptedPassword);
} catch {
// Fallback to shared password if decryption fails
}
}
return config.turnitinSharedPassword;
}