// src/secure-store/cipher.ts
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
var ENVELOPE_VERSION = 1;
var IV_LENGTH = 12;
var AUTH_TAG_LENGTH = 16;
var ENVELOPE_SALT_LENGTH = 16;
var AES_KEY_LENGTH = 32;
var ENVELOPE_LAYOUT = Object.freeze({
  version: 0,
  salt: 1,
  iv: 1 + ENVELOPE_SALT_LENGTH,
  authTag: 1 + ENVELOPE_SALT_LENGTH + IV_LENGTH,
  ciphertext: 1 + ENVELOPE_SALT_LENGTH + IV_LENGTH + AUTH_TAG_LENGTH
});
var ENVELOPE_HEADER_SIZE = ENVELOPE_LAYOUT.ciphertext;
function assertAesKey(key) {
  if (!(key instanceof Uint8Array)) {
    throw new Error("key must be a Uint8Array");
  }
  if (key.length !== AES_KEY_LENGTH) {
    throw new Error(
      `AES-256-GCM requires a ${AES_KEY_LENGTH}-byte key, got ${key.length}`
    );
  }
}
function seal(key, salt, plaintext, options = {}) {
  assertAesKey(key);
  if (!(salt instanceof Uint8Array) || salt.length !== ENVELOPE_SALT_LENGTH) {
    throw new Error(
      `salt must be ${ENVELOPE_SALT_LENGTH} bytes, got ${salt?.length ?? "non-buffer"}`
    );
  }
  if (!(plaintext instanceof Uint8Array)) {
    throw new Error("plaintext must be a Uint8Array");
  }
  let iv;
  if (options.iv) {
    if (options.iv.length !== IV_LENGTH) {
      throw new Error(`iv must be ${IV_LENGTH} bytes, got ${options.iv.length}`);
    }
    iv = options.iv;
  } else {
    iv = randomBytes(IV_LENGTH);
  }
  const cipher = createCipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv), {
    authTagLength: AUTH_TAG_LENGTH
  });
  const headerAad = buildHeaderAad(salt);
  const finalAad = options.aad ? Buffer.concat([headerAad, Buffer.from(options.aad)]) : headerAad;
  cipher.setAAD(finalAad);
  const ciphertext = Buffer.concat([cipher.update(Buffer.from(plaintext)), cipher.final()]);
  const authTag = cipher.getAuthTag();
  if (authTag.length !== AUTH_TAG_LENGTH) {
    throw new Error(`unexpected auth tag length: ${authTag.length}`);
  }
  const envelope = Buffer.alloc(ENVELOPE_HEADER_SIZE + ciphertext.length);
  envelope.writeUInt8(ENVELOPE_VERSION, ENVELOPE_LAYOUT.version);
  Buffer.from(salt).copy(envelope, ENVELOPE_LAYOUT.salt);
  Buffer.from(iv).copy(envelope, ENVELOPE_LAYOUT.iv);
  authTag.copy(envelope, ENVELOPE_LAYOUT.authTag);
  ciphertext.copy(envelope, ENVELOPE_LAYOUT.ciphertext);
  return envelope;
}
function parseEnvelope(envelope) {
  if (!(envelope instanceof Uint8Array)) {
    throw new Error("envelope must be a Uint8Array");
  }
  if (envelope.length < ENVELOPE_HEADER_SIZE) {
    throw new Error(
      `envelope too short: need \u2265 ${ENVELOPE_HEADER_SIZE} bytes, got ${envelope.length}`
    );
  }
  const buf = Buffer.from(envelope.buffer, envelope.byteOffset, envelope.byteLength);
  const version = buf.readUInt8(ENVELOPE_LAYOUT.version);
  if (version !== ENVELOPE_VERSION) {
    throw new Error(
      `unsupported envelope version: ${version} (this build supports ${ENVELOPE_VERSION})`
    );
  }
  return {
    version,
    salt: buf.subarray(ENVELOPE_LAYOUT.salt, ENVELOPE_LAYOUT.salt + ENVELOPE_SALT_LENGTH),
    iv: buf.subarray(ENVELOPE_LAYOUT.iv, ENVELOPE_LAYOUT.iv + IV_LENGTH),
    authTag: buf.subarray(
      ENVELOPE_LAYOUT.authTag,
      ENVELOPE_LAYOUT.authTag + AUTH_TAG_LENGTH
    ),
    ciphertext: buf.subarray(ENVELOPE_LAYOUT.ciphertext)
  };
}
function open(key, envelope, options = {}) {
  assertAesKey(key);
  const parsed = parseEnvelope(envelope);
  const decipher = createDecipheriv("aes-256-gcm", Buffer.from(key), parsed.iv, {
    authTagLength: AUTH_TAG_LENGTH
  });
  decipher.setAuthTag(parsed.authTag);
  const headerAad = buildHeaderAad(parsed.salt);
  const finalAad = options.aad ? Buffer.concat([headerAad, Buffer.from(options.aad)]) : headerAad;
  decipher.setAAD(finalAad);
  return Buffer.concat([decipher.update(parsed.ciphertext), decipher.final()]);
}
function buildHeaderAad(salt) {
  const out = Buffer.alloc(1 + ENVELOPE_SALT_LENGTH);
  out.writeUInt8(ENVELOPE_VERSION, 0);
  Buffer.from(salt).copy(out, 1);
  return out;
}
function generateSalt() {
  return randomBytes(ENVELOPE_SALT_LENGTH);
}

export {
  ENVELOPE_VERSION,
  IV_LENGTH,
  AUTH_TAG_LENGTH,
  ENVELOPE_SALT_LENGTH,
  AES_KEY_LENGTH,
  ENVELOPE_LAYOUT,
  ENVELOPE_HEADER_SIZE,
  seal,
  parseEnvelope,
  open,
  generateSalt
};
//# sourceMappingURL=chunk-A6XUJE5D.js.map