@msdis/shield 0.2.0

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.
Files changed (92) hide show
  1. package/LICENSE +140 -0
  2. package/README.md +106 -0
  3. package/dist/aead/index.d.ts +37 -0
  4. package/dist/aead/index.js +7 -0
  5. package/dist/aead/index.js.map +1 -0
  6. package/dist/asymmetric/index.d.ts +32 -0
  7. package/dist/asymmetric/index.js +6 -0
  8. package/dist/asymmetric/index.js.map +1 -0
  9. package/dist/chunk-3DQPQCAR.js +114 -0
  10. package/dist/chunk-3DQPQCAR.js.map +1 -0
  11. package/dist/chunk-3HCT6A2P.js +55 -0
  12. package/dist/chunk-3HCT6A2P.js.map +1 -0
  13. package/dist/chunk-AB2WZ7Y2.js +57 -0
  14. package/dist/chunk-AB2WZ7Y2.js.map +1 -0
  15. package/dist/chunk-BUFRR5PB.js +9 -0
  16. package/dist/chunk-BUFRR5PB.js.map +1 -0
  17. package/dist/chunk-CYIGDF63.js +30 -0
  18. package/dist/chunk-CYIGDF63.js.map +1 -0
  19. package/dist/chunk-EOXWR7DS.js +153 -0
  20. package/dist/chunk-EOXWR7DS.js.map +1 -0
  21. package/dist/chunk-FUDDBD2G.js +43 -0
  22. package/dist/chunk-FUDDBD2G.js.map +1 -0
  23. package/dist/chunk-JSKIWIEC.js +56 -0
  24. package/dist/chunk-JSKIWIEC.js.map +1 -0
  25. package/dist/chunk-JVFP2GAO.js +66 -0
  26. package/dist/chunk-JVFP2GAO.js.map +1 -0
  27. package/dist/chunk-KNCZMIZA.js +55 -0
  28. package/dist/chunk-KNCZMIZA.js.map +1 -0
  29. package/dist/chunk-MJO7IJZC.js +44 -0
  30. package/dist/chunk-MJO7IJZC.js.map +1 -0
  31. package/dist/chunk-MPWYZXW7.js +66 -0
  32. package/dist/chunk-MPWYZXW7.js.map +1 -0
  33. package/dist/chunk-OA5ARYJM.js +73 -0
  34. package/dist/chunk-OA5ARYJM.js.map +1 -0
  35. package/dist/chunk-OPHN2B3N.js +147 -0
  36. package/dist/chunk-OPHN2B3N.js.map +1 -0
  37. package/dist/chunk-RTAJJZKO.js +116 -0
  38. package/dist/chunk-RTAJJZKO.js.map +1 -0
  39. package/dist/chunk-SCHZI6YY.js +35 -0
  40. package/dist/chunk-SCHZI6YY.js.map +1 -0
  41. package/dist/chunk-T3IV7SHD.js +388 -0
  42. package/dist/chunk-T3IV7SHD.js.map +1 -0
  43. package/dist/chunk-U65A4HIY.js +133 -0
  44. package/dist/chunk-U65A4HIY.js.map +1 -0
  45. package/dist/core/index.d.ts +20 -0
  46. package/dist/core/index.js +6 -0
  47. package/dist/core/index.js.map +1 -0
  48. package/dist/encoding-B-cb7Duu.d.ts +37 -0
  49. package/dist/errors-C79jA9vX.d.ts +65 -0
  50. package/dist/file-encryption/index.d.ts +135 -0
  51. package/dist/file-encryption/index.js +11 -0
  52. package/dist/file-encryption/index.js.map +1 -0
  53. package/dist/format-versioning/index.d.ts +37 -0
  54. package/dist/format-versioning/index.js +4 -0
  55. package/dist/format-versioning/index.js.map +1 -0
  56. package/dist/index.d.ts +27 -0
  57. package/dist/index.js +24 -0
  58. package/dist/index.js.map +1 -0
  59. package/dist/integrity/index.d.ts +46 -0
  60. package/dist/integrity/index.js +6 -0
  61. package/dist/integrity/index.js.map +1 -0
  62. package/dist/kdf/index.d.ts +104 -0
  63. package/dist/kdf/index.js +7 -0
  64. package/dist/kdf/index.js.map +1 -0
  65. package/dist/key-management/index.d.ts +69 -0
  66. package/dist/key-management/index.js +10 -0
  67. package/dist/key-management/index.js.map +1 -0
  68. package/dist/migrations/index.d.ts +41 -0
  69. package/dist/migrations/index.js +4 -0
  70. package/dist/migrations/index.js.map +1 -0
  71. package/dist/post-quantum/index.d.ts +153 -0
  72. package/dist/post-quantum/index.js +3 -0
  73. package/dist/post-quantum/index.js.map +1 -0
  74. package/dist/random/index.d.ts +28 -0
  75. package/dist/random/index.js +5 -0
  76. package/dist/random/index.js.map +1 -0
  77. package/dist/secure-memory/index.d.ts +40 -0
  78. package/dist/secure-memory/index.js +5 -0
  79. package/dist/secure-memory/index.js.map +1 -0
  80. package/dist/signing/index.d.ts +41 -0
  81. package/dist/signing/index.js +5 -0
  82. package/dist/signing/index.js.map +1 -0
  83. package/dist/totp/index.d.ts +69 -0
  84. package/dist/totp/index.js +4 -0
  85. package/dist/totp/index.js.map +1 -0
  86. package/dist/vault-crypto/index.d.ts +225 -0
  87. package/dist/vault-crypto/index.js +465 -0
  88. package/dist/vault-crypto/index.js.map +1 -0
  89. package/dist/vault-encryption/index.d.ts +40 -0
  90. package/dist/vault-encryption/index.js +9 -0
  91. package/dist/vault-encryption/index.js.map +1 -0
  92. package/package.json +137 -0
