@yielded/crypto 0.1.0-beta.29 → 0.1.0-beta.31

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 (53) hide show
  1. package/README.md +8 -9
  2. package/THIRD_PARTY_NOTICES.md +3 -0
  3. package/dist/Kdf.d.mts +16 -2
  4. package/dist/Kdf.mjs +21 -3
  5. package/dist/Kdf.mjs.map +1 -1
  6. package/dist/Portable.d.mts +2 -1
  7. package/dist/Portable.mjs +3 -1
  8. package/dist/Portable.mjs.map +1 -1
  9. package/dist/Signature.d.mts +46 -0
  10. package/dist/Signature.mjs +15 -1
  11. package/dist/Signature.mjs.map +1 -1
  12. package/dist/WebCrypto.mjs +2 -1
  13. package/dist/WebCrypto.mjs.map +1 -1
  14. package/dist/internal/argon2-core.mjs +19 -12
  15. package/dist/internal/argon2-core.mjs.map +1 -1
  16. package/dist/internal/argon2-wasm.mjs +33 -0
  17. package/dist/internal/argon2-wasm.mjs.map +1 -0
  18. package/dist/internal/argon2.mjs +6 -5
  19. package/dist/internal/argon2.mjs.map +1 -1
  20. package/dist/internal/argon2.wasm +0 -0
  21. package/dist/internal/kdf.mjs +21 -1
  22. package/dist/internal/kdf.mjs.map +1 -1
  23. package/dist/internal/layer.mjs.map +1 -1
  24. package/dist/internal/node.d.mts +3 -2
  25. package/dist/internal/node.mjs +4 -3
  26. package/dist/internal/node.mjs.map +1 -1
  27. package/dist/internal/scrypt-backend.mjs +10 -0
  28. package/dist/internal/scrypt-backend.mjs.map +1 -0
  29. package/dist/internal/scrypt.mjs +25 -0
  30. package/dist/internal/scrypt.mjs.map +1 -0
  31. package/dist/internal/signature.mjs +85 -2
  32. package/dist/internal/signature.mjs.map +1 -1
  33. package/dist/platform-workerd.d.mts +14 -0
  34. package/dist/platform-workerd.mjs +18 -0
  35. package/dist/platform-workerd.mjs.map +1 -0
  36. package/package.json +1 -1
  37. package/src/Kdf.ts +20 -2
  38. package/src/Portable.ts +4 -1
  39. package/src/Signature.ts +24 -0
  40. package/src/WebCrypto.ts +2 -1
  41. package/src/internal/argon2-block.c +76 -0
  42. package/src/internal/argon2-core.ts +36 -12
  43. package/src/internal/argon2-wasm.ts +59 -0
  44. package/src/internal/argon2.ts +28 -23
  45. package/src/internal/argon2.wasm +0 -0
  46. package/src/internal/kdf.ts +39 -1
  47. package/src/internal/layer.ts +4 -1
  48. package/src/internal/node.ts +6 -3
  49. package/src/internal/scrypt-backend.ts +25 -0
  50. package/src/internal/scrypt.ts +38 -0
  51. package/src/internal/signature.ts +86 -1
  52. package/src/internal/wasm.d.ts +5 -0
  53. package/src/platform-workerd.ts +16 -0
@@ -1,11 +1,13 @@
1
1
  import { InvalidInput, UnsupportedAlgorithm } from "../Errors.mjs";
2
- import { Argon2idInput, HkdfInput, Kdf, Pbkdf2Input } from "../Kdf.mjs";
2
+ import { Argon2idInput, HkdfInput, Kdf, Pbkdf2Input, ScryptInput } from "../Kdf.mjs";
3
3
  import { KdfAdmission } from "../KdfAdmission.mjs";
4
4
  import { copy, decode, importError, nativeError, withSecret } from "./common.mjs";
5
+ import { ScryptBackend } from "./scrypt-backend.mjs";
5
6
  import { Effect, Redacted, Schema } from "effect";
6
7
  //#region src/internal/kdf.ts
