keychain.js 1.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. const { Crypto } = require('@peculiar/webcrypto');
  2. const crypto = new Crypto();
  3. const encoder = new TextEncoder();
  4. const decoder = new TextDecoder();
  5. module.exports = class Keychain {
  6. constructor(secretKeyB64) {
  7. if (secretKeyB64) {
  8. this.rawSecret = new Uint8Array(Buffer.from(secretKeyB64, 'base64'));
  9. } else {
  10. throw new Error('key is required');
  11. }
  12. this.secretKeyPromise = crypto.subtle.importKey(
  13. 'raw',
  14. this.rawSecret,
  15. 'HKDF',
  16. false,
  17. ['deriveKey']
  18. );
  19. this.metaKeyPromise = this.secretKeyPromise.then(function(secretKey) {
  20. return crypto.subtle.deriveKey(
  21. {
  22. name: 'HKDF',
  23. salt: new Uint8Array(),
  24. info: encoder.encode('metadata'),
  25. hash: 'SHA-256'
  26. },
  27. secretKey,
  28. {
  29. name: 'AES-GCM',
  30. length: 128
  31. },
  32. false,
  33. ['decrypt']
  34. );
  35. });
  36. }
  37. async decryptMetadata(ciphertext) {
  38. const metaKey = await this.metaKeyPromise;
  39. const plaintext = await crypto.subtle.decrypt(
  40. {
  41. name: 'AES-GCM',
  42. iv: new Uint8Array(12),
  43. tagLength: 128
  44. },
  45. metaKey,
  46. ciphertext
  47. );
  48. return JSON.parse(decoder.decode(plaintext));
  49. }
  50. };