@@ -0,0 +1,41 @@
1
+ /**
2
+ * dis-migrations — explicit, ordered transformation of encrypted payloads.
3
+ *
4
+ * Migrations are registered against a (subject, fromVersion) key and run in a
5
+ * deterministic order. This gives applications a single, testable place to
6
+ * evolve formats (e.g. re-wrap legacy no-AAD vault items, bump KDF parameters,
7
+ * re-encrypt under a new cipher) without scattering ad-hoc upgrade code.
8
+ *
9
+ * DIS provides the framework and the crypto; the application decides which
10
+ * migrations to register and how persistence happens.
11
+ */
12
+ /** Context passed to a migration step. `key` material is caller-supplied. */
13
+ interface MigrationContext {
14
+ readonly key: CryptoKey;
15
+ /** Stable identifier the payload is bound to (e.g. entry id). */
16
+ readonly bindingId?: string;
17
+ }
18
+ /** A single migration: transforms a payload from `fromVersion` to `toVersion`. */
19
+ interface Migration {
20
+ readonly subject: string;
21
+ readonly fromVersion: number | 'legacy';
22
+ readonly toVersion: number;
23
+ /** Returns the migrated payload string. Must be idempotent on its output. */
24
+ migrate(payload: string, context: MigrationContext): Promise<string>;
25
+ }
26
+ /** Detects the current version of a payload for a subject. */
27
+ type VersionDetector = (payload: string) => number | 'legacy';
28
+ /** An ordered registry of migrations for one or more subjects. */
29
+ declare class MigrationRegistry {
30
+ private readonly migrations;
31
+ private keyOf;
32
+ /** Registers a migration. Throws if one already exists for the same step. */
33
+ register(migration: Migration): this;
34
+ /**
35
+ * Applies all applicable migrations in sequence until no further migration
36
+ * exists for the payload's detected version. Guards against cycles.
37
+ */
38
+ migrateToLatest(subject: string, payload: string, detect: VersionDetector, context: MigrationContext): Promise<string>;
39
+ }
40
+
41
+ export { type Migration, type MigrationContext, MigrationRegistry, type VersionDetector };
@@ -0,0 +1,4 @@
1
+ export { MigrationRegistry } from '../chunk-FUDDBD2G.js';
2
+ import '../chunk-MJO7IJZC.js';
3
+ //# sourceMappingURL=index.js.map
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * DIS — Defensive Integration Shield · post-quantum hybrid key wrapping.
3
+ * Powered by DIS — Defensive Integration Shield.
4
+ *
5
+ * Hybrid key wrapping combining:
6
+ * - ML-KEM-768 (FIPS 203) for post-quantum key encapsulation
7
+ * - RSA-4096-OAEP for classical encryption
8
+ *
9
+ * In the product threat model this protects sharing and emergency-access
10
+ * keys against "harvest now, decrypt later" attacks. It is NOT the encryption
11
+ * layer for vault item payloads, which remain AES-256-GCM encrypted with
12
+ * user-derived symmetric keys (see `@dis/shield/vault-encryption`).
13
+ *
14
+ * Wire format is preserved byte-for-byte from the legacy Singra implementation:
15
+ * version(1) || pq_ct(1088) || rsa_ct(512) || iv(12) || aes_ct(variable)
16
+ * with version bytes 0x01 (RSA-only), 0x02 (legacy hybrid), 0x03 (HKDF-v1),
17
+ * 0x04 (HKDF-v2, current). Changing any constant below breaks decryption of
18
+ * already-stored sharing/emergency keys — treat as a hard compatibility gate.
19
+ *
20
+ * @see https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
21
+ */
22
+ /**
23
+ * Product-wide security standard version. Centralized so all hybrid/PQ
24
+ * sharing-key provisioning and runtime enforcement paths stay in sync.
25
+ */
26
+ declare const SECURITY_STANDARD_VERSION = 1;
27
+ /** Current hybrid ciphertext version (v2 HKDF construction) */
28
+ declare const HYBRID_VERSION = 4;
29
+ interface SharedKeyWrapAadInput {
30
+ collectionId: string;
31
+ senderUserId: string;
32
+ recipientUserId: string;
33
+ keyVersion: string | number;
34
+ }
35
+ declare function buildSharedKeyWrapAad(input: SharedKeyWrapAadInput): string;
36
+ /**
37
+ * Generates a new ML-KEM-768 key pair.
38
+ *
39
+ * @returns Object with base64-encoded public and secret keys
40
+ */
41
+ declare function generatePQKeyPair(): PQKeyPair;
42
+ /**
43
+ * Generates a hybrid key pair combining ML-KEM-768 and RSA-4096.
44
+ *
45
+ * @returns Object with both PQ and RSA keys
46
+ */
47
+ declare function generateHybridKeyPair(): Promise<HybridKeyPair>;
48
+ /**
49
+ * Encrypts key material using hybrid ML-KEM-768 + RSA-4096-OAEP encryption.
50
+ *
51
+ * The supplied key material is encrypted with a randomly generated AES-256 key.
52
+ * This AES key is then encapsulated/encrypted with both:
53
+ * 1. ML-KEM-768 (post-quantum KEM)
54
+ * 2. RSA-4096-OAEP (classically secure)
55
+ *
56
+ * Format: version(1) || pq_ciphertext(1088) || rsa_ciphertext(512) || iv(12) || aes_ciphertext(variable)
57
+ *
58
+ * @param plaintext - Serialized key material to wrap
59
+ * @param pqPublicKey - Base64-encoded ML-KEM-768 public key
60
+ * @param rsaPublicKey - JWK string of RSA-4096 public key
61
+ * @param aad - Optional additional authenticated data for AES-GCM context binding
62
+ * @returns Base64-encoded hybrid ciphertext
63
+ */
64
+ declare function hybridEncrypt(plaintext: string, pqPublicKey: string, rsaPublicKey: string, aad?: string): Promise<string>;
65
+ /**
66
+ * Decrypts hybrid ML-KEM-768 + RSA-4096-OAEP wrapped key material.
67
+ *
68
+ * @param ciphertextBase64 - Base64-encoded hybrid ciphertext
69
+ * @param pqSecretKey - Base64-encoded ML-KEM-768 secret key
70
+ * @param rsaPrivateKey - JWK string of RSA-4096 private key
71
+ * @param aad - Optional additional authenticated data (must match encrypt-time AAD)
72
+ * @returns Decrypted plaintext
73
+ * @throws Error if decryption fails or version is unsupported
74
+ */
75
+ declare function hybridDecrypt(ciphertextBase64: string, pqSecretKey: string, rsaPrivateKey: string, aad?: string): Promise<string>;
76
+ /**
77
+ * Wraps a shared AES key using hybrid encryption.
78
+ * Used for shared collections where each member gets a wrapped copy.
79
+ *
80
+ * @param sharedKeyJwk - JWK string of the shared AES-256 key
81
+ * @param pqPublicKey - Base64-encoded ML-KEM-768 public key
82
+ * @param rsaPublicKey - JWK string of RSA-4096 public key
83
+ * @param aad - Optional additional authenticated data (e.g. collection ID)
84
+ * @returns Base64-encoded wrapped key
85
+ */
86
+ declare function hybridWrapKey(sharedKeyJwk: string, pqPublicKey: string, rsaPublicKey: string, aad: string): Promise<string>;
87
+ /**
88
+ * Unwraps a shared AES key using hybrid decryption.
89
+ *
90
+ * @param wrappedKey - Base64-encoded wrapped key
91
+ * @param pqSecretKey - Base64-encoded ML-KEM-768 secret key
92
+ * @param rsaPrivateKey - JWK string of RSA-4096 private key
93
+ * @param aad - Optional additional authenticated data (must match wrap-time AAD)
94
+ * @returns JWK string of the shared AES-256 key
95
+ */
96
+ declare function hybridUnwrapKey(wrappedKey: string, pqSecretKey: string, rsaPrivateKey: string, aad: string): Promise<string>;
97
+ /**
98
+ * Checks if wrapped key material uses any hybrid (post-quantum) encryption version.
99
+ * Recognizes legacy hybrid (0x02), standard v1 (0x03), and standard v2 (0x04).
100
+ *
101
+ * @param ciphertextBase64 - Base64-encoded ciphertext
102
+ * @returns true if any hybrid wrapped-key version, false if legacy RSA-only or unknown
103
+ */
104
+ declare function isHybridEncrypted(ciphertextBase64: string): boolean;
105
+ /**
106
+ * Checks if a ciphertext uses the current standard encryption (v2 HKDF, version 0x04).
107
+ * Use this for security enforcement checks where only the latest format is acceptable.
108
+ *
109
+ * @param ciphertextBase64 - Base64-encoded ciphertext
110
+ * @returns true if current standard (0x04), false otherwise
111
+ */
112
+ declare function isCurrentStandardEncrypted(ciphertextBase64: string): boolean;
113
+ /**
114
+ * Re-wraps legacy RSA-only or older hybrid key material with current hybrid key wrapping (v2).
115
+ * Used during migration to post-quantum protection for sharing and emergency keys.
116
+ *
117
+ * - Version 0x04: already current, returned unchanged.
118
+ * - Version 0x03: decrypted with legacy HKDF-v1, re-encrypted with HKDF-v2.
119
+ * - Version 0x02: decrypted with legacy hybrid path, re-encrypted.
120
+ * - Version 0x01 / unknown: decrypted with RSA-only, re-encrypted.
121
+ *
122
+ * @param legacyCiphertext - Base64-encoded legacy ciphertext
123
+ * @param rsaPrivateKey - JWK string of RSA private key for decryption
124
+ * @param pqSecretKey - Base64-encoded ML-KEM-768 secret key (required for hybrid legacy)
125
+ * @param pqPublicKey - Base64-encoded ML-KEM-768 public key
126
+ * @param rsaPublicKey - JWK string of RSA public key
127
+ * @returns Base64-encoded hybrid ciphertext (version 0x04)
128
+ */
129
+ declare function migrateToHybrid(legacyCiphertext: string, rsaPrivateKey: string, pqSecretKey: string | null, pqPublicKey: string, rsaPublicKey: string, aad?: string): Promise<string>;
130
+ /**
131
+ * ML-KEM-768 key pair
132
+ */
133
+ interface PQKeyPair {
134
+ /** Base64-encoded ML-KEM-768 public key (1184 bytes) */
135
+ publicKey: string;
136
+ /** Base64-encoded ML-KEM-768 secret key (2400 bytes) */
137
+ secretKey: string;
138
+ }
139
+ /**
140
+ * Combined hybrid key pair with both PQ and classical keys
141
+ */
142
+ interface HybridKeyPair {
143
+ /** Base64-encoded ML-KEM-768 public key */
144
+ pqPublicKey: string;
145
+ /** Base64-encoded ML-KEM-768 secret key */
146
+ pqSecretKey: string;
147
+ /** JWK string of RSA-4096 public key */
148
+ rsaPublicKey: string;
149
+ /** JWK string of RSA-4096 private key */
150
+ rsaPrivateKey: string;
151
+ }
152
+
153
+ export { HYBRID_VERSION, type HybridKeyPair, type PQKeyPair, SECURITY_STANDARD_VERSION, type SharedKeyWrapAadInput, buildSharedKeyWrapAad, generateHybridKeyPair, generatePQKeyPair, hybridDecrypt, hybridEncrypt, hybridUnwrapKey, hybridWrapKey, isCurrentStandardEncrypted, isHybridEncrypted, migrateToHybrid };
@@ -0,0 +1,3 @@
1
+ export { HYBRID_VERSION, SECURITY_STANDARD_VERSION, buildSharedKeyWrapAad, generateHybridKeyPair, generatePQKeyPair, hybridDecrypt, hybridEncrypt, hybridUnwrapKey, hybridWrapKey, isCurrentStandardEncrypted, isHybridEncrypted, migrateToHybrid } from '../chunk-T3IV7SHD.js';
2
+ //# sourceMappingURL=index.js.map
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * dis-random — secure random generation.
3
+ *
4
+ * Always sources entropy from the active crypto provider's CSPRNG
5
+ * (`getRandomValues`). DIS never uses `Math.random` for any value that affects
6
+ * confidentiality, integrity, or unpredictability.
7
+ */
8
+ /** Returns `length` cryptographically secure random bytes. */
9
+ declare function randomBytes(length: number): Uint8Array;
10
+ /**
11
+ * Fills an existing `ArrayBufferView` with cryptographically secure random
12
+ * bytes in place. Used by callers that own a buffer they want to overwrite
13
+ * (e.g. secure-memory scrubbing) without allocating a second array.
14
+ */
15
+ declare function fillRandom<T extends ArrayBufferView>(view: T): T;
16
+ /**
17
+ * Returns a cryptographically secure random integer in the inclusive range
18
+ * `[min, max]` using rejection sampling to avoid modulo bias.
19
+ *
20
+ * Byte-for-byte equivalent to the `getSecureRandomInt` helpers in Singra Vault
21
+ * (password generator, backup-code generator): it draws `ceil(log2(range)/8)`
22
+ * bytes big-endian and rejects values above the largest multiple of `range`.
23
+ */
24
+ declare function randomInt(min: number, max: number): number;
25
+ /** Returns a RFC 4122 v4 UUID using the provider's CSPRNG. */
26
+ declare function randomUuid(): string;
27
+
28
+ export { fillRandom, randomBytes, randomInt, randomUuid };
@@ -0,0 +1,5 @@
1
+ export { fillRandom, randomBytes, randomInt, randomUuid } from '../chunk-3HCT6A2P.js';
2
+ import '../chunk-CYIGDF63.js';
3
+ import '../chunk-MJO7IJZC.js';
4
+ //# sourceMappingURL=index.js.map
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * dis-secure-storage / secure-memory — memory-safe handling of key material.
3
+ *
4
+ * Ported from Singra Vault's SecureBuffer. Provides controlled, callback-scoped
5
+ * access to sensitive bytes with explicit zeroing on destroy and a
6
+ * FinalizationRegistry fallback. This is defense-in-depth: JavaScript cannot
7
+ * guarantee memory wiping (GC is non-deterministic, strings are immutable), but
8
+ * controlled access plus best-effort zeroing materially reduces exposure
9
+ * (cf. KeePass CVE-2023-32784).
10
+ */
11
+ /** A wrapper for sensitive binary data with controlled access and zeroing. */
12
+ declare class SecureBuffer {
13
+ private buffer;
14
+ private destroyed;
15
+ constructor(size: number);
16
+ /** Copies `bytes` into a new SecureBuffer. The source is NOT auto-zeroed. */
17
+ static fromBytes(bytes: Uint8Array): SecureBuffer;
18
+ /** Builds a SecureBuffer from a hex string (spaces/dashes allowed). */
19
+ static fromHex(hex: string): SecureBuffer;
20
+ /** Allocates a SecureBuffer filled with CSPRNG bytes. */
21
+ static random(size: number): SecureBuffer;
22
+ /** Synchronous controlled access. Do not retain the buffer past `fn`. */
23
+ use<T>(fn: (data: Uint8Array) => T): T;
24
+ /** Asynchronous controlled access. */
25
+ useAsync<T>(fn: (data: Uint8Array) => Promise<T>): Promise<T>;
26
+ get size(): number;
27
+ get isDestroyed(): boolean;
28
+ /** Zeros the buffer and marks it destroyed. Idempotent. */
29
+ destroy(): void;
30
+ /** Returns a mutable copy of the contents (caller must zero it). */
31
+ toBytes(): Uint8Array;
32
+ /** Constant-time equality comparison against another buffer. */
33
+ equals(other: SecureBuffer | Uint8Array): boolean;
34
+ }
35
+ /** Runs `fn` with a temporary SecureBuffer that is always destroyed afterwards. */
36
+ declare function withSecureBuffer<T>(bytes: Uint8Array, fn: (secure: SecureBuffer) => Promise<T>): Promise<T>;
37
+ /** Zeros multiple buffers. Convenience for `finally` cleanup blocks. */
38
+ declare function zeroBuffers(...buffers: (Uint8Array | null | undefined)[]): void;
39
+
40
+ export { SecureBuffer, withSecureBuffer, zeroBuffers };
@@ -0,0 +1,5 @@
1
+ export { SecureBuffer, withSecureBuffer, zeroBuffers } from '../chunk-RTAJJZKO.js';
2
+ import '../chunk-CYIGDF63.js';
3
+ import '../chunk-MJO7IJZC.js';
4
+ //# sourceMappingURL=index.js.map
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * dis-signing — asymmetric digital signatures.
3
+ *
4
+ * Primitive: ECDSA over the NIST P-256 curve with SHA-256, via WebCrypto.
5
+ * Public keys are exchanged as SPKI bytes; private keys are generated
6
+ * non-extractable so they never leave the device. Signatures are the raw
7
+ * `r || s` concatenation WebCrypto produces (fixed 64 bytes for P-256), which
8
+ * is the exact wire form Singra Vault's op-log device signatures use.
9
+ *
10
+ * Canonicalisation of the signed payload is the caller's responsibility — DIS
11
+ * signs and verifies opaque byte strings and never interprets their structure.
12
+ */
13
+ /** Raw byte length of a P-256 ECDSA signature (`r || s`, 32 bytes each). */
14
+ declare const ECDSA_P256_SIGNATURE_LENGTH = 64;
15
+ interface EcdsaP256KeyPair {
16
+ readonly privateKey: CryptoKey;
17
+ readonly publicKey: CryptoKey;
18
+ /** SPKI-encoded public key bytes, ready to be base64url-encoded for storage. */
19
+ readonly publicKeySpki: Uint8Array;
20
+ }
21
+ /**
22
+ * Generates a fresh non-extractable ECDSA P-256 key pair and exports the
23
+ * public key as SPKI bytes.
24
+ */
25
+ declare function generateEcdsaP256KeyPair(): Promise<EcdsaP256KeyPair>;
26
+ /** Imports an SPKI-encoded P-256 public key for signature verification. */
27
+ declare function importEcdsaP256PublicKeySpki(spki: Uint8Array): Promise<CryptoKey>;
28
+ /**
29
+ * Signs `data` with an ECDSA P-256 private key, returning the raw 64-byte
30
+ * `r || s` signature. Throws {@link DisInvalidArgumentError} if WebCrypto
31
+ * returns an unexpected length (defends against curve/algorithm misuse).
32
+ */
33
+ declare function signEcdsaP256(privateKey: CryptoKey, data: Uint8Array): Promise<Uint8Array>;
34
+ /**
35
+ * Verifies a raw 64-byte `r || s` ECDSA P-256 signature over `data`. Returns
36
+ * `false` for an invalid signature; throws {@link DisInvalidArgumentError} if
37
+ * the signature is not the expected length.
38
+ */
39
+ declare function verifyEcdsaP256(publicKey: CryptoKey, signature: Uint8Array, data: Uint8Array): Promise<boolean>;
40
+
41
+ export { ECDSA_P256_SIGNATURE_LENGTH, type EcdsaP256KeyPair, generateEcdsaP256KeyPair, importEcdsaP256PublicKeySpki, signEcdsaP256, verifyEcdsaP256 };
@@ -0,0 +1,5 @@
1
+ export { ECDSA_P256_SIGNATURE_LENGTH, generateEcdsaP256KeyPair, importEcdsaP256PublicKeySpki, signEcdsaP256, verifyEcdsaP256 } from '../chunk-AB2WZ7Y2.js';
2
+ import '../chunk-CYIGDF63.js';
3
+ import '../chunk-MJO7IJZC.js';
4
+ //# sourceMappingURL=index.js.map
5
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * dis-totp — time-based one-time passwords (RFC 6238).
3
+ *
4
+ * Thin wrapper over the audited `otpauth` library so applications never embed
5
+ * the OTP primitive directly. Parameters are pinned to the values Singra Vault
6
+ * uses (SHA-1, 6 digits, 30-second period, 160-bit secrets) so existing
7
+ * enrolled authenticators keep working unchanged.
8
+ *
9
+ * SHA-1 here is the standardised HMAC inside the TOTP construction (RFC 6238),
10
+ * which every authenticator app implements; it is not used as a hash for any
11
+ * security decision elsewhere.
12
+ */
13
+ /** TOTP parameters, fixed to remain compatible with enrolled authenticators. */
14
+ declare const TOTP_ALGORITHM: "SHA1";
15
+ declare const TOTP_DIGITS = 6;
16
+ declare const TOTP_PERIOD_SECONDS = 30;
17
+ /** Secret size in bytes (160-bit) as produced by {@link generateTotpSecret}. */
18
+ declare const TOTP_SECRET_SIZE = 20;
19
+ /** HMAC algorithms RFC 6238 permits and authenticator apps implement. */
20
+ type TotpAlgorithm = 'SHA1' | 'SHA256' | 'SHA512';
21
+ /**
22
+ * Parameters for third-party TOTP entries (password-manager authenticator
23
+ * storage). Unlike Singra's own 2FA enrolment — which is pinned to
24
+ * SHA-1 / 6 digits / 30 s — imported entries carry whatever parameters the
25
+ * issuing service chose, so each knob is explicit here.
26
+ */
27
+ interface TotpCodeOptions {
28
+ /** HMAC algorithm. Defaults to {@link TOTP_ALGORITHM}. */
29
+ readonly algorithm?: TotpAlgorithm;
30
+ /** Code length. Defaults to {@link TOTP_DIGITS}. */
31
+ readonly digits?: number;
32
+ /** Time step in seconds. Defaults to {@link TOTP_PERIOD_SECONDS}. */
33
+ readonly period?: number;
34
+ /** Epoch milliseconds to generate for. Defaults to the current time. */
35
+ readonly timestamp?: number;
36
+ }
37
+ interface TotpParams {
38
+ /** Issuer label shown in the authenticator app. */
39
+ readonly issuer: string;
40
+ /** Account label (typically the user's email). */
41
+ readonly label: string;
42
+ /** Base32-encoded shared secret. */
43
+ readonly secret: string;
44
+ }
45
+ /** Generates a new base32-encoded 160-bit TOTP secret. */
46
+ declare function generateTotpSecret(): string;
47
+ /** Builds the `otpauth://` provisioning URI for a QR code. */
48
+ declare function buildTotpUri(params: TotpParams): string;
49
+ /**
50
+ * Generates the TOTP code for a base32 `secret` with explicit parameters —
51
+ * the primitive behind a password manager's authenticator view. Throws
52
+ * {@link DisInvalidArgumentError} on a malformed secret so callers can decide
53
+ * how to surface the error.
54
+ */
55
+ declare function generateTotpCode(secret: string, options?: TotpCodeOptions): string;
56
+ /**
57
+ * Builds the `otpauth://` provisioning URI for an entry with explicit
58
+ * parameters (third-party authenticator entries). Singra's own 2FA enrolment
59
+ * should keep using {@link buildTotpUri}, which pins the Singra parameter set.
60
+ */
61
+ declare function buildTotpUriWithOptions(params: TotpParams, options?: Omit<TotpCodeOptions, 'timestamp'>): string;
62
+ /**
63
+ * Verifies a TOTP `code` against a base32 `secret`, allowing `window` periods
64
+ * of clock drift on either side (default 1 = ±30s). Returns `true` on a match.
65
+ * Malformed secrets/codes return `false` rather than throwing.
66
+ */
67
+ declare function verifyTotpCode(secret: string, code: string, window?: number): boolean;
68
+
69
+ export { TOTP_ALGORITHM, TOTP_DIGITS, TOTP_PERIOD_SECONDS, TOTP_SECRET_SIZE, type TotpAlgorithm, type TotpCodeOptions, type TotpParams, buildTotpUri, buildTotpUriWithOptions, generateTotpCode, generateTotpSecret, verifyTotpCode };
@@ -0,0 +1,4 @@
1
+ export { TOTP_ALGORITHM, TOTP_DIGITS, TOTP_PERIOD_SECONDS, TOTP_SECRET_SIZE, buildTotpUri, buildTotpUriWithOptions, generateTotpCode, generateTotpSecret, verifyTotpCode } from '../chunk-OA5ARYJM.js';
2
+ import '../chunk-MJO7IJZC.js';
3
+ //# sourceMappingURL=index.js.map
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}