7
8
  const makeKdf = Effect.fnUntraced(function* (subtle, limits, argon2) {
8
9
  const admission = yield* KdfAdmission;
10
+ const scrypt = yield* ScryptBackend;
9
11
  const boundedBytes = Schema.Uint8Array.check(Schema.isMaxLength(limits.maximumInputBytes));
10
12
  const output = Schema.Int.check(Schema.isBetween({
11
13
  minimum: 1,
@@ -14,6 +16,24 @@ const makeKdf = Effect.fnUntraced(function* (subtle, limits, argon2) {
14
16
  const inputBytes = (input) => decode(boundedBytes, input, "data");
15
17
  const outputLength = (input) => decode(output, input, "parameters");
16
18
  return Kdf.of({
19
+ scrypt: (input) => admission.run(Effect.gen(function* () {
20
+ const value = yield* decode(ScryptInput, input, "parameters");
21
+ yield* outputLength(value.length);
22
+ yield* inputBytes(Redacted.value(value.password));
23
+ yield* inputBytes(value.salt);
24
+ const memoryBytes = 128 * value.blockSize * (value.cost + value.parallelism + 2);
25
+ if (!Number.isInteger(Math.log2(value.cost)) || Math.log2(value.cost) >= 16 * value.blockSize || value.blockSize * value.parallelism >= 2 ** 30 || memoryBytes > limits.maximumMemoryKiB * 1024 || value.cost * value.blockSize * value.parallelism / 8 > limits.maximumMemoryPasses) return yield* InvalidInput.make({ reason: "parameters" });
26
+ const salt = yield* copy(value.salt);
27
+ return yield* withSecret(value.password, (password) => scrypt.derive({
28
+ password,
29
+ salt,
30
+ cost: value.cost,
31
+ blockSize: value.blockSize,
32
+ parallelism: value.parallelism,
33
+ length: value.length,
34
+ maximumMemoryBytes: limits.maximumMemoryKiB * 1024
35
+ }).pipe(Effect.map(Redacted.make)));
36
+ })),
17
37
  pbkdf2: (input) => admission.run(Effect.gen(function* () {
18
38
  const value = yield* decode(Pbkdf2Input, input, "parameters");
19
39
  yield* decode(Schema.Int.check(Schema.isBetween({
@@ -1 +1 @@
1
- {"version":3,"file":"kdf.mjs","names":[],"sources":["../../src/internal/kdf.ts"],"sourcesContent":["import { Effect, Redacted, Schema } from \"effect\";\n\nimport { InvalidInput, type OperationError, UnsupportedAlgorithm } from \"../Errors\";\nimport { Argon2idInput, HkdfInput, Kdf, type Limits, Pbkdf2Input } from \"../Kdf\";\nimport { KdfAdmission } from \"../KdfAdmission\";\nimport { copy, decode, importError, nativeError, withSecret } from \"./common\";\n\nexport interface Argon2Parameters {\n readonly password: Uint8Array<ArrayBuffer>;\n readonly salt: Uint8Array<ArrayBuffer>;\n readonly memoryKiB: number;\n readonly passes: number;\n readonly parallelism: number;\n readonly length: number;\n readonly secret?: Uint8Array<ArrayBuffer>;\n readonly associatedData: Uint8Array<ArrayBuffer>;\n}\n\nexport type Argon2 = (input: Argon2Parameters) => Effect.Effect<Uint8Array, OperationError>;\n\nexport const makeKdf = Effect.fnUntraced(function* (\n subtle: SubtleCrypto,\n limits: Limits,\n argon2?: Argon2,\n) {\n const admission = yield* KdfAdmission;\n const boundedBytes = Schema.Uint8Array.check(Schema.isMaxLength(limits.maximumInputBytes));\n\n const output = Schema.Int.check(\n Schema.isBetween({ minimum: 1, maximum: limits.maximumOutputBytes }),\n );\n\n const inputBytes = (input: Uint8Array) => decode(boundedBytes, input, \"data\");\n const outputLength = (input: number) => decode(output, input, \"parameters\");\n\n return Kdf.of({\n pbkdf2: (input) =>\n admission.run(\n Effect.gen(function* () {\n const value = yield* decode(Pbkdf2Input, input, \"parameters\");\n\n yield* decode(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: limits.maximumIterations })),\n value.iterations,\n \"parameters\",\n );\n yield* outputLength(value.length);\n yield* inputBytes(Redacted.value(value.password));\n yield* inputBytes(value.salt);\n const salt = yield* copy(value.salt);\n\n return yield* withSecret(value.password, (password) =>\n Effect.gen(function* () {\n const key = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"raw\", password, \"PBKDF2\", false, [\"deriveBits\"]),\n catch: importError,\n });\n\n const result = yield* Effect.tryPromise({\n try: () =>\n subtle.deriveBits(\n { name: \"PBKDF2\", hash: \"SHA-256\", salt, iterations: value.iterations },\n key,\n value.length * 8,\n ),\n catch: nativeError,\n });\n\n return Redacted.make(new Uint8Array(result));\n }).pipe(Effect.uninterruptible),\n );\n }),\n ),\n hkdf: (input) =>\n admission.run(\n Effect.gen(function* () {\n const value = yield* decode(HkdfInput, input, \"parameters\");\n\n yield* outputLength(value.length);\n yield* inputBytes(Redacted.value(value.key));\n yield* inputBytes(value.salt);\n yield* inputBytes(value.info);\n const salt = yield* copy(value.salt);\n const info = yield* copy(value.info);\n\n return yield* withSecret(value.key, (material) =>\n Effect.gen(function* () {\n const key = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"raw\", material, \"HKDF\", false, [\"deriveBits\"]),\n catch: importError,\n });\n\n const result = yield* Effect.tryPromise({\n try: () =>\n subtle.deriveBits(\n { name: \"HKDF\", hash: \"SHA-256\", salt, info },\n key,\n value.length * 8,\n ),\n catch: nativeError,\n });\n\n return Redacted.make(new Uint8Array(result));\n }).pipe(Effect.uninterruptible),\n );\n }),\n ),\n argon2id: (input) =>\n admission.run(\n Effect.gen(function* () {\n const value = yield* decode(Argon2idInput, input, \"parameters\");\n\n yield* outputLength(value.length);\n yield* inputBytes(Redacted.value(value.password));\n yield* inputBytes(value.salt);\n if (value.secret !== undefined) yield* inputBytes(Redacted.value(value.secret));\n if (value.associatedData !== undefined) yield* inputBytes(value.associatedData);\n\n if (\n value.memoryKiB < 8 * value.parallelism ||\n value.memoryKiB > limits.maximumMemoryKiB ||\n value.passes > limits.maximumPasses ||\n value.parallelism > limits.maximumParallelism ||\n value.memoryKiB * value.passes > limits.maximumMemoryPasses\n )\n return yield* InvalidInput.make({ reason: \"parameters\" });\n if (argon2 === undefined) return yield* UnsupportedAlgorithm.make({});\n\n const salt = yield* copy(value.salt);\n const associatedData = yield* copy(value.associatedData ?? new Uint8Array());\n\n return yield* withSecret(value.password, (password) => {\n const derive = (secret?: Uint8Array<ArrayBuffer>) =>\n argon2({\n password,\n salt,\n ...(secret === undefined ? {} : { secret }),\n associatedData,\n memoryKiB: value.memoryKiB,\n passes: value.passes,\n parallelism: value.parallelism,\n length: value.length,\n }).pipe(Effect.map((bytes) => Redacted.make(bytes)));\n\n return value.secret === undefined ? derive() : withSecret(value.secret, derive);\n });\n }),\n ),\n });\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"kdf.mjs","names":[],"sources":["../../src/internal/kdf.ts"],"sourcesContent":["import { Effect, Redacted, Schema } from \"effect\";\n\nimport { InvalidInput, type OperationError, UnsupportedAlgorithm } from \"../Errors\";\nimport { Argon2idInput, HkdfInput, Kdf, type Limits, Pbkdf2Input, ScryptInput } from \"../Kdf\";\nimport { KdfAdmission } from \"../KdfAdmission\";\nimport { copy, decode, importError, nativeError, withSecret } from \"./common\";\nimport { ScryptBackend } from \"./scrypt-backend\";\n\nexport interface Argon2Parameters {\n readonly password: Uint8Array<ArrayBuffer>;\n readonly salt: Uint8Array<ArrayBuffer>;\n readonly memoryKiB: number;\n readonly passes: number;\n readonly parallelism: number;\n readonly length: number;\n readonly secret?: Uint8Array<ArrayBuffer>;\n readonly associatedData: Uint8Array<ArrayBuffer>;\n}\n\nexport type Argon2 = (input: Argon2Parameters) => Effect.Effect<Uint8Array, OperationError>;\n\nexport const makeKdf = Effect.fnUntraced(function* (\n subtle: SubtleCrypto,\n limits: Limits,\n argon2?: Argon2,\n) {\n const admission = yield* KdfAdmission;\n const scrypt = yield* ScryptBackend;\n const boundedBytes = Schema.Uint8Array.check(Schema.isMaxLength(limits.maximumInputBytes));\n\n const output = Schema.Int.check(\n Schema.isBetween({ minimum: 1, maximum: limits.maximumOutputBytes }),\n );\n\n const inputBytes = (input: Uint8Array) => decode(boundedBytes, input, \"data\");\n const outputLength = (input: number) => decode(output, input, \"parameters\");\n\n return Kdf.of({\n scrypt: (input) =>\n admission.run(\n Effect.gen(function* () {\n const value = yield* decode(ScryptInput, input, \"parameters\");\n\n yield* outputLength(value.length);\n yield* inputBytes(Redacted.value(value.password));\n yield* inputBytes(value.salt);\n\n const memoryBytes = 128 * value.blockSize * (value.cost + value.parallelism + 2);\n\n if (\n !Number.isInteger(Math.log2(value.cost)) ||\n Math.log2(value.cost) >= 16 * value.blockSize ||\n value.blockSize * value.parallelism >= 2 ** 30 ||\n memoryBytes > limits.maximumMemoryKiB * 1024 ||\n (value.cost * value.blockSize * value.parallelism) / 8 > limits.maximumMemoryPasses\n )\n return yield* InvalidInput.make({ reason: \"parameters\" });\n const salt = yield* copy(value.salt);\n\n return yield* withSecret(value.password, (password) =>\n scrypt\n .derive({\n password,\n salt,\n cost: value.cost,\n blockSize: value.blockSize,\n parallelism: value.parallelism,\n length: value.length,\n maximumMemoryBytes: limits.maximumMemoryKiB * 1024,\n })\n .pipe(Effect.map(Redacted.make)),\n );\n }),\n ),\n pbkdf2: (input) =>\n admission.run(\n Effect.gen(function* () {\n const value = yield* decode(Pbkdf2Input, input, \"parameters\");\n\n yield* decode(\n Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: limits.maximumIterations })),\n value.iterations,\n \"parameters\",\n );\n yield* outputLength(value.length);\n yield* inputBytes(Redacted.value(value.password));\n yield* inputBytes(value.salt);\n const salt = yield* copy(value.salt);\n\n return yield* withSecret(value.password, (password) =>\n Effect.gen(function* () {\n const key = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"raw\", password, \"PBKDF2\", false, [\"deriveBits\"]),\n catch: importError,\n });\n\n const result = yield* Effect.tryPromise({\n try: () =>\n subtle.deriveBits(\n { name: \"PBKDF2\", hash: \"SHA-256\", salt, iterations: value.iterations },\n key,\n value.length * 8,\n ),\n catch: nativeError,\n });\n\n return Redacted.make(new Uint8Array(result));\n }).pipe(Effect.uninterruptible),\n );\n }),\n ),\n hkdf: (input) =>\n admission.run(\n Effect.gen(function* () {\n const value = yield* decode(HkdfInput, input, \"parameters\");\n\n yield* outputLength(value.length);\n yield* inputBytes(Redacted.value(value.key));\n yield* inputBytes(value.salt);\n yield* inputBytes(value.info);\n const salt = yield* copy(value.salt);\n const info = yield* copy(value.info);\n\n return yield* withSecret(value.key, (material) =>\n Effect.gen(function* () {\n const key = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"raw\", material, \"HKDF\", false, [\"deriveBits\"]),\n catch: importError,\n });\n\n const result = yield* Effect.tryPromise({\n try: () =>\n subtle.deriveBits(\n { name: \"HKDF\", hash: \"SHA-256\", salt, info },\n key,\n value.length * 8,\n ),\n catch: nativeError,\n });\n\n return Redacted.make(new Uint8Array(result));\n }).pipe(Effect.uninterruptible),\n );\n }),\n ),\n argon2id: (input) =>\n admission.run(\n Effect.gen(function* () {\n const value = yield* decode(Argon2idInput, input, \"parameters\");\n\n yield* outputLength(value.length);\n yield* inputBytes(Redacted.value(value.password));\n yield* inputBytes(value.salt);\n if (value.secret !== undefined) yield* inputBytes(Redacted.value(value.secret));\n if (value.associatedData !== undefined) yield* inputBytes(value.associatedData);\n\n if (\n value.memoryKiB < 8 * value.parallelism ||\n value.memoryKiB > limits.maximumMemoryKiB ||\n value.passes > limits.maximumPasses ||\n value.parallelism > limits.maximumParallelism ||\n value.memoryKiB * value.passes > limits.maximumMemoryPasses\n )\n return yield* InvalidInput.make({ reason: \"parameters\" });\n if (argon2 === undefined) return yield* UnsupportedAlgorithm.make({});\n\n const salt = yield* copy(value.salt);\n const associatedData = yield* copy(value.associatedData ?? new Uint8Array());\n\n return yield* withSecret(value.password, (password) => {\n const derive = (secret?: Uint8Array<ArrayBuffer>) =>\n argon2({\n password,\n salt,\n ...(secret === undefined ? {} : { secret }),\n associatedData,\n memoryKiB: value.memoryKiB,\n passes: value.passes,\n parallelism: value.parallelism,\n length: value.length,\n }).pipe(Effect.map((bytes) => Redacted.make(bytes)));\n\n return value.secret === undefined ? derive() : withSecret(value.secret, derive);\n });\n }),\n ),\n });\n});\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"layer.mjs","names":[],"sources":["../../src/internal/layer.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\n\nimport { Aead } from \"../Aead\";\nimport { Hmac } from \"../Hmac\";\nimport { defaultLimits, Kdf, Limits } from \"../Kdf\";\nimport { Signature } from \"../Signature\";\nimport { makeAead, type XChaCha } from \"./aead\";\nimport { decode } from \"./common\";\nimport { makeHmac } from \"./hmac\";\nimport { type Argon2, makeKdf } from \"./kdf\";\nimport { makeSignature } from \"./signature\";\n\nexport const makeLayer = (\n subtle: SubtleCrypto,\n input: Partial<Limits>,\n extensions: { readonly argon2?: Argon2; readonly xchacha?: XChaCha } = {},\n) => {\n const snapshot = { ...defaultLimits, ...input };\n\n return Layer.effectContext(\n Effect.gen(function* () {\n const limits = yield* decode(Limits, snapshot, \"parameters\");\n const kdf = yield* makeKdf(subtle, limits, extensions.argon2);\n\n return Context.make(Aead, makeAead(subtle, extensions.xchacha)).pipe(\n Context.add(Hmac, makeHmac(subtle)),\n Context.add(Kdf, kdf),\n Context.add(Signature, makeSignature(subtle)),\n );\n }),\n );\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,aACX,QACA,OACA,aAAuE,CAAC,MACrE;CACH,MAAM,WAAW;EAAE,GAAG;EAAe,GAAG;CAAM;CAE9C,OAAO,MAAM,cACX,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,UAAU,YAAY;EAC3D,MAAM,MAAM,OAAO,QAAQ,QAAQ,QAAQ,WAAW,MAAM;EAE5D,OAAO,QAAQ,KAAK,MAAM,SAAS,QAAQ,WAAW,OAAO,CAAC,CAAC,CAAC,KAC9D,QAAQ,IAAI,MAAM,SAAS,MAAM,CAAC,GAClC,QAAQ,IAAI,KAAK,GAAG,GACpB,QAAQ,IAAI,WAAW,cAAc,MAAM,CAAC,CAC9C;CACF,CAAC,CACH;AACF"}
1
+ {"version":3,"file":"layer.mjs","names":[],"sources":["../../src/internal/layer.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\n\nimport { Aead } from \"../Aead\";\nimport { Hmac } from \"../Hmac\";\nimport { defaultLimits, Kdf, Limits } from \"../Kdf\";\nimport { Signature } from \"../Signature\";\nimport { makeAead, type XChaCha } from \"./aead\";\nimport { decode } from \"./common\";\nimport { makeHmac } from \"./hmac\";\nimport { type Argon2, makeKdf } from \"./kdf\";\nimport { makeSignature } from \"./signature\";\n\nexport const makeLayer = (\n subtle: SubtleCrypto,\n input: Partial<Limits>,\n extensions: {\n readonly argon2?: Argon2;\n readonly xchacha?: XChaCha;\n } = {},\n) => {\n const snapshot = { ...defaultLimits, ...input };\n\n return Layer.effectContext(\n Effect.gen(function* () {\n const limits = yield* decode(Limits, snapshot, \"parameters\");\n const kdf = yield* makeKdf(subtle, limits, extensions.argon2);\n\n return Context.make(Aead, makeAead(subtle, extensions.xchacha)).pipe(\n Context.add(Hmac, makeHmac(subtle)),\n Context.add(Kdf, kdf),\n Context.add(Signature, makeSignature(subtle)),\n );\n }),\n );\n};\n"],"mappings":";;;;;;;;;;;AAYA,MAAa,aACX,QACA,OACA,aAGI,CAAC,MACF;CACH,MAAM,WAAW;EAAE,GAAG;EAAe,GAAG;CAAM;CAE9C,OAAO,MAAM,cACX,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,OAAO,QAAQ,UAAU,YAAY;EAC3D,MAAM,MAAM,OAAO,QAAQ,QAAQ,QAAQ,WAAW,MAAM;EAE5D,OAAO,QAAQ,KAAK,MAAM,SAAS,QAAQ,WAAW,OAAO,CAAC,CAAC,CAAC,KAC9D,QAAQ,IAAI,MAAM,SAAS,MAAM,CAAC,GAClC,QAAQ,IAAI,KAAK,GAAG,GACpB,QAAQ,IAAI,WAAW,cAAc,MAAM,CAAC,CAC9C;CACF,CAAC,CACH;AACF"}
@@ -4,8 +4,9 @@ import { Hmac } from "../Hmac.mjs";
4
4
  import { Kdf, Limits } from "../Kdf.mjs";
5
5
  import { KdfAdmission } from "../KdfAdmission.mjs";
6
6
  import { Signature } from "../Signature.mjs";
7
+ import { Layer } from "effect";
7
8
  //#region src/internal/node.d.ts
8
- /** Node-compatible WebCrypto/Argon2id with the portable XChaCha20-Poly1305 extension. */
9
- export declare const layer: (limits?: Partial<Limits>) => import("effect/Layer").Layer<Aead | Hmac | Kdf | Signature, InvalidInput, KdfAdmission>;
9
+ /** Node-compatible WebCrypto and native password KDFs with portable XChaCha20-Poly1305. */
10
+ export declare const layer: (limits?: Partial<Limits>) => Layer.Layer<Aead | Hmac | Kdf | Signature, InvalidInput, KdfAdmission>;
10
11
  //#endregion
11
12
  //# sourceMappingURL=node.d.mts.map
@@ -1,7 +1,8 @@
1
1
  import { CryptoUnavailable, UnsupportedAlgorithm } from "../Errors.mjs";
2
2
  import { makeLayer } from "./layer.mjs";
3
+ import { layer as layer$1 } from "./scrypt.mjs";
3
4
  import { xchacha } from "./xchacha.mjs";
4
- import { Effect, Result } from "effect";
5
+ import { Effect, Layer, Result } from "effect";
5
6
  import * as crypto from "node:crypto";
6
7
  //#region src/internal/node.ts
7
8
  const argon2 = Effect.fnUntraced(function* (input) {
@@ -23,11 +24,11 @@ const argon2 = Effect.fnUntraced(function* (input) {
23
24
  if (Result.isFailure(registration)) resume(Effect.fail(registration.failure));
24
25
  }).pipe(Effect.uninterruptible);
25
26
  });
26
- /** Node-compatible WebCrypto/Argon2id with the portable XChaCha20-Poly1305 extension. */
27
+ /** Node-compatible WebCrypto and native password KDFs with portable XChaCha20-Poly1305. */
27
28
  const layer = (limits = {}) => makeLayer(crypto.webcrypto.subtle, limits, {
28
29
  argon2,
29
30
  xchacha
30
- });
31
+ }).pipe(Layer.provide(layer$1));
31
32
  //#endregion
32
33
  export { layer };
33
34
 
@@ -1 +1 @@
1
- {"version":3,"file":"node.mjs","names":[],"sources":["../../src/internal/node.ts"],"sourcesContent":["// @effect-diagnostics-next-line nodeBuiltinImport:off -- This platform adapter needs native Argon2 and WebCrypto, which Effect Crypto does not expose.\nimport * as crypto from \"node:crypto\";\n\nimport { Effect, Result } from \"effect\";\n\nimport { CryptoUnavailable, UnsupportedAlgorithm } from \"../Errors\";\nimport type { Limits } from \"../Kdf\";\nimport type { Argon2, Argon2Parameters } from \"./kdf\";\nimport { makeLayer } from \"./layer\";\nimport { xchacha } from \"./xchacha\";\n\nconst argon2: Argon2 = Effect.fnUntraced(function* (input: Argon2Parameters) {\n // Namespace import keeps this module loadable on Node versions without Argon2.\n if (typeof crypto.argon2 !== \"function\") return yield* UnsupportedAlgorithm.make({});\n\n // Node cannot cancel this work. Keep borrowed buffers and admission until the\n // callback completes, including when its caller has requested interruption.\n return yield* Effect.callback<Uint8Array, CryptoUnavailable>((resume) => {\n const registration = Result.try({\n try: () =>\n crypto.argon2(\n \"argon2id\",\n {\n message: input.password,\n nonce: input.salt,\n parallelism: input.parallelism,\n memory: input.memoryKiB,\n passes: input.passes,\n tagLength: input.length,\n secret: input.secret,\n associatedData: input.associatedData,\n },\n (error, key) =>\n resume(error === null ? Effect.succeed(key) : Effect.fail(CryptoUnavailable.make({}))),\n ),\n catch: () => CryptoUnavailable.make({}),\n });\n\n if (Result.isFailure(registration)) resume(Effect.fail(registration.failure));\n }).pipe(Effect.uninterruptible);\n});\n\n/** Node-compatible WebCrypto/Argon2id with the portable XChaCha20-Poly1305 extension. */\nexport const layer = (limits: Partial<Limits> = {}) =>\n // Node's declarations include additional key usages absent from lib.dom. The\n // standard operations used here share the WebCrypto ABI; no payload is cast.\n makeLayer(crypto.webcrypto.subtle as SubtleCrypto, limits, { argon2, xchacha });\n"],"mappings":";;;;;;AAWA,MAAM,SAAiB,OAAO,WAAW,WAAW,OAAyB;CAE3E,IAAI,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,qBAAqB,KAAK,CAAC,CAAC;CAInF,OAAO,OAAO,OAAO,UAAyC,WAAW;EACvE,MAAM,eAAe,OAAO,IAAI;GAC9B,WACE,OAAO,OACL,YACA;IACE,SAAS,MAAM;IACf,OAAO,MAAM;IACb,aAAa,MAAM;IACnB,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,WAAW,MAAM;IACjB,QAAQ,MAAM;IACd,gBAAgB,MAAM;GACxB,IACC,OAAO,QACN,OAAO,UAAU,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,KAAK,kBAAkB,KAAK,CAAC,CAAC,CAAC,CAAC,CACzF;GACF,aAAa,kBAAkB,KAAK,CAAC,CAAC;EACxC,CAAC;EAED,IAAI,OAAO,UAAU,YAAY,GAAG,OAAO,OAAO,KAAK,aAAa,OAAO,CAAC;CAC9E,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe;AAChC,CAAC;;AAGD,MAAa,SAAS,SAA0B,CAAC,MAG/C,UAAU,OAAO,UAAU,QAAwB,QAAQ;CAAE;CAAQ;AAAQ,CAAC"}
1
+ {"version":3,"file":"node.mjs","names":["Scrypt.layer"],"sources":["../../src/internal/node.ts"],"sourcesContent":["// @effect-diagnostics-next-line nodeBuiltinImport:off -- This platform adapter needs native Argon2 and WebCrypto, which Effect Crypto does not expose.\nimport * as crypto from \"node:crypto\";\n\nimport { Effect, Layer, Result } from \"effect\";\n\nimport { CryptoUnavailable, UnsupportedAlgorithm } from \"../Errors\";\nimport type { Limits } from \"../Kdf\";\nimport type { Argon2, Argon2Parameters } from \"./kdf\";\nimport { makeLayer } from \"./layer\";\nimport * as Scrypt from \"./scrypt\";\nimport { xchacha } from \"./xchacha\";\n\nconst argon2: Argon2 = Effect.fnUntraced(function* (input: Argon2Parameters) {\n // Namespace import keeps this module loadable on Node versions without Argon2.\n if (typeof crypto.argon2 !== \"function\") return yield* UnsupportedAlgorithm.make({});\n\n // Node cannot cancel this work. Keep borrowed buffers and admission until the\n // callback completes, including when its caller has requested interruption.\n return yield* Effect.callback<Uint8Array, CryptoUnavailable>((resume) => {\n const registration = Result.try({\n try: () =>\n crypto.argon2(\n \"argon2id\",\n {\n message: input.password,\n nonce: input.salt,\n parallelism: input.parallelism,\n memory: input.memoryKiB,\n passes: input.passes,\n tagLength: input.length,\n secret: input.secret,\n associatedData: input.associatedData,\n },\n (error, key) =>\n resume(error === null ? Effect.succeed(key) : Effect.fail(CryptoUnavailable.make({}))),\n ),\n catch: () => CryptoUnavailable.make({}),\n });\n\n if (Result.isFailure(registration)) resume(Effect.fail(registration.failure));\n }).pipe(Effect.uninterruptible);\n});\n\n/** Node-compatible WebCrypto and native password KDFs with portable XChaCha20-Poly1305. */\nexport const layer = (limits: Partial<Limits> = {}) =>\n // Node's declarations include additional key usages absent from lib.dom. The\n // standard operations used here share the WebCrypto ABI; no payload is cast.\n makeLayer(crypto.webcrypto.subtle as SubtleCrypto, limits, { argon2, xchacha }).pipe(\n Layer.provide(Scrypt.layer),\n );\n"],"mappings":";;;;;;;AAYA,MAAM,SAAiB,OAAO,WAAW,WAAW,OAAyB;CAE3E,IAAI,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,qBAAqB,KAAK,CAAC,CAAC;CAInF,OAAO,OAAO,OAAO,UAAyC,WAAW;EACvE,MAAM,eAAe,OAAO,IAAI;GAC9B,WACE,OAAO,OACL,YACA;IACE,SAAS,MAAM;IACf,OAAO,MAAM;IACb,aAAa,MAAM;IACnB,QAAQ,MAAM;IACd,QAAQ,MAAM;IACd,WAAW,MAAM;IACjB,QAAQ,MAAM;IACd,gBAAgB,MAAM;GACxB,IACC,OAAO,QACN,OAAO,UAAU,OAAO,OAAO,QAAQ,GAAG,IAAI,OAAO,KAAK,kBAAkB,KAAK,CAAC,CAAC,CAAC,CAAC,CACzF;GACF,aAAa,kBAAkB,KAAK,CAAC,CAAC;EACxC,CAAC;EAED,IAAI,OAAO,UAAU,YAAY,GAAG,OAAO,OAAO,KAAK,aAAa,OAAO,CAAC;CAC9E,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe;AAChC,CAAC;;AAGD,MAAa,SAAS,SAA0B,CAAC,MAG/C,UAAU,OAAO,UAAU,QAAwB,QAAQ;CAAE;CAAQ;AAAQ,CAAC,CAAC,CAAC,KAC9E,MAAM,QAAQA,OAAY,CAC5B"}
@@ -0,0 +1,10 @@
1
+ import { UnsupportedAlgorithm } from "../Errors.mjs";
2
+ import { Context, Effect, Layer } from "effect";
3
+ //#region src/internal/scrypt-backend.ts
4
+ /** Raw derivation selected by a platform Layer; Kdf owns validation and admission. */
5
+ var ScryptBackend = class extends Context.Service()("@yielded/crypto/internal/scrypt-backend") {};
6
+ const layerUnsupported = Layer.succeed(ScryptBackend, { derive: () => Effect.fail(UnsupportedAlgorithm.make({})) });
7
+ //#endregion
8
+ export { ScryptBackend, layerUnsupported };
9
+
10
+ //# sourceMappingURL=scrypt-backend.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrypt-backend.mjs","names":[],"sources":["../../src/internal/scrypt-backend.ts"],"sourcesContent":["import { Context, Effect, Layer } from \"effect\";\n\nimport { type OperationError, UnsupportedAlgorithm } from \"../Errors\";\n\nexport interface ScryptParameters {\n readonly password: Uint8Array<ArrayBuffer>;\n readonly salt: Uint8Array<ArrayBuffer>;\n readonly cost: number;\n readonly blockSize: number;\n readonly parallelism: number;\n readonly length: number;\n readonly maximumMemoryBytes: number;\n}\n\n/** Raw derivation selected by a platform Layer; Kdf owns validation and admission. */\nexport class ScryptBackend extends Context.Service<\n ScryptBackend,\n {\n readonly derive: (input: ScryptParameters) => Effect.Effect<Uint8Array, OperationError>;\n }\n>()(\"@yielded/crypto/internal/scrypt-backend\") {}\n\nexport const layerUnsupported = Layer.succeed(ScryptBackend, {\n derive: () => Effect.fail(UnsupportedAlgorithm.make({})),\n});\n"],"mappings":";;;;AAeA,IAAa,gBAAb,cAAmC,QAAQ,QAKzC,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC;AAEhD,MAAa,mBAAmB,MAAM,QAAQ,eAAe,EAC3D,cAAc,OAAO,KAAK,qBAAqB,KAAK,CAAC,CAAC,CAAC,EACzD,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { CryptoUnavailable, UnsupportedAlgorithm } from "../Errors.mjs";
2
+ import { ScryptBackend } from "./scrypt-backend.mjs";
3
+ import { Effect, Layer, Result } from "effect";
4
+ import * as crypto from "node:crypto";
5
+ //#region src/internal/scrypt.ts
6
+ const derive = Effect.fnUntraced(function* (input) {
7
+ if (typeof crypto.scrypt !== "function") return yield* UnsupportedAlgorithm.make({});
8
+ return yield* Effect.callback((resume) => {
9
+ const registration = Result.try({
10
+ try: () => crypto.scrypt(input.password, input.salt, input.length, {
11
+ N: input.cost,
12
+ r: input.blockSize,
13
+ p: input.parallelism,
14
+ maxmem: input.maximumMemoryBytes
15
+ }, (error, key) => resume(error ? Effect.fail(CryptoUnavailable.make({})) : Effect.succeed(key))),
16
+ catch: () => CryptoUnavailable.make({})
17
+ });
18
+ if (Result.isFailure(registration)) resume(Effect.fail(registration.failure));
19
+ }).pipe(Effect.uninterruptible);
20
+ });
21
+ const layer = Layer.succeed(ScryptBackend, { derive });
22
+ //#endregion
23
+ export { layer };
24
+
25
+ //# sourceMappingURL=scrypt.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrypt.mjs","names":[],"sources":["../../src/internal/scrypt.ts"],"sourcesContent":["// @effect-diagnostics-next-line nodeBuiltinImport:off -- Native scrypt is not exposed by Effect Crypto or WebCrypto.\nimport * as crypto from \"node:crypto\";\n\nimport { Effect, Layer, Result } from \"effect\";\n\nimport { CryptoUnavailable, UnsupportedAlgorithm } from \"../Errors\";\nimport { ScryptBackend, type ScryptParameters } from \"./scrypt-backend\";\n\nconst derive = Effect.fnUntraced(function* (input: ScryptParameters) {\n if (typeof crypto.scrypt !== \"function\") return yield* UnsupportedAlgorithm.make({});\n\n // Native work cannot be cancelled. Keep admission and borrowed buffers until\n // its callback finishes, including when the caller requests interruption.\n return yield* Effect.callback<Uint8Array, CryptoUnavailable>((resume) => {\n const registration = Result.try({\n try: () =>\n crypto.scrypt(\n input.password,\n input.salt,\n input.length,\n {\n N: input.cost,\n r: input.blockSize,\n p: input.parallelism,\n maxmem: input.maximumMemoryBytes,\n },\n // Bun supplies undefined on success; Node supplies null.\n (error, key) =>\n resume(error ? Effect.fail(CryptoUnavailable.make({})) : Effect.succeed(key)),\n ),\n catch: () => CryptoUnavailable.make({}),\n });\n\n if (Result.isFailure(registration)) resume(Effect.fail(registration.failure));\n }).pipe(Effect.uninterruptible);\n});\n\nexport const layer = Layer.succeed(ScryptBackend, { derive });\n"],"mappings":";;;;;AAQA,MAAM,SAAS,OAAO,WAAW,WAAW,OAAyB;CACnE,IAAI,OAAO,OAAO,WAAW,YAAY,OAAO,OAAO,qBAAqB,KAAK,CAAC,CAAC;CAInF,OAAO,OAAO,OAAO,UAAyC,WAAW;EACvE,MAAM,eAAe,OAAO,IAAI;GAC9B,WACE,OAAO,OACL,MAAM,UACN,MAAM,MACN,MAAM,QACN;IACE,GAAG,MAAM;IACT,GAAG,MAAM;IACT,GAAG,MAAM;IACT,QAAQ,MAAM;GAChB,IAEC,OAAO,QACN,OAAO,QAAQ,OAAO,KAAK,kBAAkB,KAAK,CAAC,CAAC,CAAC,IAAI,OAAO,QAAQ,GAAG,CAAC,CAChF;GACF,aAAa,kBAAkB,KAAK,CAAC,CAAC;EACxC,CAAC;EAED,IAAI,OAAO,UAAU,YAAY,GAAG,OAAO,OAAO,KAAK,aAAa,OAAO,CAAC;CAC9E,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe;AAChC,CAAC;AAED,MAAa,QAAQ,MAAM,QAAQ,eAAe,EAAE,OAAO,CAAC"}
@@ -1,5 +1,5 @@
1
- import { InvalidInput } from "../Errors.mjs";
2
- import { PrivateKeyInput, PrivateKeyParameters, PublicKeyInput, PublicKeyParameters, SignInput, Signature, VerifyInput } from "../Signature.mjs";
1
+ import { CryptoUnavailable, InvalidInput } from "../Errors.mjs";
2
+ import { GenerateKeyPairInput, PrivateKeyInput, PrivateKeyParameters, PublicKeyInput, PublicKeyParameters, SignInput, Signature, VerifyInput } from "../Signature.mjs";
3
3
  import { copy, decode, importError, nativeError, withSecret } from "./common.mjs";
4
4
  import { makeScopedKey } from "./scoped-key.mjs";
5
5
  import { Effect, Redacted, Schema } from "effect";
@@ -7,6 +7,26 @@ import { Base64Url } from "effect/encoding";
7
7
  //#region src/internal/signature.ts
8
8
  const derBytes = Schema.Uint8Array.check(Schema.isMinLength(1), Schema.isMaxLength(16384));
9
9
  const RsaAlgorithm = Schema.Struct({ modulusLength: Schema.Int.check(Schema.isGreaterThanOrEqualTo(2048)) });
10
+ const component = Schema.Uint8ArrayFromBase64Url;
11
+ const GeneratedEc = Schema.Struct({
12
+ x: component,
13
+ y: component,
14
+ d: component
15
+ });
16
+ const GeneratedEd = Schema.Struct({
17
+ x: component,
18
+ d: component
19
+ });
20
+ const GeneratedRsa = Schema.Struct({
21
+ n: component,
22
+ e: component,
23
+ d: component,
24
+ p: component,
25
+ q: component,
26
+ dp: component,
27
+ dq: component,
28
+ qi: component
29
+ });
10
30
  const importAlgorithm = (algorithm) => {
11
31
  switch (algorithm) {
12
32
  case "ECDSA-P256-SHA256": return {
@@ -120,6 +140,69 @@ const makeSignature = (subtle) => {
120
140
  });
121
141
  }) };
122
142
  }),
143
+ generateKeyPair: Effect.fnUntraced(function* (input) {
144
+ const value = yield* decode(GenerateKeyPairInput, input, "parameters");
145
+ const pair = yield* Effect.tryPromise({
146
+ try: () => {
147
+ switch (value.algorithm) {
148
+ case "ECDSA-P256-SHA256": return subtle.generateKey({
149
+ name: "ECDSA",
150
+ namedCurve: "P-256"
151
+ }, true, ["sign", "verify"]);
152
+ case "Ed25519": return subtle.generateKey("Ed25519", true, ["sign", "verify"]);
153
+ case "RSASSA-PKCS1-v1_5-SHA256":
154
+ case "RSA-PSS-SHA256": return subtle.generateKey({
155
+ name: value.algorithm === "RSA-PSS-SHA256" ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
156
+ hash: "SHA-256",
157
+ modulusLength: value.modulusLength ?? 2048,
158
+ publicExponent: new Uint8Array([
159
+ 1,
160
+ 0,
161
+ 1
162
+ ])
163
+ }, true, ["sign", "verify"]);
164
+ }
165
+ },
166
+ catch: nativeError
167
+ });
168
+ const jwk = yield* Effect.tryPromise({
169
+ try: () => subtle.exportKey("jwk", pair.privateKey),
170
+ catch: nativeError
171
+ });
172
+ const parameters = yield* Effect.gen(function* () {
173
+ switch (value.algorithm) {
174
+ case "ECDSA-P256-SHA256": return {
175
+ algorithm: value.algorithm,
176
+ ...yield* Schema.decodeUnknownEffect(GeneratedEc)(jwk, { reportInput: false })
177
+ };
178
+ case "Ed25519": return {
179
+ algorithm: value.algorithm,
180
+ ...yield* Schema.decodeUnknownEffect(GeneratedEd)(jwk, { reportInput: false })
181
+ };
182
+ case "RSASSA-PKCS1-v1_5-SHA256":
183
+ case "RSA-PSS-SHA256": return {
184
+ algorithm: value.algorithm,
185
+ ...yield* Schema.decodeUnknownEffect(GeneratedRsa)(jwk, { reportInput: false })
186
+ };
187
+ }
188
+ }).pipe(Effect.mapError(() => CryptoUnavailable.make({})));
189
+ yield* decode(PrivateKeyParameters, parameters, "key");
190
+ return {
191
+ publicKey: "n" in parameters ? {
192
+ algorithm: parameters.algorithm,
193
+ n: parameters.n.slice(),
194
+ e: parameters.e.slice()
195
+ } : "y" in parameters ? {
196
+ algorithm: parameters.algorithm,
197
+ x: parameters.x.slice(),
198
+ y: parameters.y.slice()
199
+ } : {
200
+ algorithm: "Ed25519",
201
+ x: parameters.x.slice()
202
+ },
203
+ privateKey: Redacted.make(parameters)
204
+ };
205
+ }, Effect.uninterruptible),
123
206
  encodePublicKey: Effect.fnUntraced(function* (input) {
124
207
  const parameters = yield* decode(PublicKeyParameters, input, "key");
125
208
  const key = yield* importComponents(parameters, "verify");
@@ -1 +1 @@
1
- {"version":3,"file":"signature.mjs","names":[],"sources":["../../src/internal/signature.ts"],"sourcesContent":["import { Effect, Redacted, Schema } from \"effect\";\nimport { Base64Url } from \"effect/encoding\";\n\nimport { InvalidInput } from \"../Errors\";\nimport {\n type Algorithm,\n type PrivateKey,\n PrivateKeyInput,\n PrivateKeyParameters,\n type PublicKey,\n PublicKeyInput,\n PublicKeyParameters,\n SignInput,\n Signature,\n VerifyInput,\n} from \"../Signature\";\nimport { copy, decode, importError, nativeError, withSecret } from \"./common\";\nimport { makeScopedKey } from \"./scoped-key\";\n\nconst derBytes = Schema.Uint8Array.check(Schema.isMinLength(1), Schema.isMaxLength(16384));\n\nconst RsaAlgorithm = Schema.Struct({\n modulusLength: Schema.Int.check(Schema.isGreaterThanOrEqualTo(2048)),\n});\n\nconst importAlgorithm = (algorithm: Algorithm) => {\n switch (algorithm) {\n case \"ECDSA-P256-SHA256\":\n return { name: \"ECDSA\", namedCurve: \"P-256\" };\n case \"RSA-PSS-SHA256\":\n return { name: \"RSA-PSS\", hash: \"SHA-256\" };\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n return { name: \"RSASSA-PKCS1-v1_5\", hash: \"SHA-256\" };\n case \"Ed25519\":\n return { name: \"Ed25519\" };\n }\n};\n\nconst operationAlgorithm = (algorithm: Algorithm) => {\n switch (algorithm) {\n case \"ECDSA-P256-SHA256\":\n return { name: \"ECDSA\", hash: \"SHA-256\" };\n case \"RSA-PSS-SHA256\":\n return { name: \"RSA-PSS\", saltLength: 32 };\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n return { name: \"RSASSA-PKCS1-v1_5\" };\n case \"Ed25519\":\n return { name: \"Ed25519\" };\n }\n};\n\nexport const makeSignature = (subtle: SubtleCrypto): Signature[\"Service\"] => {\n // JOSE owns JWK metadata and policy. The adapter translates validated raw\n // components through its platform key parser.\n const importComponents = Effect.fnUntraced(function* (\n parameters: PublicKeyParameters | PrivateKeyParameters,\n usage: \"sign\" | \"verify\",\n ) {\n let jwk: JsonWebKey;\n\n switch (parameters.algorithm) {\n case \"ECDSA-P256-SHA256\":\n jwk = {\n kty: \"EC\",\n crv: \"P-256\",\n x: Base64Url.encode(parameters.x),\n y: Base64Url.encode(parameters.y),\n };\n break;\n case \"Ed25519\":\n jwk = { kty: \"OKP\", crv: \"Ed25519\", x: Base64Url.encode(parameters.x) };\n break;\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n case \"RSA-PSS-SHA256\":\n jwk = { kty: \"RSA\", n: Base64Url.encode(parameters.n), e: Base64Url.encode(parameters.e) };\n if (\"p\" in parameters) {\n jwk.p = Base64Url.encode(parameters.p);\n jwk.q = Base64Url.encode(parameters.q);\n jwk.dp = Base64Url.encode(parameters.dp);\n jwk.dq = Base64Url.encode(parameters.dq);\n jwk.qi = Base64Url.encode(parameters.qi);\n }\n }\n if (\"d\" in parameters) jwk.d = Base64Url.encode(parameters.d);\n\n const key = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"jwk\", jwk, importAlgorithm(parameters.algorithm), true, [usage]),\n catch: importError,\n });\n\n if (\n parameters.algorithm === \"RSA-PSS-SHA256\" ||\n parameters.algorithm === \"RSASSA-PKCS1-v1_5-SHA256\"\n ) {\n yield* Schema.decodeUnknownEffect(RsaAlgorithm)(key.algorithm).pipe(\n Effect.mapError(() => InvalidInput.make({ reason: \"key\" })),\n );\n }\n\n return key;\n });\n\n const importKey = Effect.fnUntraced(function* (\n algorithm: Algorithm,\n format: \"pkcs8\" | \"spki\",\n material: Uint8Array<ArrayBuffer>,\n ) {\n yield* decode(derBytes, material, \"key\");\n\n const key = yield* Effect.tryPromise({\n try: () =>\n subtle.importKey(format, material, importAlgorithm(algorithm), false, [\n format === \"pkcs8\" ? \"sign\" : \"verify\",\n ]),\n catch: importError,\n });\n\n if (algorithm === \"RSA-PSS-SHA256\" || algorithm === \"RSASSA-PKCS1-v1_5-SHA256\") {\n // The platform parsed this DER key. Validate its actual modulus, not caller metadata.\n yield* Schema.decodeUnknownEffect(RsaAlgorithm)(key.algorithm).pipe(\n Effect.mapError(() => InvalidInput.make({ reason: \"key\" })),\n );\n }\n\n return key;\n });\n\n return Signature.of({\n importPrivateKey: Effect.fnUntraced(function* (input) {\n const value = yield* decode(PrivateKeyInput, input, \"key\");\n const algorithm = value.algorithm;\n\n const use = yield* makeScopedKey(\n withSecret(value.privateKey, (material) => importKey(algorithm, \"pkcs8\", material)),\n );\n\n return {\n sign: Effect.fnUntraced(function* (input) {\n const data = yield* decode(Schema.Uint8Array, input, \"data\").pipe(Effect.flatMap(copy));\n\n const result = yield* use((key) =>\n Effect.tryPromise({\n try: () => subtle.sign(operationAlgorithm(algorithm), key, data),\n catch: nativeError,\n }),\n );\n\n return new Uint8Array(result);\n }),\n } satisfies PrivateKey;\n }),\n importPublicKey: Effect.fnUntraced(function* (input) {\n const value = yield* decode(PublicKeyInput, input, \"key\");\n const algorithm = value.algorithm;\n const material = yield* copy(value.publicKey);\n const use = yield* makeScopedKey(importKey(algorithm, \"spki\", material));\n\n return {\n verify: Effect.fnUntraced(function* (input, signature) {\n const data = yield* decode(Schema.Uint8Array, input, \"data\").pipe(Effect.flatMap(copy));\n\n const tag = yield* decode(Schema.Uint8Array, signature, \"data\").pipe(\n Effect.flatMap(copy),\n );\n\n return yield* use((key) => {\n if ((algorithm === \"ECDSA-P256-SHA256\" || algorithm === \"Ed25519\") && tag.length !== 64)\n return Effect.succeed(false);\n\n return Effect.tryPromise({\n try: () => subtle.verify(operationAlgorithm(algorithm), key, tag, data),\n catch: nativeError,\n });\n });\n }),\n } satisfies PublicKey;\n }),\n encodePublicKey: Effect.fnUntraced(function* (input) {\n const parameters = yield* decode(PublicKeyParameters, input, \"key\");\n const key = yield* importComponents(parameters, \"verify\");\n\n const encoded = yield* Effect.tryPromise({\n try: () => subtle.exportKey(\"spki\", key),\n catch: nativeError,\n });\n\n return new Uint8Array(encoded);\n }),\n encodePrivateKey: Effect.fnUntraced(function* (input) {\n const wrapped = yield* decode(\n Schema.Redacted(PrivateKeyParameters, { disallowJsonEncode: true }),\n input,\n \"key\",\n );\n\n const parameters = Redacted.value(wrapped);\n const key = yield* importComponents(parameters, \"sign\");\n\n const encoded = yield* Effect.tryPromise({\n try: () => subtle.exportKey(\"pkcs8\", key),\n catch: nativeError,\n });\n\n return Redacted.make(new Uint8Array(encoded));\n }),\n sign: Effect.fnUntraced(function* (input) {\n const value = yield* decode(SignInput, input, \"data\");\n const data = yield* copy(value.data);\n\n return yield* withSecret(value.privateKey, (material) =>\n Effect.gen(function* () {\n const key = yield* importKey(value.algorithm, \"pkcs8\", material);\n\n const result = yield* Effect.tryPromise({\n try: () => subtle.sign(operationAlgorithm(value.algorithm), key, data),\n catch: nativeError,\n });\n\n return new Uint8Array(result);\n }).pipe(Effect.uninterruptible),\n );\n }),\n verify: Effect.fnUntraced(function* (input) {\n const value = yield* decode(VerifyInput, input, \"data\");\n const material = yield* copy(value.publicKey);\n const data = yield* copy(value.data);\n const signature = yield* copy(value.signature);\n const key = yield* importKey(value.algorithm, \"spki\", material);\n\n if (\n (value.algorithm === \"ECDSA-P256-SHA256\" || value.algorithm === \"Ed25519\") &&\n signature.length !== 64\n )\n return false;\n\n return yield* Effect.tryPromise({\n try: () => subtle.verify(operationAlgorithm(value.algorithm), key, signature, data),\n catch: nativeError,\n });\n }),\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"signature.mjs","names":[],"sources":["../../src/internal/signature.ts"],"sourcesContent":["import { Effect, Redacted, Schema } from \"effect\";\nimport { Base64Url } from \"effect/encoding\";\n\nimport { CryptoUnavailable, InvalidInput } from \"../Errors\";\nimport {\n type Algorithm,\n type PrivateKey,\n PrivateKeyInput,\n GenerateKeyPairInput,\n PrivateKeyParameters,\n type PublicKey,\n PublicKeyInput,\n PublicKeyParameters,\n SignInput,\n Signature,\n VerifyInput,\n} from \"../Signature\";\nimport { copy, decode, importError, nativeError, withSecret } from \"./common\";\nimport { makeScopedKey } from \"./scoped-key\";\n\nconst derBytes = Schema.Uint8Array.check(Schema.isMinLength(1), Schema.isMaxLength(16384));\n\nconst RsaAlgorithm = Schema.Struct({\n modulusLength: Schema.Int.check(Schema.isGreaterThanOrEqualTo(2048)),\n});\n\nconst component = Schema.Uint8ArrayFromBase64Url;\nconst GeneratedEc = Schema.Struct({ x: component, y: component, d: component });\nconst GeneratedEd = Schema.Struct({ x: component, d: component });\n\nconst GeneratedRsa = Schema.Struct({\n n: component,\n e: component,\n d: component,\n p: component,\n q: component,\n dp: component,\n dq: component,\n qi: component,\n});\n\nconst importAlgorithm = (algorithm: Algorithm) => {\n switch (algorithm) {\n case \"ECDSA-P256-SHA256\":\n return { name: \"ECDSA\", namedCurve: \"P-256\" };\n case \"RSA-PSS-SHA256\":\n return { name: \"RSA-PSS\", hash: \"SHA-256\" };\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n return { name: \"RSASSA-PKCS1-v1_5\", hash: \"SHA-256\" };\n case \"Ed25519\":\n return { name: \"Ed25519\" };\n }\n};\n\nconst operationAlgorithm = (algorithm: Algorithm) => {\n switch (algorithm) {\n case \"ECDSA-P256-SHA256\":\n return { name: \"ECDSA\", hash: \"SHA-256\" };\n case \"RSA-PSS-SHA256\":\n return { name: \"RSA-PSS\", saltLength: 32 };\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n return { name: \"RSASSA-PKCS1-v1_5\" };\n case \"Ed25519\":\n return { name: \"Ed25519\" };\n }\n};\n\nexport const makeSignature = (subtle: SubtleCrypto): Signature[\"Service\"] => {\n // JOSE owns JWK metadata and policy. The adapter translates validated raw\n // components through its platform key parser.\n const importComponents = Effect.fnUntraced(function* (\n parameters: PublicKeyParameters | PrivateKeyParameters,\n usage: \"sign\" | \"verify\",\n ) {\n let jwk: JsonWebKey;\n\n switch (parameters.algorithm) {\n case \"ECDSA-P256-SHA256\":\n jwk = {\n kty: \"EC\",\n crv: \"P-256\",\n x: Base64Url.encode(parameters.x),\n y: Base64Url.encode(parameters.y),\n };\n break;\n case \"Ed25519\":\n jwk = { kty: \"OKP\", crv: \"Ed25519\", x: Base64Url.encode(parameters.x) };\n break;\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n case \"RSA-PSS-SHA256\":\n jwk = { kty: \"RSA\", n: Base64Url.encode(parameters.n), e: Base64Url.encode(parameters.e) };\n if (\"p\" in parameters) {\n jwk.p = Base64Url.encode(parameters.p);\n jwk.q = Base64Url.encode(parameters.q);\n jwk.dp = Base64Url.encode(parameters.dp);\n jwk.dq = Base64Url.encode(parameters.dq);\n jwk.qi = Base64Url.encode(parameters.qi);\n }\n }\n if (\"d\" in parameters) jwk.d = Base64Url.encode(parameters.d);\n\n const key = yield* Effect.tryPromise({\n try: () => subtle.importKey(\"jwk\", jwk, importAlgorithm(parameters.algorithm), true, [usage]),\n catch: importError,\n });\n\n if (\n parameters.algorithm === \"RSA-PSS-SHA256\" ||\n parameters.algorithm === \"RSASSA-PKCS1-v1_5-SHA256\"\n ) {\n yield* Schema.decodeUnknownEffect(RsaAlgorithm)(key.algorithm).pipe(\n Effect.mapError(() => InvalidInput.make({ reason: \"key\" })),\n );\n }\n\n return key;\n });\n\n const importKey = Effect.fnUntraced(function* (\n algorithm: Algorithm,\n format: \"pkcs8\" | \"spki\",\n material: Uint8Array<ArrayBuffer>,\n ) {\n yield* decode(derBytes, material, \"key\");\n\n const key = yield* Effect.tryPromise({\n try: () =>\n subtle.importKey(format, material, importAlgorithm(algorithm), false, [\n format === \"pkcs8\" ? \"sign\" : \"verify\",\n ]),\n catch: importError,\n });\n\n if (algorithm === \"RSA-PSS-SHA256\" || algorithm === \"RSASSA-PKCS1-v1_5-SHA256\") {\n // The platform parsed this DER key. Validate its actual modulus, not caller metadata.\n yield* Schema.decodeUnknownEffect(RsaAlgorithm)(key.algorithm).pipe(\n Effect.mapError(() => InvalidInput.make({ reason: \"key\" })),\n );\n }\n\n return key;\n });\n\n return Signature.of({\n importPrivateKey: Effect.fnUntraced(function* (input) {\n const value = yield* decode(PrivateKeyInput, input, \"key\");\n const algorithm = value.algorithm;\n\n const use = yield* makeScopedKey(\n withSecret(value.privateKey, (material) => importKey(algorithm, \"pkcs8\", material)),\n );\n\n return {\n sign: Effect.fnUntraced(function* (input) {\n const data = yield* decode(Schema.Uint8Array, input, \"data\").pipe(Effect.flatMap(copy));\n\n const result = yield* use((key) =>\n Effect.tryPromise({\n try: () => subtle.sign(operationAlgorithm(algorithm), key, data),\n catch: nativeError,\n }),\n );\n\n return new Uint8Array(result);\n }),\n } satisfies PrivateKey;\n }),\n importPublicKey: Effect.fnUntraced(function* (input) {\n const value = yield* decode(PublicKeyInput, input, \"key\");\n const algorithm = value.algorithm;\n const material = yield* copy(value.publicKey);\n const use = yield* makeScopedKey(importKey(algorithm, \"spki\", material));\n\n return {\n verify: Effect.fnUntraced(function* (input, signature) {\n const data = yield* decode(Schema.Uint8Array, input, \"data\").pipe(Effect.flatMap(copy));\n\n const tag = yield* decode(Schema.Uint8Array, signature, \"data\").pipe(\n Effect.flatMap(copy),\n );\n\n return yield* use((key) => {\n if ((algorithm === \"ECDSA-P256-SHA256\" || algorithm === \"Ed25519\") && tag.length !== 64)\n return Effect.succeed(false);\n\n return Effect.tryPromise({\n try: () => subtle.verify(operationAlgorithm(algorithm), key, tag, data),\n catch: nativeError,\n });\n });\n }),\n } satisfies PublicKey;\n }),\n generateKeyPair: Effect.fnUntraced(function* (input) {\n const value = yield* decode(GenerateKeyPairInput, input, \"parameters\");\n\n const pair = yield* Effect.tryPromise({\n try: () => {\n switch (value.algorithm) {\n case \"ECDSA-P256-SHA256\":\n return subtle.generateKey({ name: \"ECDSA\", namedCurve: \"P-256\" }, true, [\n \"sign\",\n \"verify\",\n ]);\n case \"Ed25519\":\n return subtle.generateKey(\"Ed25519\", true, [\"sign\", \"verify\"]);\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n case \"RSA-PSS-SHA256\":\n return subtle.generateKey(\n {\n name: value.algorithm === \"RSA-PSS-SHA256\" ? \"RSA-PSS\" : \"RSASSA-PKCS1-v1_5\",\n hash: \"SHA-256\",\n modulusLength: value.modulusLength ?? 2048,\n publicExponent: new Uint8Array([1, 0, 1]),\n },\n true,\n [\"sign\", \"verify\"],\n );\n }\n },\n catch: nativeError,\n });\n\n const jwk = yield* Effect.tryPromise({\n try: () => subtle.exportKey(\"jwk\", pair.privateKey),\n catch: nativeError,\n });\n\n // JsonWebKey does not guarantee algorithm-specific fields. Decode only at\n // this native boundary; callers receive typed components, never loose JWKs.\n const parameters: PrivateKeyParameters = yield* Effect.gen(function* () {\n switch (value.algorithm) {\n case \"ECDSA-P256-SHA256\":\n return {\n algorithm: value.algorithm,\n ...(yield* Schema.decodeUnknownEffect(GeneratedEc)(jwk, { reportInput: false })),\n };\n case \"Ed25519\":\n return {\n algorithm: value.algorithm,\n ...(yield* Schema.decodeUnknownEffect(GeneratedEd)(jwk, { reportInput: false })),\n };\n case \"RSASSA-PKCS1-v1_5-SHA256\":\n case \"RSA-PSS-SHA256\":\n return {\n algorithm: value.algorithm,\n ...(yield* Schema.decodeUnknownEffect(GeneratedRsa)(jwk, { reportInput: false })),\n };\n }\n }).pipe(Effect.mapError(() => CryptoUnavailable.make({})));\n\n yield* decode(PrivateKeyParameters, parameters, \"key\");\n\n const publicKey: PublicKeyParameters =\n \"n\" in parameters\n ? { algorithm: parameters.algorithm, n: parameters.n.slice(), e: parameters.e.slice() }\n : \"y\" in parameters\n ? { algorithm: parameters.algorithm, x: parameters.x.slice(), y: parameters.y.slice() }\n : { algorithm: \"Ed25519\", x: parameters.x.slice() };\n\n return { publicKey, privateKey: Redacted.make(parameters) };\n }, Effect.uninterruptible),\n encodePublicKey: Effect.fnUntraced(function* (input) {\n const parameters = yield* decode(PublicKeyParameters, input, \"key\");\n const key = yield* importComponents(parameters, \"verify\");\n\n const encoded = yield* Effect.tryPromise({\n try: () => subtle.exportKey(\"spki\", key),\n catch: nativeError,\n });\n\n return new Uint8Array(encoded);\n }),\n encodePrivateKey: Effect.fnUntraced(function* (input) {\n const wrapped = yield* decode(\n Schema.Redacted(PrivateKeyParameters, { disallowJsonEncode: true }),\n input,\n \"key\",\n );\n\n const parameters = Redacted.value(wrapped);\n const key = yield* importComponents(parameters, \"sign\");\n\n const encoded = yield* Effect.tryPromise({\n try: () => subtle.exportKey(\"pkcs8\", key),\n catch: nativeError,\n });\n\n return Redacted.make(new Uint8Array(encoded));\n }),\n sign: Effect.fnUntraced(function* (input) {\n const value = yield* decode(SignInput, input, \"data\");\n const data = yield* copy(value.data);\n\n return yield* withSecret(value.privateKey, (material) =>\n Effect.gen(function* () {\n const key = yield* importKey(value.algorithm, \"pkcs8\", material);\n\n const result = yield* Effect.tryPromise({\n try: () => subtle.sign(operationAlgorithm(value.algorithm), key, data),\n catch: nativeError,\n });\n\n return new Uint8Array(result);\n }).pipe(Effect.uninterruptible),\n );\n }),\n verify: Effect.fnUntraced(function* (input) {\n const value = yield* decode(VerifyInput, input, \"data\");\n const material = yield* copy(value.publicKey);\n const data = yield* copy(value.data);\n const signature = yield* copy(value.signature);\n const key = yield* importKey(value.algorithm, \"spki\", material);\n\n if (\n (value.algorithm === \"ECDSA-P256-SHA256\" || value.algorithm === \"Ed25519\") &&\n signature.length !== 64\n )\n return false;\n\n return yield* Effect.tryPromise({\n try: () => subtle.verify(operationAlgorithm(value.algorithm), key, signature, data),\n catch: nativeError,\n });\n }),\n });\n};\n"],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { InvalidInput } from "./Errors.mjs";
2
+ import { Aead } from "./Aead.mjs";
3
+ import { Hmac } from "./Hmac.mjs";
4
+ import { Kdf, Limits } from "./Kdf.mjs";
5
+ import { KdfAdmission } from "./KdfAdmission.mjs";
6
+ import { Signature } from "./Signature.mjs";
7
+ import { Layer } from "effect";
8
+ //#region src/platform-workerd.d.ts
9
+ /** Workers WebCrypto, Wasm Argon2id and native scrypt.
10
+ * Bundle with Wrangler and enable Node.js compatibility.
11
+ */
12
+ export declare const layer: (subtle: SubtleCrypto, limits?: Partial<Limits>) => Layer.Layer<Aead | Hmac | Kdf | Signature, InvalidInput, KdfAdmission>;
13
+ //#endregion
14
+ //# sourceMappingURL=platform-workerd.d.mts.map
@@ -0,0 +1,18 @@
1
+ import { makeLayer } from "./internal/layer.mjs";
2
+ import { layer as layer$1 } from "./internal/scrypt.mjs";
3
+ import { xchacha } from "./internal/xchacha.mjs";
4
+ import { makeArgon2 } from "./internal/argon2-wasm.mjs";
5
+ import { Layer } from "effect";
6
+ import module from "./internal/argon2.wasm";
7
+ //#region src/platform-workerd.ts
8
+ /** Workers WebCrypto, Wasm Argon2id and native scrypt.
9
+ * Bundle with Wrangler and enable Node.js compatibility.
10
+ */
11
+ const layer = (subtle, limits = {}) => makeLayer(subtle, limits, {
12
+ argon2: makeArgon2(module),
13
+ xchacha
14
+ }).pipe(Layer.provide(layer$1));
15
+ //#endregion
16
+ export { layer };
17
+
18
+ //# sourceMappingURL=platform-workerd.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform-workerd.mjs","names":["Scrypt.layer"],"sources":["../src/platform-workerd.ts"],"sourcesContent":["import { Layer } from \"effect\";\n\nimport { makeArgon2 } from \"./internal/argon2-wasm\";\nimport module from \"./internal/argon2.wasm\";\nimport { makeLayer } from \"./internal/layer\";\nimport * as Scrypt from \"./internal/scrypt\";\nimport { xchacha } from \"./internal/xchacha\";\nimport type { Limits } from \"./Kdf\";\n\n/** Workers WebCrypto, Wasm Argon2id and native scrypt.\n * Bundle with Wrangler and enable Node.js compatibility.\n */\nexport const layer = (subtle: SubtleCrypto, limits: Partial<Limits> = {}) =>\n makeLayer(subtle, limits, { argon2: makeArgon2(module), xchacha }).pipe(\n Layer.provide(Scrypt.layer),\n );\n"],"mappings":";;;;;;;;;;AAYA,MAAa,SAAS,QAAsB,SAA0B,CAAC,MACrE,UAAU,QAAQ,QAAQ;CAAE,QAAQ,WAAW,MAAM;CAAG;AAAQ,CAAC,CAAC,CAAC,KACjE,MAAM,QAAQA,OAAY,CAC5B"}
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@yielded/crypto","version":"0.1.0-beta.29","devDependencies":{"@effect/vitest":"4.0.0","@types/node":"26.1.2","effect":"4.0.0","typescript":"7.0.2","vite-plus":"0.3.3"},"peerDependencies":{"effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./Aead":{"types":"./dist/Aead.d.mts","default":"./dist/Aead.mjs"},"./Errors":{"types":"./dist/Errors.d.mts","default":"./dist/Errors.mjs"},"./Hmac":{"types":"./dist/Hmac.d.mts","default":"./dist/Hmac.mjs"},"./Kdf":{"types":"./dist/Kdf.d.mts","default":"./dist/Kdf.mjs"},"./KdfAdmission":{"types":"./dist/KdfAdmission.d.mts","default":"./dist/KdfAdmission.mjs"},"./Signature":{"types":"./dist/Signature.d.mts","default":"./dist/Signature.mjs"},"./WebCrypto":{"types":"./dist/WebCrypto.d.mts","default":"./dist/WebCrypto.mjs"},"./platform-node":{"types":"./dist/platform-node.d.mts","default":"./dist/platform-node.mjs"},"./platform-bun":{"types":"./dist/platform-bun.d.mts","default":"./dist/platform-bun.mjs"},"./Portable":{"types":"./dist/Portable.d.mts","default":"./dist/Portable.mjs"}},"description":"Effect cryptography services with explicit native and portable backends.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/crypto"},"files":["dist","src","THIRD_PARTY_NOTICES.md"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","check":"tsc --noEmit -p tsconfig.json","test":"vp test"}}
1
+ {"name":"@yielded/crypto","version":"0.1.0-beta.31","devDependencies":{"@effect/vitest":"4.0.0","@types/node":"26.1.2","effect":"4.0.0","typescript":"7.0.2","vite":"npm:@voidzero-dev/vite-plus-core@1.1.0","vite-plus":"1.1.0","vitest":"5.0.3"},"peerDependencies":{"effect":"^4.0.0"},"exports":{".":{"types":"./dist/index.d.mts","default":"./dist/index.mjs"},"./Aead":{"types":"./dist/Aead.d.mts","default":"./dist/Aead.mjs"},"./Errors":{"types":"./dist/Errors.d.mts","default":"./dist/Errors.mjs"},"./Hmac":{"types":"./dist/Hmac.d.mts","default":"./dist/Hmac.mjs"},"./Kdf":{"types":"./dist/Kdf.d.mts","default":"./dist/Kdf.mjs"},"./KdfAdmission":{"types":"./dist/KdfAdmission.d.mts","default":"./dist/KdfAdmission.mjs"},"./Signature":{"types":"./dist/Signature.d.mts","default":"./dist/Signature.mjs"},"./WebCrypto":{"types":"./dist/WebCrypto.d.mts","default":"./dist/WebCrypto.mjs"},"./platform-node":{"types":"./dist/platform-node.d.mts","default":"./dist/platform-node.mjs"},"./platform-bun":{"types":"./dist/platform-bun.d.mts","default":"./dist/platform-bun.mjs"},"./platform-workerd":{"types":"./dist/platform-workerd.d.mts","default":"./dist/platform-workerd.mjs"},"./Portable":{"types":"./dist/Portable.d.mts","default":"./dist/Portable.mjs"}},"description":"Effect cryptography services with explicit native and portable backends.","homepage":"https://yielded.dev/auth/","bugs":{"url":"https://github.com/yielded-dev/auth/issues"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/yielded-dev/auth.git","directory":"packages/crypto"},"files":["dist","src","THIRD_PARTY_NOTICES.md"],"type":"module","sideEffects":[],"publishConfig":{"access":"public"},"scripts":{"build":"vp pack","build:wasm":"clang --target=wasm32 -O3 -msimd128 -ffreestanding -fno-builtin -nostdlib -Wl,--no-entry -Wl,--import-memory -Wl,--export=argon2_block -Wl,--export=__heap_base -Wl,--strip-all src/internal/argon2-block.c -o src/internal/argon2.wasm","check":"tsc --noEmit -p tsconfig.json","test":"vp test"}}
package/src/Kdf.ts CHANGED
@@ -22,6 +22,17 @@ export const Argon2idInput = Schema.Struct({
22
22
 
23
23
  export type Argon2idInput = typeof Argon2idInput.Type;
24
24
 
25
+ export const ScryptInput = Schema.Struct({
26
+ password: secret,
27
+ salt: bytes,
28
+ cost: Schema.Int.check(Schema.isBetween({ minimum: 2, maximum: 0x80000000 })),
29
+ blockSize: uint32,
30
+ parallelism: uint32,
31
+ length: Schema.Int.check(Schema.isBetween({ minimum: 1, maximum: 0x7fffffff })),
32
+ });
33
+
34
+ export type ScryptInput = typeof ScryptInput.Type;
35
+
25
36
  export const Pbkdf2Input = Schema.Struct({
26
37
  password: secret,
27
38
  salt: bytes,
@@ -42,7 +53,10 @@ export const HkdfInput = Schema.Struct({
42
53
 
43
54
  export type HkdfInput = typeof HkdfInput.Type;
44
55
 
45
- /** Resource ceilings, not a password-strength policy. Limits apply per permit. */
56
+ /** Resource ceilings, not a password-strength policy. Limits apply per permit.
57
+ * Scrypt bounds its allocation by maximumMemoryKiB and N*r*p/8 by
58
+ * maximumMemoryPasses. maximumPasses/maximumParallelism apply to Argon2id.
59
+ */
46
60
  export const Limits = Schema.Struct({
47
61
  maximumMemoryKiB: positive,
48
62
  maximumPasses: positive,
@@ -67,7 +81,8 @@ export const defaultLimits: Limits = Object.freeze({
67
81
 
68
82
  /**
69
83
  * Byte-preserving derivation; no text normalization, PHC parsing or password policy.
70
- * Argon2id uses version 19; PBKDF2 and HKDF use SHA-256. A backend captures shared
84
+ * Argon2id uses version 19; PBKDF2 and HKDF use SHA-256. Scrypt names N/r/p as
85
+ * cost/blockSize/parallelism. A backend captures shared
71
86
  * KdfAdmission when its Layer is built and retains admission until work and cleanup
72
87
  * finish, including when a native operation cannot be cancelled.
73
88
  */
@@ -77,6 +92,9 @@ export class Kdf extends Context.Service<
77
92
  readonly argon2id: (
78
93
  input: Argon2idInput,
79
94
  ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;
95
+ readonly scrypt: (
96
+ input: ScryptInput,
97
+ ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;
80
98
  readonly pbkdf2: (
81
99
  input: Pbkdf2Input,
82
100
  ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError | KdfBusy>;
package/src/Portable.ts CHANGED
@@ -1,8 +1,11 @@
1
+ import { Layer } from "effect";
2
+
1
3
  import { argon2 } from "./internal/argon2";
2
4
  import { makeLayer } from "./internal/layer";
5
+ import { layerUnsupported } from "./internal/scrypt-backend";
3
6
  import { xchacha } from "./internal/xchacha";
4
7
  import type { Limits } from "./Kdf";
5
8
 
6
9
  /** WebCrypto with owned, portable Argon2id and XChaCha20-Poly1305 implementations. */
7
10
  export const layer = (subtle: SubtleCrypto, limits: Partial<Limits> = {}) =>
8
- makeLayer(subtle, limits, { argon2, xchacha });
11
+ makeLayer(subtle, limits, { argon2, xchacha }).pipe(Layer.provide(layerUnsupported));
package/src/Signature.ts CHANGED
@@ -50,6 +50,26 @@ export const PrivateKeyParameters = Schema.Union([
50
50
 
51
51
  export type PrivateKeyParameters = typeof PrivateKeyParameters.Type;
52
52
 
53
+ export const RsaModulusLength = Schema.Literals([2048, 3072, 4096]);
54
+
55
+ /** RSA defaults to 2048 bits and exponent 65537; curves are fixed by algorithm. */
56
+ export const GenerateKeyPairInput = Schema.Union([
57
+ Schema.Struct({ algorithm: Schema.Literals(["ECDSA-P256-SHA256", "Ed25519"]) }),
58
+ Schema.Struct({
59
+ algorithm: Schema.Literals(["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]),
60
+ modulusLength: Schema.optionalKey(RsaModulusLength),
61
+ }),
62
+ ]);
63
+
64
+ export type GenerateKeyPairInput = typeof GenerateKeyPairInput.Type;
65
+
66
+ export const KeyPairParameters = Schema.Struct({
67
+ publicKey: PublicKeyParameters,
68
+ privateKey: Schema.Redacted(PrivateKeyParameters, { disallowJsonEncode: true }),
69
+ });
70
+
71
+ export type KeyPairParameters = typeof KeyPairParameters.Type;
72
+
53
73
  export const PrivateKeyInput = Schema.Struct({
54
74
  algorithm: Algorithm,
55
75
  privateKey: Schema.Redacted(Schema.Uint8Array, { disallowJsonEncode: true }),
@@ -108,6 +128,10 @@ export class Signature extends Context.Service<
108
128
  readonly importPublicKey: (
109
129
  input: PublicKeyInput,
110
130
  ) => Effect.Effect<PublicKey, OperationError, Scope.Scope>;
131
+ /** Generate exportable components. The caller owns the returned secret bytes. */
132
+ readonly generateKeyPair: (
133
+ input: GenerateKeyPairInput,
134
+ ) => Effect.Effect<KeyPairParameters, OperationError>;
111
135
  readonly encodePublicKey: (
112
136
  input: PublicKeyParameters,
113
137
  ) => Effect.Effect<Uint8Array, OperationError>;
package/src/WebCrypto.ts CHANGED
@@ -3,11 +3,12 @@ import { Crypto, Effect, Layer, PlatformError } from "effect";
3
3
  import { Hmac } from "./Hmac";
4
4
  import { makeHmac } from "./internal/hmac";
5
5
  import { makeLayer } from "./internal/layer";
6
+ import { layerUnsupported } from "./internal/scrypt-backend";
6
7
  import type { Limits } from "./Kdf";
7
8
 
8
9
  /** Supply the host capability explicitly; no implicit global backend selection. */
9
10
  export const layer = (subtle: SubtleCrypto, limits: Partial<Limits> = {}) =>
10
- makeLayer(subtle, limits);
11
+ makeLayer(subtle, limits).pipe(Layer.provide(layerUnsupported));
11
12
 
12
13
  /** HMAC alone has no KDF admission requirement. */
13
14
  export const layerHmac = (subtle: SubtleCrypto): Layer.Layer<Hmac> =>