@yielded/crypto 0.1.0-beta.29 → 0.1.0-beta.30
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.
- package/dist/Signature.d.mts +46 -0
- package/dist/Signature.mjs +15 -1
- package/dist/Signature.mjs.map +1 -1
- package/dist/internal/signature.mjs +85 -2
- package/dist/internal/signature.mjs.map +1 -1
- package/package.json +1 -1
- package/src/Signature.ts +24 -0
- package/src/internal/signature.ts +86 -1
package/dist/Signature.d.mts
CHANGED
|
@@ -41,6 +41,50 @@ export declare const PrivateKeyParameters: Schema.Union<readonly [Schema.Struct<
|
|
|
41
41
|
readonly qi: Schema.Uint8Array;
|
|
42
42
|
}>]>;
|
|
43
43
|
export type PrivateKeyParameters = typeof PrivateKeyParameters.Type;
|
|
44
|
+
export declare const RsaModulusLength: Schema.Literals<readonly [2048, 3072, 4096]>;
|
|
45
|
+
/** RSA defaults to 2048 bits and exponent 65537; curves are fixed by algorithm. */
|
|
46
|
+
export declare const GenerateKeyPairInput: Schema.Union<readonly [Schema.Struct<{
|
|
47
|
+
readonly algorithm: Schema.Literals<readonly ["ECDSA-P256-SHA256", "Ed25519"]>;
|
|
48
|
+
}>, Schema.Struct<{
|
|
49
|
+
readonly algorithm: Schema.Literals<readonly ["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]>;
|
|
50
|
+
readonly modulusLength: Schema.optionalKey<Schema.Literals<readonly [2048, 3072, 4096]>>;
|
|
51
|
+
}>]>;
|
|
52
|
+
export type GenerateKeyPairInput = typeof GenerateKeyPairInput.Type;
|
|
53
|
+
export declare const KeyPairParameters: Schema.Struct<{
|
|
54
|
+
readonly publicKey: Schema.Union<readonly [Schema.Struct<{
|
|
55
|
+
algorithm: Schema.Literal<"ECDSA-P256-SHA256">;
|
|
56
|
+
x: Schema.Uint8Array;
|
|
57
|
+
y: Schema.Uint8Array;
|
|
58
|
+
}>, Schema.Struct<{
|
|
59
|
+
algorithm: Schema.Literal<"Ed25519">;
|
|
60
|
+
x: Schema.Uint8Array;
|
|
61
|
+
}>, Schema.Struct<{
|
|
62
|
+
algorithm: Schema.Literals<readonly ["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]>;
|
|
63
|
+
n: Schema.Uint8Array;
|
|
64
|
+
e: Schema.Uint8Array;
|
|
65
|
+
}>]>;
|
|
66
|
+
readonly privateKey: Schema.Redacted<Schema.Union<readonly [Schema.Struct<{
|
|
67
|
+
readonly algorithm: Schema.Literal<"ECDSA-P256-SHA256">;
|
|
68
|
+
readonly x: Schema.Uint8Array;
|
|
69
|
+
readonly y: Schema.Uint8Array;
|
|
70
|
+
readonly d: Schema.Uint8Array;
|
|
71
|
+
}>, Schema.Struct<{
|
|
72
|
+
readonly algorithm: Schema.Literal<"Ed25519">;
|
|
73
|
+
readonly x: Schema.Uint8Array;
|
|
74
|
+
readonly d: Schema.Uint8Array;
|
|
75
|
+
}>, Schema.Struct<{
|
|
76
|
+
readonly algorithm: Schema.Literals<readonly ["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]>;
|
|
77
|
+
readonly n: Schema.Uint8Array;
|
|
78
|
+
readonly e: Schema.Uint8Array;
|
|
79
|
+
readonly d: Schema.Uint8Array;
|
|
80
|
+
readonly p: Schema.Uint8Array;
|
|
81
|
+
readonly q: Schema.Uint8Array;
|
|
82
|
+
readonly dp: Schema.Uint8Array;
|
|
83
|
+
readonly dq: Schema.Uint8Array;
|
|
84
|
+
readonly qi: Schema.Uint8Array;
|
|
85
|
+
}>]>>;
|
|
86
|
+
}>;
|
|
87
|
+
export type KeyPairParameters = typeof KeyPairParameters.Type;
|
|
44
88
|
export declare const PrivateKeyInput: Schema.Struct<{
|
|
45
89
|
readonly algorithm: Schema.Literals<readonly ["ECDSA-P256-SHA256", "RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256", "Ed25519"]>;
|
|
46
90
|
readonly privateKey: Schema.Redacted<Schema.Uint8Array>;
|
|
@@ -77,6 +121,8 @@ declare const Signature_base: Context.ServiceClass<Signature, "@yielded/crypto/S
|
|
|
77
121
|
readonly importPrivateKey: (input: PrivateKeyInput) => Effect.Effect<PrivateKey, OperationError, Scope.Scope>;
|
|
78
122
|
/** Snapshot SPKI once; scope closure joins native work and rejects later use. */
|
|
79
123
|
readonly importPublicKey: (input: PublicKeyInput) => Effect.Effect<PublicKey, OperationError, Scope.Scope>;
|
|
124
|
+
/** Generate exportable components. The caller owns the returned secret bytes. */
|
|
125
|
+
readonly generateKeyPair: (input: GenerateKeyPairInput) => Effect.Effect<KeyPairParameters, OperationError>;
|
|
80
126
|
readonly encodePublicKey: (input: PublicKeyParameters) => Effect.Effect<Uint8Array, OperationError>;
|
|
81
127
|
readonly encodePrivateKey: (input: Redacted.Redacted<PrivateKeyParameters>) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError>;
|
|
82
128
|
readonly sign: (input: SignInput) => Effect.Effect<Uint8Array, OperationError>;
|
package/dist/Signature.mjs
CHANGED
|
@@ -50,6 +50,20 @@ const PrivateKeyParameters = Schema.Union([
|
|
|
50
50
|
qi: integer
|
|
51
51
|
})
|
|
52
52
|
]);
|
|
53
|
+
const RsaModulusLength = Schema.Literals([
|
|
54
|
+
2048,
|
|
55
|
+
3072,
|
|
56
|
+
4096
|
|
57
|
+
]);
|
|
58
|
+
/** RSA defaults to 2048 bits and exponent 65537; curves are fixed by algorithm. */
|
|
59
|
+
const GenerateKeyPairInput = Schema.Union([Schema.Struct({ algorithm: Schema.Literals(["ECDSA-P256-SHA256", "Ed25519"]) }), Schema.Struct({
|
|
60
|
+
algorithm: Schema.Literals(["RSASSA-PKCS1-v1_5-SHA256", "RSA-PSS-SHA256"]),
|
|
61
|
+
modulusLength: Schema.optionalKey(RsaModulusLength)
|
|
62
|
+
})]);
|
|
63
|
+
const KeyPairParameters = Schema.Struct({
|
|
64
|
+
publicKey: PublicKeyParameters,
|
|
65
|
+
privateKey: Schema.Redacted(PrivateKeyParameters, { disallowJsonEncode: true })
|
|
66
|
+
});
|
|
53
67
|
const PrivateKeyInput = Schema.Struct({
|
|
54
68
|
algorithm: Algorithm,
|
|
55
69
|
privateKey: Schema.Redacted(Schema.Uint8Array, { disallowJsonEncode: true })
|
|
@@ -74,6 +88,6 @@ const VerifyInput = Schema.Struct({
|
|
|
74
88
|
*/
|
|
75
89
|
var Signature = class extends Context.Service()("@yielded/crypto/Signature") {};
|
|
76
90
|
//#endregion
|
|
77
|
-
export { Algorithm, PrivateKeyInput, PrivateKeyParameters, PublicKeyInput, PublicKeyParameters, SignInput, Signature, VerifyInput };
|
|
91
|
+
export { Algorithm, GenerateKeyPairInput, KeyPairParameters, PrivateKeyInput, PrivateKeyParameters, PublicKeyInput, PublicKeyParameters, RsaModulusLength, SignInput, Signature, VerifyInput };
|
|
78
92
|
|
|
79
93
|
//# sourceMappingURL=Signature.mjs.map
|
package/dist/Signature.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Signature.mjs","names":[],"sources":["../src/Signature.ts"],"sourcesContent":["import { Context, type Effect, type Redacted, Schema, type Scope } from \"effect\";\n\nimport type { OperationError } from \"./Errors\";\n\nexport const Algorithm = Schema.Literals([\n \"ECDSA-P256-SHA256\",\n \"RSASSA-PKCS1-v1_5-SHA256\",\n \"RSA-PSS-SHA256\",\n \"Ed25519\",\n]);\n\nexport type Algorithm = typeof Algorithm.Type;\n\nconst coordinate = Schema.Uint8Array.check(Schema.isMinLength(32), Schema.isMaxLength(32));\nconst integer = Schema.Uint8Array.check(Schema.isMinLength(1), Schema.isMaxLength(1024));\nconst ec = { algorithm: Schema.Literal(\"ECDSA-P256-SHA256\"), x: coordinate, y: coordinate };\nconst ed = { algorithm: Schema.Literal(\"Ed25519\"), x: coordinate };\n\nconst rsa = {\n algorithm: Schema.Literals([\"RSASSA-PKCS1-v1_5-SHA256\", \"RSA-PSS-SHA256\"]),\n n: integer,\n e: integer,\n};\n\n/**\n * Unsigned big-endian components: 32-byte curve values and RSA components up to\n * 1024 bytes. Native import validates the actual key, including RSA's minimum.\n */\nexport const PublicKeyParameters = Schema.Union([\n Schema.Struct(ec),\n Schema.Struct(ed),\n Schema.Struct(rsa),\n]);\n\nexport type PublicKeyParameters = typeof PublicKeyParameters.Type;\n\nexport const PrivateKeyParameters = Schema.Union([\n Schema.Struct({ ...ec, d: coordinate }),\n Schema.Struct({ ...ed, d: coordinate }),\n Schema.Struct({\n ...rsa,\n d: integer,\n p: integer,\n q: integer,\n dp: integer,\n dq: integer,\n qi: integer,\n }),\n]);\n\nexport type PrivateKeyParameters = typeof PrivateKeyParameters.Type;\n\nexport const PrivateKeyInput = Schema.Struct({\n algorithm: Algorithm,\n privateKey: Schema.Redacted(Schema.Uint8Array, { disallowJsonEncode: true }),\n});\n\nexport type PrivateKeyInput = typeof PrivateKeyInput.Type;\n\nexport const PublicKeyInput = Schema.Struct({\n algorithm: Algorithm,\n publicKey: Schema.Uint8Array,\n});\n\nexport type PublicKeyInput = typeof PublicKeyInput.Type;\n\nexport const SignInput = Schema.Struct({\n ...PrivateKeyInput.fields,\n data: Schema.Uint8Array,\n});\n\nexport type SignInput = typeof SignInput.Type;\n\nexport const VerifyInput = Schema.Struct({\n ...PublicKeyInput.fields,\n data: Schema.Uint8Array,\n signature: Schema.Uint8Array,\n});\n\nexport type VerifyInput = typeof VerifyInput.Type;\n\n/** A nonextractable signing key with its algorithm fixed at import. */\nexport interface PrivateKey {\n readonly sign: (data: Uint8Array) => Effect.Effect<Uint8Array, OperationError>;\n}\n\n/** A verification key with its algorithm fixed at import. */\nexport interface PublicKey {\n readonly verify: (\n data: Uint8Array,\n signature: Uint8Array,\n ) => Effect.Effect<boolean, OperationError>;\n}\n\n/**\n * Private keys are PKCS8 DER; public keys are SPKI DER. ECDSA signatures are\n * 64-byte IEEE P1363 (r || s), not ASN.1 DER. RSA requires at least 2048 bits;\n * PSS uses a 32-byte salt. Key serialization/selection and JOSE policy stay outside.\n */\nexport class Signature extends Context.Service<\n Signature,\n {\n /** Snapshot PKCS8 once; the imported key is usable only inside its owning Scope. */\n readonly importPrivateKey: (\n input: PrivateKeyInput,\n ) => Effect.Effect<PrivateKey, OperationError, Scope.Scope>;\n /** Snapshot SPKI once; scope closure joins native work and rejects later use. */\n readonly importPublicKey: (\n input: PublicKeyInput,\n ) => Effect.Effect<PublicKey, OperationError, Scope.Scope>;\n readonly encodePublicKey: (\n input: PublicKeyParameters,\n ) => Effect.Effect<Uint8Array, OperationError>;\n readonly encodePrivateKey: (\n input: Redacted.Redacted<PrivateKeyParameters>,\n ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError>;\n readonly sign: (input: SignInput) => Effect.Effect<Uint8Array, OperationError>;\n readonly verify: (input: VerifyInput) => Effect.Effect<boolean, OperationError>;\n }\n>()(\"@yielded/crypto/Signature\") {}\n"],"mappings":";;AAIA,MAAa,YAAY,OAAO,SAAS;CACvC;CACA;CACA;CACA;AACF,CAAC;AAID,MAAM,aAAa,OAAO,WAAW,MAAM,OAAO,YAAY,EAAE,GAAG,OAAO,YAAY,EAAE,CAAC;AACzF,MAAM,UAAU,OAAO,WAAW,MAAM,OAAO,YAAY,CAAC,GAAG,OAAO,YAAY,IAAI,CAAC;AACvF,MAAM,KAAK;CAAE,WAAW,OAAO,QAAQ,mBAAmB;CAAG,GAAG;CAAY,GAAG;AAAW;AAC1F,MAAM,KAAK;CAAE,WAAW,OAAO,QAAQ,SAAS;CAAG,GAAG;AAAW;AAEjE,MAAM,MAAM;CACV,WAAW,OAAO,SAAS,CAAC,4BAA4B,gBAAgB,CAAC;CACzE,GAAG;CACH,GAAG;AACL;;;;;AAMA,MAAa,sBAAsB,OAAO,MAAM;CAC9C,OAAO,OAAO,EAAE;CAChB,OAAO,OAAO,EAAE;CAChB,OAAO,OAAO,GAAG;AACnB,CAAC;AAID,MAAa,uBAAuB,OAAO,MAAM;CAC/C,OAAO,OAAO;EAAE,GAAG;EAAI,GAAG;CAAW,CAAC;CACtC,OAAO,OAAO;EAAE,GAAG;EAAI,GAAG;CAAW,CAAC;CACtC,OAAO,OAAO;EACZ,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,CAAC;AACH,CAAC;AAID,MAAa,kBAAkB,OAAO,OAAO;CAC3C,WAAW;CACX,YAAY,OAAO,SAAS,OAAO,YAAY,EAAE,oBAAoB,KAAK,CAAC;AAC7E,CAAC;AAID,MAAa,iBAAiB,OAAO,OAAO;CAC1C,WAAW;CACX,WAAW,OAAO;AACpB,CAAC;AAID,MAAa,YAAY,OAAO,OAAO;CACrC,GAAG,gBAAgB;CACnB,MAAM,OAAO;AACf,CAAC;AAID,MAAa,cAAc,OAAO,OAAO;CACvC,GAAG,eAAe;CAClB,MAAM,OAAO;CACb,WAAW,OAAO;AACpB,CAAC;;;;;;AAsBD,IAAa,YAAb,cAA+B,QAAQ,
|
|
1
|
+
{"version":3,"file":"Signature.mjs","names":[],"sources":["../src/Signature.ts"],"sourcesContent":["import { Context, type Effect, type Redacted, Schema, type Scope } from \"effect\";\n\nimport type { OperationError } from \"./Errors\";\n\nexport const Algorithm = Schema.Literals([\n \"ECDSA-P256-SHA256\",\n \"RSASSA-PKCS1-v1_5-SHA256\",\n \"RSA-PSS-SHA256\",\n \"Ed25519\",\n]);\n\nexport type Algorithm = typeof Algorithm.Type;\n\nconst coordinate = Schema.Uint8Array.check(Schema.isMinLength(32), Schema.isMaxLength(32));\nconst integer = Schema.Uint8Array.check(Schema.isMinLength(1), Schema.isMaxLength(1024));\nconst ec = { algorithm: Schema.Literal(\"ECDSA-P256-SHA256\"), x: coordinate, y: coordinate };\nconst ed = { algorithm: Schema.Literal(\"Ed25519\"), x: coordinate };\n\nconst rsa = {\n algorithm: Schema.Literals([\"RSASSA-PKCS1-v1_5-SHA256\", \"RSA-PSS-SHA256\"]),\n n: integer,\n e: integer,\n};\n\n/**\n * Unsigned big-endian components: 32-byte curve values and RSA components up to\n * 1024 bytes. Native import validates the actual key, including RSA's minimum.\n */\nexport const PublicKeyParameters = Schema.Union([\n Schema.Struct(ec),\n Schema.Struct(ed),\n Schema.Struct(rsa),\n]);\n\nexport type PublicKeyParameters = typeof PublicKeyParameters.Type;\n\nexport const PrivateKeyParameters = Schema.Union([\n Schema.Struct({ ...ec, d: coordinate }),\n Schema.Struct({ ...ed, d: coordinate }),\n Schema.Struct({\n ...rsa,\n d: integer,\n p: integer,\n q: integer,\n dp: integer,\n dq: integer,\n qi: integer,\n }),\n]);\n\nexport type PrivateKeyParameters = typeof PrivateKeyParameters.Type;\n\nexport const RsaModulusLength = Schema.Literals([2048, 3072, 4096]);\n\n/** RSA defaults to 2048 bits and exponent 65537; curves are fixed by algorithm. */\nexport const GenerateKeyPairInput = Schema.Union([\n Schema.Struct({ algorithm: Schema.Literals([\"ECDSA-P256-SHA256\", \"Ed25519\"]) }),\n Schema.Struct({\n algorithm: Schema.Literals([\"RSASSA-PKCS1-v1_5-SHA256\", \"RSA-PSS-SHA256\"]),\n modulusLength: Schema.optionalKey(RsaModulusLength),\n }),\n]);\n\nexport type GenerateKeyPairInput = typeof GenerateKeyPairInput.Type;\n\nexport const KeyPairParameters = Schema.Struct({\n publicKey: PublicKeyParameters,\n privateKey: Schema.Redacted(PrivateKeyParameters, { disallowJsonEncode: true }),\n});\n\nexport type KeyPairParameters = typeof KeyPairParameters.Type;\n\nexport const PrivateKeyInput = Schema.Struct({\n algorithm: Algorithm,\n privateKey: Schema.Redacted(Schema.Uint8Array, { disallowJsonEncode: true }),\n});\n\nexport type PrivateKeyInput = typeof PrivateKeyInput.Type;\n\nexport const PublicKeyInput = Schema.Struct({\n algorithm: Algorithm,\n publicKey: Schema.Uint8Array,\n});\n\nexport type PublicKeyInput = typeof PublicKeyInput.Type;\n\nexport const SignInput = Schema.Struct({\n ...PrivateKeyInput.fields,\n data: Schema.Uint8Array,\n});\n\nexport type SignInput = typeof SignInput.Type;\n\nexport const VerifyInput = Schema.Struct({\n ...PublicKeyInput.fields,\n data: Schema.Uint8Array,\n signature: Schema.Uint8Array,\n});\n\nexport type VerifyInput = typeof VerifyInput.Type;\n\n/** A nonextractable signing key with its algorithm fixed at import. */\nexport interface PrivateKey {\n readonly sign: (data: Uint8Array) => Effect.Effect<Uint8Array, OperationError>;\n}\n\n/** A verification key with its algorithm fixed at import. */\nexport interface PublicKey {\n readonly verify: (\n data: Uint8Array,\n signature: Uint8Array,\n ) => Effect.Effect<boolean, OperationError>;\n}\n\n/**\n * Private keys are PKCS8 DER; public keys are SPKI DER. ECDSA signatures are\n * 64-byte IEEE P1363 (r || s), not ASN.1 DER. RSA requires at least 2048 bits;\n * PSS uses a 32-byte salt. Key serialization/selection and JOSE policy stay outside.\n */\nexport class Signature extends Context.Service<\n Signature,\n {\n /** Snapshot PKCS8 once; the imported key is usable only inside its owning Scope. */\n readonly importPrivateKey: (\n input: PrivateKeyInput,\n ) => Effect.Effect<PrivateKey, OperationError, Scope.Scope>;\n /** Snapshot SPKI once; scope closure joins native work and rejects later use. */\n readonly importPublicKey: (\n input: PublicKeyInput,\n ) => Effect.Effect<PublicKey, OperationError, Scope.Scope>;\n /** Generate exportable components. The caller owns the returned secret bytes. */\n readonly generateKeyPair: (\n input: GenerateKeyPairInput,\n ) => Effect.Effect<KeyPairParameters, OperationError>;\n readonly encodePublicKey: (\n input: PublicKeyParameters,\n ) => Effect.Effect<Uint8Array, OperationError>;\n readonly encodePrivateKey: (\n input: Redacted.Redacted<PrivateKeyParameters>,\n ) => Effect.Effect<Redacted.Redacted<Uint8Array>, OperationError>;\n readonly sign: (input: SignInput) => Effect.Effect<Uint8Array, OperationError>;\n readonly verify: (input: VerifyInput) => Effect.Effect<boolean, OperationError>;\n }\n>()(\"@yielded/crypto/Signature\") {}\n"],"mappings":";;AAIA,MAAa,YAAY,OAAO,SAAS;CACvC;CACA;CACA;CACA;AACF,CAAC;AAID,MAAM,aAAa,OAAO,WAAW,MAAM,OAAO,YAAY,EAAE,GAAG,OAAO,YAAY,EAAE,CAAC;AACzF,MAAM,UAAU,OAAO,WAAW,MAAM,OAAO,YAAY,CAAC,GAAG,OAAO,YAAY,IAAI,CAAC;AACvF,MAAM,KAAK;CAAE,WAAW,OAAO,QAAQ,mBAAmB;CAAG,GAAG;CAAY,GAAG;AAAW;AAC1F,MAAM,KAAK;CAAE,WAAW,OAAO,QAAQ,SAAS;CAAG,GAAG;AAAW;AAEjE,MAAM,MAAM;CACV,WAAW,OAAO,SAAS,CAAC,4BAA4B,gBAAgB,CAAC;CACzE,GAAG;CACH,GAAG;AACL;;;;;AAMA,MAAa,sBAAsB,OAAO,MAAM;CAC9C,OAAO,OAAO,EAAE;CAChB,OAAO,OAAO,EAAE;CAChB,OAAO,OAAO,GAAG;AACnB,CAAC;AAID,MAAa,uBAAuB,OAAO,MAAM;CAC/C,OAAO,OAAO;EAAE,GAAG;EAAI,GAAG;CAAW,CAAC;CACtC,OAAO,OAAO;EAAE,GAAG;EAAI,GAAG;CAAW,CAAC;CACtC,OAAO,OAAO;EACZ,GAAG;EACH,GAAG;EACH,GAAG;EACH,GAAG;EACH,IAAI;EACJ,IAAI;EACJ,IAAI;CACN,CAAC;AACH,CAAC;AAID,MAAa,mBAAmB,OAAO,SAAS;CAAC;CAAM;CAAM;AAAI,CAAC;;AAGlE,MAAa,uBAAuB,OAAO,MAAM,CAC/C,OAAO,OAAO,EAAE,WAAW,OAAO,SAAS,CAAC,qBAAqB,SAAS,CAAC,EAAE,CAAC,GAC9E,OAAO,OAAO;CACZ,WAAW,OAAO,SAAS,CAAC,4BAA4B,gBAAgB,CAAC;CACzE,eAAe,OAAO,YAAY,gBAAgB;AACpD,CAAC,CACH,CAAC;AAID,MAAa,oBAAoB,OAAO,OAAO;CAC7C,WAAW;CACX,YAAY,OAAO,SAAS,sBAAsB,EAAE,oBAAoB,KAAK,CAAC;AAChF,CAAC;AAID,MAAa,kBAAkB,OAAO,OAAO;CAC3C,WAAW;CACX,YAAY,OAAO,SAAS,OAAO,YAAY,EAAE,oBAAoB,KAAK,CAAC;AAC7E,CAAC;AAID,MAAa,iBAAiB,OAAO,OAAO;CAC1C,WAAW;CACX,WAAW,OAAO;AACpB,CAAC;AAID,MAAa,YAAY,OAAO,OAAO;CACrC,GAAG,gBAAgB;CACnB,MAAM,OAAO;AACf,CAAC;AAID,MAAa,cAAc,OAAO,OAAO;CACvC,GAAG,eAAe;CAClB,MAAM,OAAO;CACb,WAAW,OAAO;AACpB,CAAC;;;;;;AAsBD,IAAa,YAAb,cAA+B,QAAQ,QAwBrC,CAAC,CAAC,2BAA2B,CAAC,CAAC,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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"}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@yielded/crypto","version":"0.1.0-beta.
|
|
1
|
+
{"name":"@yielded/crypto","version":"0.1.0-beta.30","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"}}
|
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>;
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { Effect, Redacted, Schema } from "effect";
|
|
2
2
|
import { Base64Url } from "effect/encoding";
|
|
3
3
|
|
|
4
|
-
import { InvalidInput } from "../Errors";
|
|
4
|
+
import { CryptoUnavailable, InvalidInput } from "../Errors";
|
|
5
5
|
import {
|
|
6
6
|
type Algorithm,
|
|
7
7
|
type PrivateKey,
|
|
8
8
|
PrivateKeyInput,
|
|
9
|
+
GenerateKeyPairInput,
|
|
9
10
|
PrivateKeyParameters,
|
|
10
11
|
type PublicKey,
|
|
11
12
|
PublicKeyInput,
|
|
@@ -23,6 +24,21 @@ const RsaAlgorithm = Schema.Struct({
|
|
|
23
24
|
modulusLength: Schema.Int.check(Schema.isGreaterThanOrEqualTo(2048)),
|
|
24
25
|
});
|
|
25
26
|
|
|
27
|
+
const component = Schema.Uint8ArrayFromBase64Url;
|
|
28
|
+
const GeneratedEc = Schema.Struct({ x: component, y: component, d: component });
|
|
29
|
+
const GeneratedEd = Schema.Struct({ x: component, d: component });
|
|
30
|
+
|
|
31
|
+
const GeneratedRsa = Schema.Struct({
|
|
32
|
+
n: component,
|
|
33
|
+
e: component,
|
|
34
|
+
d: component,
|
|
35
|
+
p: component,
|
|
36
|
+
q: component,
|
|
37
|
+
dp: component,
|
|
38
|
+
dq: component,
|
|
39
|
+
qi: component,
|
|
40
|
+
});
|
|
41
|
+
|
|
26
42
|
const importAlgorithm = (algorithm: Algorithm) => {
|
|
27
43
|
switch (algorithm) {
|
|
28
44
|
case "ECDSA-P256-SHA256":
|
|
@@ -175,6 +191,75 @@ export const makeSignature = (subtle: SubtleCrypto): Signature["Service"] => {
|
|
|
175
191
|
}),
|
|
176
192
|
} satisfies PublicKey;
|
|
177
193
|
}),
|
|
194
|
+
generateKeyPair: Effect.fnUntraced(function* (input) {
|
|
195
|
+
const value = yield* decode(GenerateKeyPairInput, input, "parameters");
|
|
196
|
+
|
|
197
|
+
const pair = yield* Effect.tryPromise({
|
|
198
|
+
try: () => {
|
|
199
|
+
switch (value.algorithm) {
|
|
200
|
+
case "ECDSA-P256-SHA256":
|
|
201
|
+
return subtle.generateKey({ name: "ECDSA", namedCurve: "P-256" }, true, [
|
|
202
|
+
"sign",
|
|
203
|
+
"verify",
|
|
204
|
+
]);
|
|
205
|
+
case "Ed25519":
|
|
206
|
+
return subtle.generateKey("Ed25519", true, ["sign", "verify"]);
|
|
207
|
+
case "RSASSA-PKCS1-v1_5-SHA256":
|
|
208
|
+
case "RSA-PSS-SHA256":
|
|
209
|
+
return subtle.generateKey(
|
|
210
|
+
{
|
|
211
|
+
name: value.algorithm === "RSA-PSS-SHA256" ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
212
|
+
hash: "SHA-256",
|
|
213
|
+
modulusLength: value.modulusLength ?? 2048,
|
|
214
|
+
publicExponent: new Uint8Array([1, 0, 1]),
|
|
215
|
+
},
|
|
216
|
+
true,
|
|
217
|
+
["sign", "verify"],
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
catch: nativeError,
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
const jwk = yield* Effect.tryPromise({
|
|
225
|
+
try: () => subtle.exportKey("jwk", pair.privateKey),
|
|
226
|
+
catch: nativeError,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
// JsonWebKey does not guarantee algorithm-specific fields. Decode only at
|
|
230
|
+
// this native boundary; callers receive typed components, never loose JWKs.
|
|
231
|
+
const parameters: PrivateKeyParameters = yield* Effect.gen(function* () {
|
|
232
|
+
switch (value.algorithm) {
|
|
233
|
+
case "ECDSA-P256-SHA256":
|
|
234
|
+
return {
|
|
235
|
+
algorithm: value.algorithm,
|
|
236
|
+
...(yield* Schema.decodeUnknownEffect(GeneratedEc)(jwk, { reportInput: false })),
|
|
237
|
+
};
|
|
238
|
+
case "Ed25519":
|
|
239
|
+
return {
|
|
240
|
+
algorithm: value.algorithm,
|
|
241
|
+
...(yield* Schema.decodeUnknownEffect(GeneratedEd)(jwk, { reportInput: false })),
|
|
242
|
+
};
|
|
243
|
+
case "RSASSA-PKCS1-v1_5-SHA256":
|
|
244
|
+
case "RSA-PSS-SHA256":
|
|
245
|
+
return {
|
|
246
|
+
algorithm: value.algorithm,
|
|
247
|
+
...(yield* Schema.decodeUnknownEffect(GeneratedRsa)(jwk, { reportInput: false })),
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}).pipe(Effect.mapError(() => CryptoUnavailable.make({})));
|
|
251
|
+
|
|
252
|
+
yield* decode(PrivateKeyParameters, parameters, "key");
|
|
253
|
+
|
|
254
|
+
const publicKey: PublicKeyParameters =
|
|
255
|
+
"n" in parameters
|
|
256
|
+
? { algorithm: parameters.algorithm, n: parameters.n.slice(), e: parameters.e.slice() }
|
|
257
|
+
: "y" in parameters
|
|
258
|
+
? { algorithm: parameters.algorithm, x: parameters.x.slice(), y: parameters.y.slice() }
|
|
259
|
+
: { algorithm: "Ed25519", x: parameters.x.slice() };
|
|
260
|
+
|
|
261
|
+
return { publicKey, privateKey: Redacted.make(parameters) };
|
|
262
|
+
}, Effect.uninterruptible),
|
|
178
263
|
encodePublicKey: Effect.fnUntraced(function* (input) {
|
|
179
264
|
const parameters = yield* decode(PublicKeyParameters, input, "key");
|
|
180
265
|
const key = yield* importComponents(parameters, "verify");
|