deadmanswitch-encryption
Version:
Cross-platform encryption library for React Native and React web applications with password-based encryption
76 lines (75 loc) • 3.9 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decrypt = exports.encrypt = void 0;
const react_native_quick_crypto_1 = __importDefault(require("react-native-quick-crypto"));
const utils_1 = require("./utils");
class ReactNativeCryptoService {
constructor() {
this.defaultIterations = 100000;
this.defaultKeyLength = 256;
}
async encrypt(data, options) {
const { password, iterations = this.defaultIterations, keyLength = this.defaultKeyLength } = options;
const salt = react_native_quick_crypto_1.default.randomBytes(16);
const iv = react_native_quick_crypto_1.default.randomBytes(12);
const passwordKey = await this.deriveKey(password, salt, iterations, keyLength);
const encoder = new TextEncoder();
const dataBuffer = encoder.encode(data);
const cipher = react_native_quick_crypto_1.default.createCipheriv('aes-256-gcm', passwordKey, iv);
cipher.setAAD(Buffer.alloc(0));
let encrypted = cipher.update(dataBuffer);
cipher.final();
const authTag = cipher.getAuthTag();
const encryptedWithTag = new Uint8Array(encrypted.length + authTag.length);
encryptedWithTag.set(encrypted);
encryptedWithTag.set(authTag, encrypted.length);
return {
encryptedData: (0, utils_1.arrayBufferToBase64)(encryptedWithTag.buffer),
salt: (0, utils_1.arrayBufferToBase64)(salt.buffer),
iv: (0, utils_1.arrayBufferToBase64)(iv.buffer)
};
}
async decrypt(options) {
const { password, encryptedData, salt, iv, iterations = this.defaultIterations, keyLength = this.defaultKeyLength } = options;
const saltBuffer = new Uint8Array((0, utils_1.base64ToArrayBuffer)(salt));
const ivBuffer = new Uint8Array((0, utils_1.base64ToArrayBuffer)(iv));
const encryptedBuffer = new Uint8Array((0, utils_1.base64ToArrayBuffer)(encryptedData));
const authTagLength = 16;
const ciphertext = encryptedBuffer.slice(0, -authTagLength);
const authTag = encryptedBuffer.slice(-authTagLength);
const passwordKey = await this.deriveKey(password, saltBuffer, iterations, keyLength);
const decipher = react_native_quick_crypto_1.default.createDecipheriv('aes-256-gcm', passwordKey, ivBuffer);
decipher.setAAD(Buffer.alloc(0));
decipher.setAuthTag(authTag);
let decrypted = decipher.update(ciphertext);
decipher.final();
const decoder = new TextDecoder();
return decoder.decode(decrypted);
}
async deriveKey(password, salt, iterations, keyLength) {
return react_native_quick_crypto_1.default.pbkdf2Sync(password, Buffer.from(salt), iterations, keyLength / 8, 'sha256');
}
}
const cryptoService = new ReactNativeCryptoService();
const encrypt = (data, options) => cryptoService.encrypt(data, options);
exports.encrypt = encrypt;
const decrypt = (options) => cryptoService.decrypt(options);
exports.decrypt = decrypt;
__exportStar(require("./types"), exports);
;