• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

KeychainMDIP / kc / 15904334807 / 1

Source File

95.56
/packages/keymaster/src/db/json-enc.ts
1
import crypto from 'crypto';
2
import {WalletBase, StoredWallet} from '../types.js'
3
import { isEncryptedWallet } from './typeGuards.js';
4

5
const algorithm = 'aes-256-gcm';      // Algorithm
1✔
6
const keyLength = 32;                 // 256 bit AES-256
1✔
7
const ivLength = 12;                  // 96-bit IV, standard for AES-GCM
1✔
8
const saltLength = 16;                // 128-bit salt
1✔
9
const iterations = 100000;            // PBKDF2 iterations
1✔
10
const digest = 'sha512';              // PBKDF2 hash function
1✔
11

12
export default class WalletEncrypted implements WalletBase {
13
    private baseWallet: WalletBase;
14
    private readonly passphrase: string;
15

16
    constructor(baseWallet: WalletBase, passphrase: string) {
17
        this.baseWallet = baseWallet;
8✔
18
        this.passphrase = passphrase;
8✔
19
    }
20

21
    async saveWallet(wallet: StoredWallet, overwrite: boolean = false): Promise<boolean> {
22
        if (!this.passphrase) {
6✔
23
            throw new Error('KC_ENCRYPTED_PASSPHRASE not set');
1✔
24
        }
25

26
        const walletJson = JSON.stringify(wallet, null, 4);
5✔
27
        const salt = crypto.randomBytes(saltLength);
5✔
28
        const key = crypto.pbkdf2Sync(this.passphrase, salt, iterations, keyLength, digest);
5✔
29
        const iv = crypto.randomBytes(ivLength);
5✔
30
        const cipher = crypto.createCipheriv(algorithm, key, iv);
5✔
31

32
        let encrypted = cipher.update(walletJson, 'utf8');
5✔
33
        encrypted = Buffer.concat([encrypted, cipher.final()]);
5✔
34

35
        const authTag = cipher.getAuthTag();
5✔
36
        const combined = Buffer.concat([encrypted, authTag]);
5✔
37

38
        const encryptedData = {
5✔
39
            salt: salt.toString('base64'),
40
            iv: iv.toString('base64'),
41
            data: combined.toString('base64')
42
        };
43

44
        return this.baseWallet.saveWallet(encryptedData, overwrite);
5✔
45
    }
46

47
    async loadWallet(): Promise<StoredWallet> {
48
        if (!this.passphrase) {
6✔
49
            throw new Error('KC_ENCRYPTED_PASSPHRASE not set');
1✔
50
        }
51

52
        const encryptedData = await this.baseWallet.loadWallet();
5✔
53
        if (!encryptedData) {
5✔
54
            return null;
2✔
55
        }
56

57
        if (!isEncryptedWallet(encryptedData)) {
3!
58
            // We'll assume here that the passphrase has just been set and the wallet is not yet encrypted
59
            return encryptedData;
×
60
        }
61

62
        const salt = Buffer.from(encryptedData.salt, 'base64');
3✔
63
        const iv = Buffer.from(encryptedData.iv, 'base64');
3✔
64
        const combined = Buffer.from(encryptedData.data, 'base64');
3✔
65

66
        const authTag = combined.subarray(combined.length - 16);
3✔
67
        const encryptedJSON = combined.subarray(0, combined.length - 16);
3✔
68
        const key = crypto.pbkdf2Sync(this.passphrase, salt, iterations, keyLength, digest);
3✔
69
        const decipher = crypto.createDecipheriv(algorithm, key, iv);
3✔
70
        decipher.setAuthTag(authTag);
3✔
71

72
        let decrypted;
73
        try {
3✔
74
            decrypted = decipher.update(encryptedJSON, undefined, 'utf8');
3✔
75
            decrypted += decipher.final('utf8');
3✔
76
        } catch (err) {
77
            throw new Error('Incorrect passphrase.');
1✔
78
        }
79

80
        return JSON.parse(decrypted);
2✔
81
    }
82
}
  • Back to Build 15904334807
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc