|
|
|
|
|
const crypto = require('crypto'); |
|
|
|
|
|
|
|
|
const ALGORITHM = 'aes-256-gcm'; |
|
|
const IV_LENGTH = 12; |
|
|
const AUTH_TAG_LENGTH = 16; |
|
|
const SALT_LENGTH = 16; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function deriveKey(secret, salt) { |
|
|
|
|
|
return crypto.pbkdf2Sync(secret, salt, 10000, 32, 'sha256'); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function encrypt(data, secret) { |
|
|
|
|
|
const salt = crypto.randomBytes(SALT_LENGTH); |
|
|
const iv = crypto.randomBytes(IV_LENGTH); |
|
|
|
|
|
|
|
|
const key = deriveKey(secret, salt); |
|
|
|
|
|
|
|
|
const cipher = crypto.createCipheriv(ALGORITHM, key, iv); |
|
|
|
|
|
|
|
|
let encrypted = cipher.update(data); |
|
|
encrypted = Buffer.concat([encrypted, cipher.final()]); |
|
|
|
|
|
|
|
|
const authTag = cipher.getAuthTag(); |
|
|
|
|
|
|
|
|
return { |
|
|
data: encrypted, |
|
|
salt: salt, |
|
|
iv: iv, |
|
|
authTag: authTag |
|
|
}; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function decrypt(encryptedData, salt, iv, authTag, secret) { |
|
|
|
|
|
const key = deriveKey(secret, salt); |
|
|
|
|
|
|
|
|
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv); |
|
|
|
|
|
|
|
|
decipher.setAuthTag(authTag); |
|
|
|
|
|
|
|
|
let decrypted = decipher.update(encryptedData); |
|
|
decrypted = Buffer.concat([decrypted, decipher.final()]); |
|
|
|
|
|
return decrypted; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function verifyIntegrity(data, salt, iv, authTag, secret) { |
|
|
try { |
|
|
|
|
|
decrypt(data, salt, iv, authTag, secret); |
|
|
return true; |
|
|
} catch (error) { |
|
|
return false; |
|
|
} |
|
|
} |
|
|
|
|
|
module.exports = { |
|
|
encrypt, |
|
|
decrypt, |
|
|
verifyIntegrity, |
|
|
ALGORITHM, |
|
|
IV_LENGTH, |
|
|
AUTH_TAG_LENGTH, |
|
|
SALT_LENGTH |
|
|
}; |