@byok-sdk/core 0.30.0 → 0.30.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,6 +15,8 @@ export { MEMBER_CHAIN_OPS, deriveMemberId, memberChainEntryHash, signMemberChain
15
15
  export type { MemberChainEntryV1, MemberChainEntryVerifyResult, MemberChainOp, UnsignedMemberChainEntryV1, } from './member-chain';
16
16
  export { MEMBER_KEY_BUNDLE_VERSION, createMemberKeyBundle, parseMemberKeyBundle, verifyMemberKem } from './member-bundle';
17
17
  export type { CreateMemberKeyBundleInput, MemberKeyBundleV1 } from './member-bundle';
18
+ export { beginMemberKemRotation, finishMemberKemRotation, generateMemberKeyRecord, openMemberKeyRecord, } from './member-key-record';
19
+ export type { MemberKemKey, MemberKeyBinding, MemberKeyStore, MemberKeys } from './member-key-record';
18
20
  export { MEMBER_FINGERPRINT_DOMAIN, memberApprovalCode, memberFingerprint } from './member-fingerprint';
19
21
  export type { MemberFingerprintInput } from './member-fingerprint';
20
22
  export { CLIENT_PAIRING_MAC_DOMAIN, DEVICE_PAIRING_MAC_DOMAIN, PAIRING_VERIFICATION_SECRET_BYTES, computeClientPairingMac, computeDevicePairingMac, decodePairingVerificationSecret, encodePairingVerificationSecret, formatPairingInput, generatePairingVerificationSecret, parsePairingInput, verifyClientPairingMac, verifyDevicePairingMac, } from './pairing-verification';
@@ -1165,6 +1165,115 @@ async function parseMemberKeyBundle(value) {
1165
1165
  if (!await verifyMemberKem(bundle, bundle)) return void 0;
1166
1166
  return bundle;
1167
1167
  }
1168
+ var MEMBER_KEY_RECORD_VERSION = 1;
1169
+ var PrivateJwkSchema = z.strictObject({
1170
+ kty: z.literal("EC"),
1171
+ crv: z.literal("P-256"),
1172
+ x: base64UrlBytes(32),
1173
+ y: base64UrlBytes(32),
1174
+ d: base64UrlBytes(32)
1175
+ });
1176
+ var KemEpochSchema2 = z.number().int().positive().max(Number.MAX_SAFE_INTEGER);
1177
+ var MemberKeyRecordV1Schema = z.strictObject({
1178
+ v: z.literal(MEMBER_KEY_RECORD_VERSION),
1179
+ tenantId: z.string().min(1),
1180
+ deviceId: z.string().min(1).optional(),
1181
+ signingJwk: PrivateJwkSchema,
1182
+ kemEpoch: KemEpochSchema2,
1183
+ kemJwk: PrivateJwkSchema,
1184
+ nextKem: z.strictObject({ epoch: KemEpochSchema2, jwk: PrivateJwkSchema }).optional()
1185
+ }).refine((record) => record.nextKem === void 0 || record.nextKem.epoch === record.kemEpoch + 1);
1186
+ var BindingSchema = z.object({ tenantId: z.string().min(1), deviceId: z.string().min(1).optional() });
1187
+ function keySubtle() {
1188
+ return webCryptoSubtle();
1189
+ }
1190
+ var ECDSA_P2562 = { name: "ECDSA", namedCurve: "P-256" };
1191
+ var ECDSA_SHA2562 = { name: "ECDSA", hash: "SHA-256" };
1192
+ var ECDH_P256 = { name: "ECDH", namedCurve: "P-256" };
1193
+ async function generatePrivateJwk(algorithm, usages) {
1194
+ const pair = await keySubtle().generateKey(algorithm, true, usages);
1195
+ const { kty, crv, x, y, d } = await keySubtle().exportKey("jwk", pair.privateKey);
1196
+ return PrivateJwkSchema.parse({ kty, crv, x, y, d });
1197
+ }
1198
+ async function generateMemberKeyRecord(binding) {
1199
+ const parsed = safeParseTotal(BindingSchema, binding);
1200
+ if (!parsed.success) throw invalidInput("Member key binding is invalid");
1201
+ const { tenantId, deviceId } = parsed.data;
1202
+ return canonicalizeJson({
1203
+ v: MEMBER_KEY_RECORD_VERSION,
1204
+ tenantId,
1205
+ ...deviceId === void 0 ? {} : { deviceId },
1206
+ signingJwk: await generatePrivateJwk(ECDSA_P2562, ["sign", "verify"]),
1207
+ kemEpoch: 1,
1208
+ kemJwk: await generatePrivateJwk(ECDH_P256, ["deriveBits"])
1209
+ });
1210
+ }
1211
+ function publicJwkOf(jwk) {
1212
+ return P256PublicJwkSchema.parse({ kty: jwk.kty, crv: jwk.crv, x: jwk.x, y: jwk.y });
1213
+ }
1214
+ function bytesEqual(left, right) {
1215
+ const a = new Uint8Array(left);
1216
+ const b = new Uint8Array(right);
1217
+ return a.length === b.length && a.every((byte, index) => byte === b[index]);
1218
+ }
1219
+ async function importSigningKey(jwk) {
1220
+ const subtle = keySubtle();
1221
+ const publicJwk = publicJwkOf(jwk);
1222
+ const privateKey = await subtle.importKey("jwk", { ...jwk, ext: false }, ECDSA_P2562, false, ["sign"]);
1223
+ const publicKey = await subtle.importKey("jwk", publicJwk, ECDSA_P2562, true, ["verify"]);
1224
+ const probe = randomBytes(32);
1225
+ if (!await subtle.verify(ECDSA_SHA2562, publicKey, await subtle.sign(ECDSA_SHA2562, privateKey, probe), probe)) {
1226
+ throw new TypeError("signing scalar does not match its public point");
1227
+ }
1228
+ return { publicJwk, privateKey };
1229
+ }
1230
+ async function importKemKey(jwk) {
1231
+ const subtle = keySubtle();
1232
+ const publicJwk = publicJwkOf(jwk);
1233
+ const privateKey = await subtle.importKey("jwk", { ...jwk, ext: false }, ECDH_P256, false, ["deriveBits"]);
1234
+ const publicKey = await subtle.importKey("jwk", publicJwk, ECDH_P256, true, []);
1235
+ const probe = await subtle.generateKey(ECDH_P256, false, ["deriveBits"]);
1236
+ const viaMember = await subtle.deriveBits({ name: "ECDH", public: probe.publicKey }, privateKey, 256);
1237
+ const viaProbe = await subtle.deriveBits({ name: "ECDH", public: publicKey }, probe.privateKey, 256);
1238
+ if (!bytesEqual(viaMember, viaProbe)) throw new TypeError("KEM scalar does not match its public point");
1239
+ return { publicJwk, privateKey };
1240
+ }
1241
+ async function openMemberKeyRecord(text) {
1242
+ const record = parseRecord(text);
1243
+ if (record === void 0) return void 0;
1244
+ try {
1245
+ const signing = await importSigningKey(record.signingJwk);
1246
+ const kem = { epoch: record.kemEpoch, ...await importKemKey(record.kemJwk) };
1247
+ const binding = record.deviceId === void 0 ? { tenantId: record.tenantId } : { tenantId: record.tenantId, deviceId: record.deviceId };
1248
+ if (record.nextKem === void 0) return { binding, signing, kem };
1249
+ return { binding, signing, kem, nextKem: { epoch: record.nextKem.epoch, ...await importKemKey(record.nextKem.jwk) } };
1250
+ } catch {
1251
+ return void 0;
1252
+ }
1253
+ }
1254
+ async function beginMemberKemRotation(text) {
1255
+ const record = parseRecord(text);
1256
+ if (record === void 0) throw invalidInput("Member key record is invalid");
1257
+ if (record.nextKem !== void 0) return text;
1258
+ return canonicalizeJson({ ...record, nextKem: { epoch: record.kemEpoch + 1, jwk: await generatePrivateJwk(ECDH_P256, ["deriveBits"]) } });
1259
+ }
1260
+ function finishMemberKemRotation(text, epoch) {
1261
+ const record = parseRecord(text);
1262
+ if (record === void 0) throw invalidInput("Member key record is invalid");
1263
+ if (record.nextKem === void 0) return record.kemEpoch === epoch ? text : void 0;
1264
+ if (record.nextKem.epoch !== epoch) return void 0;
1265
+ const { nextKem, ...rest } = record;
1266
+ return canonicalizeJson({ ...rest, kemEpoch: nextKem.epoch, kemJwk: nextKem.jwk });
1267
+ }
1268
+ function parseRecord(text) {
1269
+ if (typeof text !== "string") return void 0;
1270
+ try {
1271
+ const parsed = safeParseTotal(MemberKeyRecordV1Schema, JSON.parse(text));
1272
+ return parsed.success && canonicalizeJson(parsed.data) === text ? parsed.data : void 0;
1273
+ } catch {
1274
+ return void 0;
1275
+ }
1276
+ }
1168
1277
  var MEMBER_FINGERPRINT_DOMAIN = "byok-member-fingerprint-v1\n";
1169
1278
  var FINGERPRINT_GROUPS = 5;
1170
1279
  var GROUP_BYTES = 5;
@@ -1481,6 +1590,6 @@ async function verifyMemberChainFromAnchor(input) {
1481
1590
  return { ok: true, state: outcome.state, anchorSeq: anchor.seq };
1482
1591
  }
1483
1592
 
1484
- export { CLIENT_PAIRING_MAC_DOMAIN, DEVICE_PAIRING_MAC_DOMAIN, MEMBER_CHAIN_OPS, MEMBER_FINGERPRINT_DOMAIN, MEMBER_KEY_BUNDLE_VERSION, PAIRING_VERIFICATION_SECRET_BYTES, SEALED_CATEGORIES, SEALED_CONTENT_SUITE, SEALED_CONTENT_VERSION, SEALED_DIRECTIONS, SealedContentHeaderV1Schema, applyMemberChainEntries, computeClientPairingMac, computeDevicePairingMac, createMemberKeyBundle, decodePairingVerificationSecret, deriveMemberId, deriveScopeKeyId, emptyMemberChainState, encodePairingVerificationSecret, formatPairingInput, generatePairingVerificationSecret, generateScopeKey, memberApprovalCode, memberChainEntryHash, memberChainScopeRecipients, memberFingerprint, openScopeKeyPackage, openSealedContent, parseMemberKeyBundle, parsePairingInput, sealContent, sealScopeKeyPackage, signMemberChainEntry, verifyClientPairingMac, verifyDevicePairingMac, verifyMemberChainEntry, verifyMemberChainFromAnchor, verifyMemberKem };
1593
+ export { CLIENT_PAIRING_MAC_DOMAIN, DEVICE_PAIRING_MAC_DOMAIN, MEMBER_CHAIN_OPS, MEMBER_FINGERPRINT_DOMAIN, MEMBER_KEY_BUNDLE_VERSION, PAIRING_VERIFICATION_SECRET_BYTES, SEALED_CATEGORIES, SEALED_CONTENT_SUITE, SEALED_CONTENT_VERSION, SEALED_DIRECTIONS, SealedContentHeaderV1Schema, applyMemberChainEntries, beginMemberKemRotation, computeClientPairingMac, computeDevicePairingMac, createMemberKeyBundle, decodePairingVerificationSecret, deriveMemberId, deriveScopeKeyId, emptyMemberChainState, encodePairingVerificationSecret, finishMemberKemRotation, formatPairingInput, generateMemberKeyRecord, generatePairingVerificationSecret, generateScopeKey, memberApprovalCode, memberChainEntryHash, memberChainScopeRecipients, memberFingerprint, openMemberKeyRecord, openScopeKeyPackage, openSealedContent, parseMemberKeyBundle, parsePairingInput, sealContent, sealScopeKeyPackage, signMemberChainEntry, verifyClientPairingMac, verifyDevicePairingMac, verifyMemberChainEntry, verifyMemberChainFromAnchor, verifyMemberKem };
1485
1594
  //# sourceMappingURL=index.js.map
1486
1595
  //# sourceMappingURL=index.js.map