iso-signatures 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/asn1.d.ts +31 -0
- package/dist/src/asn1.d.ts.map +1 -0
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/spki.d.ts +14 -0
- package/dist/src/spki.d.ts.map +1 -0
- package/dist/src/types.d.ts +63 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/utils.d.ts +12 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/package.json +138 -0
- package/readme.md +59 -0
- package/src/asn1.js +329 -0
- package/src/index.js +1 -0
- package/src/signers/ecdsa.js +147 -0
- package/src/signers/eddsa.js +80 -0
- package/src/signers/rsa-old.js +128 -0
- package/src/signers/rsa.js +133 -0
- package/src/spki.js +39 -0
- package/src/types.ts +75 -0
- package/src/utils.js +35 -0
- package/src/verifiers/ecdsa.js +56 -0
- package/src/verifiers/eddsa.js +12 -0
- package/src/verifiers/resolver.js +63 -0
- package/src/verifiers/rsa-old.js +25 -0
- package/src/verifiers/rsa.js +26 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export const INT_TAG: 2;
|
|
2
|
+
export const BITSTRING_TAG: 3;
|
|
3
|
+
export const OCTET_STRING_TAG: 4;
|
|
4
|
+
export const NULL_TAG: 5;
|
|
5
|
+
export const OBJECT_TAG: 6;
|
|
6
|
+
export const SEQUENCE_TAG: 48;
|
|
7
|
+
export const UNUSED_BIT_PAD: 0;
|
|
8
|
+
export function encodeDERLength(length: number): Uint8Array;
|
|
9
|
+
export function readDERLength(bytes: Uint8Array, offset?: number): {
|
|
10
|
+
number: number;
|
|
11
|
+
consumed: number;
|
|
12
|
+
};
|
|
13
|
+
export function skip(input: Uint8Array, expectedTag: number, position: number): number;
|
|
14
|
+
export function into(input: Uint8Array, expectedTag: number, offset: number): {
|
|
15
|
+
position: number;
|
|
16
|
+
length: number;
|
|
17
|
+
};
|
|
18
|
+
export function encodeBitString(input: Uint8Array): Uint8Array;
|
|
19
|
+
export function encodeOctetString(input: Uint8Array): Uint8Array;
|
|
20
|
+
export function encodeSequence(sequence: Uint8Array[]): Uint8Array;
|
|
21
|
+
export function readSequence(bytes: Uint8Array, offset?: number): Uint8Array;
|
|
22
|
+
export function encodeInt(input: Uint8Array): Uint8Array;
|
|
23
|
+
export function enterSequence(bytes: Uint8Array, offset?: number): number;
|
|
24
|
+
export function skipSequence(bytes: Uint8Array, offset?: number): number;
|
|
25
|
+
export function skipInt(bytes: Uint8Array, offset?: number): number;
|
|
26
|
+
export function readBitString(bytes: Uint8Array, offset?: number): Uint8Array;
|
|
27
|
+
export function readInt(bytes: Uint8Array, byteOffset?: number): Uint8Array;
|
|
28
|
+
export function readOctetString(bytes: Uint8Array, offset?: number): Uint8Array;
|
|
29
|
+
export function readSequenceWith(readers: [Reader, ...Reader[]], source: Uint8Array, byteOffset?: number): Uint8Array[];
|
|
30
|
+
export type Reader = (bytes: Uint8Array, offset: number) => Uint8Array;
|
|
31
|
+
//# sourceMappingURL=asn1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asn1.d.ts","sourceRoot":"","sources":["../../src/asn1.js"],"names":[],"mappings":"AAIA,wBAA2B;AAC3B,8BAAiC;AACjC,iCAAoC;AACpC,yBAA4B;AAC5B,2BAA8B;AAC9B,8BAAgC;AAEhC,+BAAkC;AAM3B,wCAHI,MAAM,GACJ,UAAU,CAetB;AAOM,qCAJI,UAAU,WACV,MAAM,GACJ;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAC,CAsB9C;AAQM,4BALI,UAAU,eACV,MAAM,YACN,MAAM,GACJ,MAAM,CAKlB;AAQM,4BALI,UAAU,eACV,MAAM,UACN,MAAM;cACQ,MAAM;YAAU,MAAM;EAmB9C;AAKM,uCAFI,UAAU,cA8BpB;AAKM,yCAFI,UAAU,cAqBpB;AAKM,yCAFI,UAAU,EAAE,cAgCtB;AAMM,oCAHI,UAAU,WACV,MAAM,cAMhB;AAKM,iCAFI,UAAU,cAkCpB;AAQM,qCALI,UAAU,WACV,MAAM,GACJ,MAAM,CAIyB;AAOrC,oCAJI,UAAU,WACV,MAAM,GACJ,MAAM,CAGgB;AAO5B,+BAJI,UAAU,WACV,MAAM,GACJ,MAAM,CAEuD;AAOnE,qCAJI,UAAU,WACV,MAAM,GACJ,UAAU,CAiBtB;AAOM,+BAJI,UAAU,eACV,MAAM,GACJ,UAAU,CAgBtB;AAOM,uCAJI,UAAU,WACV,MAAM,GACJ,UAAU,CAMtB;AAQM,0CAJI,CAAC,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,UACrB,UAAU,eACV,MAAM,gBAYhB;6BAfmB,UAAU,UAAS,MAAM,KAAK,UAAU"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export namespace spki {
|
|
2
|
+
export { encode };
|
|
3
|
+
export { decode };
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* @param {Uint8Array} key
|
|
7
|
+
*/
|
|
8
|
+
declare function encode(key: Uint8Array): Uint8Array;
|
|
9
|
+
/**
|
|
10
|
+
* @param {Uint8Array} info
|
|
11
|
+
*/
|
|
12
|
+
declare function decode(info: Uint8Array): Uint8Array;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=spki.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"spki.d.ts","sourceRoot":"","sources":["../../src/spki.js"],"names":[],"mappings":";;;;AAgBA;;GAEG;AACH,6BAFW,UAAU,cAIpB;AAED;;GAEG;AACH,8BAFW,UAAU,cAUpB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { DIDKey } from 'iso-did/key';
|
|
2
|
+
import type { SignatureAlgorithm, KeyType } from 'iso-did/types';
|
|
3
|
+
export interface ISigner<Export extends CryptoKeyPair | string> {
|
|
4
|
+
/**
|
|
5
|
+
* JWT signing algorithm
|
|
6
|
+
*/
|
|
7
|
+
alg: SignatureAlgorithm;
|
|
8
|
+
/**
|
|
9
|
+
* Keypair type
|
|
10
|
+
*/
|
|
11
|
+
type: KeyType;
|
|
12
|
+
/**
|
|
13
|
+
* Multicodec identifier for the private key
|
|
14
|
+
*/
|
|
15
|
+
code?: number;
|
|
16
|
+
did: DIDKey;
|
|
17
|
+
/**
|
|
18
|
+
* Sign a message
|
|
19
|
+
*/
|
|
20
|
+
sign: (message: Uint8Array) => Promise<Uint8Array>;
|
|
21
|
+
export: () => Export;
|
|
22
|
+
}
|
|
23
|
+
export interface VerifyInput {
|
|
24
|
+
signature: Uint8Array;
|
|
25
|
+
message: Uint8Array;
|
|
26
|
+
publicKey: Uint8Array;
|
|
27
|
+
}
|
|
28
|
+
export type Verify = (input: VerifyInput) => Promise<boolean>;
|
|
29
|
+
export type Verifier<T extends SignatureAlgorithm> = Record<T, Verify>;
|
|
30
|
+
export type VerifierRegistry<T extends SignatureAlgorithm> = Partial<Verifier<T>>;
|
|
31
|
+
export interface ResolverVerifyInput extends VerifyInput {
|
|
32
|
+
alg: SignatureAlgorithm;
|
|
33
|
+
}
|
|
34
|
+
export type Cache = (parsed: VerifyInput, verify: Verify) => Promise<boolean>;
|
|
35
|
+
export interface IResolver {
|
|
36
|
+
verify: (input: ResolverVerifyInput) => Promise<boolean>;
|
|
37
|
+
}
|
|
38
|
+
export interface ResolverOptions {
|
|
39
|
+
cache?: Cache | boolean | undefined;
|
|
40
|
+
}
|
|
41
|
+
export interface PublicKeyJwk {
|
|
42
|
+
kty: string;
|
|
43
|
+
crv: string;
|
|
44
|
+
x: string;
|
|
45
|
+
y: string;
|
|
46
|
+
}
|
|
47
|
+
export interface PublicKeyRSAJwk {
|
|
48
|
+
kty: string;
|
|
49
|
+
n: string;
|
|
50
|
+
e: string;
|
|
51
|
+
}
|
|
52
|
+
export interface PrivateKeyRSAJwk extends PublicKeyRSAJwk {
|
|
53
|
+
d: string;
|
|
54
|
+
p: string;
|
|
55
|
+
q: string;
|
|
56
|
+
dp: string;
|
|
57
|
+
dq: string;
|
|
58
|
+
qi: string;
|
|
59
|
+
}
|
|
60
|
+
export type PrivateKeyJwk = PublicKeyJwk & {
|
|
61
|
+
d: string;
|
|
62
|
+
};
|
|
63
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AAEhE,MAAM,WAAW,OAAO,CAAC,MAAM,SAAS,aAAa,GAAG,MAAM;IAC5D;;OAEG;IACH,GAAG,EAAE,kBAAkB,CAAA;IACvB;;OAEG;IACH,IAAI,EAAE,OAAO,CAAA;IACb;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IAEb,GAAG,EAAE,MAAM,CAAA;IACX;;OAEG;IACH,IAAI,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,OAAO,CAAC,UAAU,CAAC,CAAA;IAElD,MAAM,EAAE,MAAM,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,UAAU,CAAA;IACrB,OAAO,EAAE,UAAU,CAAA;IACnB,SAAS,EAAE,UAAU,CAAA;CACtB;AACD,MAAM,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,WAAW,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE7D,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,kBAAkB,IAAI,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAA;AAEtE,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,kBAAkB,IAAI,OAAO,CAClE,QAAQ,CAAC,CAAC,CAAC,CACZ,CAAA;AAED,MAAM,WAAW,mBAAoB,SAAQ,WAAW;IACtD,GAAG,EAAE,kBAAkB,CAAA;CACxB;AACD,MAAM,MAAM,KAAK,GAAG,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;AAE7E,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACzD;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,GAAG,SAAS,CAAA;CACpC;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAA;IACX,GAAG,EAAE,MAAM,CAAA;IACX,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAA;IACX,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;IACV,EAAE,EAAE,MAAM,CAAA;CACX;AAED,MAAM,MAAM,aAAa,GAAG,YAAY,GAAG;IAAE,CAAC,EAAE,MAAM,CAAA;CAAE,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create web crypto params for ECDSA.
|
|
3
|
+
*
|
|
4
|
+
* @param {import("iso-did/types").SignatureAlgorithm} alg
|
|
5
|
+
* @returns {{name: 'ECDSA', namedCurve: 'P-256' | 'P-384' | 'P-521', hash: 'SHA-256' | 'SHA-384' | 'SHA-512'}}
|
|
6
|
+
*/
|
|
7
|
+
export function createEcdsaParams(alg: import("iso-did/types").SignatureAlgorithm): {
|
|
8
|
+
name: 'ECDSA';
|
|
9
|
+
namedCurve: 'P-256' | 'P-384' | 'P-521';
|
|
10
|
+
hash: 'SHA-256' | 'SHA-384' | 'SHA-512';
|
|
11
|
+
};
|
|
12
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.js"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,uCAHW,OAAO,eAAe,EAAE,kBAAkB,GACxC;IAAC,MAAM,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,SAAS,CAAA;CAAC,CA8B7G"}
|
package/package.json
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iso-signatures",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Signatures tooling.",
|
|
5
|
+
"author": "Hugo Dias <hugomrdias@gmail.com> (hugodias.me)",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"url": "hugomrdias/iso-repo",
|
|
9
|
+
"directory": "packages/iso-signatures"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://github.com/hugomrdias/iso-repo/tree/main/packages/iso-signatures",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"elliptic",
|
|
14
|
+
"curve",
|
|
15
|
+
"cryptography",
|
|
16
|
+
"edwards",
|
|
17
|
+
"p256",
|
|
18
|
+
"p384",
|
|
19
|
+
"p521",
|
|
20
|
+
"secp256r1",
|
|
21
|
+
"secp256k1",
|
|
22
|
+
"ed25519",
|
|
23
|
+
"ecdsa",
|
|
24
|
+
"eddsa",
|
|
25
|
+
"rsa",
|
|
26
|
+
"signatures"
|
|
27
|
+
],
|
|
28
|
+
"type": "module",
|
|
29
|
+
"main": "src/index.js",
|
|
30
|
+
"types": "dist/src/index.d.ts",
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/src/index.d.ts",
|
|
34
|
+
"import": "./src/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./signers/ecdsa": {
|
|
37
|
+
"types": "./dist/src/signers/ecdsa.d.ts",
|
|
38
|
+
"import": "./src/signers/ecdsa.js"
|
|
39
|
+
},
|
|
40
|
+
"./signers/eddsa": {
|
|
41
|
+
"types": "./dist/src/signers/eddsa.d.ts",
|
|
42
|
+
"import": "./src/signers/eddsa.js"
|
|
43
|
+
},
|
|
44
|
+
"./signers/rsa-old": {
|
|
45
|
+
"types": "./dist/src/signers/rsa-old.d.ts",
|
|
46
|
+
"import": "./src/signers/rsa-old.js"
|
|
47
|
+
},
|
|
48
|
+
"./signers/rsa": {
|
|
49
|
+
"types": "./dist/src/signers/rsa.d.ts",
|
|
50
|
+
"import": "./src/signers/rsa.js"
|
|
51
|
+
},
|
|
52
|
+
"./verifiers/ecdsa": {
|
|
53
|
+
"types": "./dist/src/verifiers/ecdsa.d.ts",
|
|
54
|
+
"import": "./src/verifiers/ecdsa.js"
|
|
55
|
+
},
|
|
56
|
+
"./verifiers/eddsa": {
|
|
57
|
+
"types": "./dist/src/verifiers/eddsa.d.ts",
|
|
58
|
+
"import": "./src/verifiers/eddsa.js"
|
|
59
|
+
},
|
|
60
|
+
"./verifiers/rsa-old": {
|
|
61
|
+
"types": "./dist/src/verifiers/rsa-old.d.ts",
|
|
62
|
+
"import": "./src/verifiers/rsa-old.js"
|
|
63
|
+
},
|
|
64
|
+
"./verifiers/rsa": {
|
|
65
|
+
"types": "./dist/src/verifiers/rsa.d.ts",
|
|
66
|
+
"import": "./src/verifiers/rsa.js"
|
|
67
|
+
},
|
|
68
|
+
"./verifiers/resolver": {
|
|
69
|
+
"types": "./dist/src/verifiers/resolver.d.ts",
|
|
70
|
+
"import": "./src/verifiers/resolver.js"
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
"typesVersions": {
|
|
74
|
+
"*": {
|
|
75
|
+
".": [
|
|
76
|
+
"dist/src/index"
|
|
77
|
+
],
|
|
78
|
+
"signers/*": [
|
|
79
|
+
"dist/src/signers/*"
|
|
80
|
+
],
|
|
81
|
+
"verifiers/*": [
|
|
82
|
+
"dist/src/verifiers/*"
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"files": [
|
|
87
|
+
"src",
|
|
88
|
+
"dist/src/*.d.ts",
|
|
89
|
+
"dist/src/*.d.ts.map"
|
|
90
|
+
],
|
|
91
|
+
"dependencies": {
|
|
92
|
+
"@noble/ed25519": "^2.0.0",
|
|
93
|
+
"iso-base": "^1.0.0",
|
|
94
|
+
"iso-did": "^1.3.0"
|
|
95
|
+
},
|
|
96
|
+
"devDependencies": {
|
|
97
|
+
"@types/assert": "^1.5.6",
|
|
98
|
+
"@types/mocha": "^10.0.1",
|
|
99
|
+
"@types/node": "^20.3.1",
|
|
100
|
+
"assert": "^2.0.0",
|
|
101
|
+
"hd-scripts": "^7.0.0",
|
|
102
|
+
"mocha": "^10.2.0",
|
|
103
|
+
"playwright-test": "^9.2.0",
|
|
104
|
+
"type-fest": "^3.12.0",
|
|
105
|
+
"typescript": "5.1.3"
|
|
106
|
+
},
|
|
107
|
+
"eslintConfig": {
|
|
108
|
+
"extends": [
|
|
109
|
+
"../../node_modules/hd-scripts/eslint/index.js"
|
|
110
|
+
],
|
|
111
|
+
"parserOptions": {
|
|
112
|
+
"project": "./tsconfig.json"
|
|
113
|
+
},
|
|
114
|
+
"env": {
|
|
115
|
+
"mocha": true
|
|
116
|
+
},
|
|
117
|
+
"ignorePatterns": [
|
|
118
|
+
"dist"
|
|
119
|
+
]
|
|
120
|
+
},
|
|
121
|
+
"depcheck": {
|
|
122
|
+
"specials": [
|
|
123
|
+
"bin"
|
|
124
|
+
],
|
|
125
|
+
"ignores": [
|
|
126
|
+
"@types/*",
|
|
127
|
+
"hd-scripts",
|
|
128
|
+
"assert",
|
|
129
|
+
"type-fest"
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
"scripts": {
|
|
133
|
+
"lint": "tsc --build && eslint '**/*.{js,ts}' && prettier --check '**/*.{js,ts,yml,json}' --ignore-path ../../.gitignore",
|
|
134
|
+
"test": "tsc --build && pnpm run test:node && pnpm run test:browser",
|
|
135
|
+
"test:node": "mocha 'test/**/!(*.browser).test.js'",
|
|
136
|
+
"test:browser": "playwright-test 'test/**/!(*.node).test.js'"
|
|
137
|
+
}
|
|
138
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# iso-signatures [](https://www.npmjs.com/package/iso-signatures) [](https://github.com/hugomrdias/iso-repo/blob/main/license) [](https://github.com/hugomrdias/iso-repo/actions/workflows/iso-signatures.yml)
|
|
2
|
+
|
|
3
|
+
> Isomorphic signatures tooling
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm install iso-signatures
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { EdDSASigner } from 'iso-signatures/signers/eddsa'
|
|
15
|
+
import * as EdDSA from 'iso-signatures/verifiers/eddsa'
|
|
16
|
+
|
|
17
|
+
const message = new TextEncoder().encode('hello world')
|
|
18
|
+
const resolver = new Resolver({
|
|
19
|
+
...EdDSA.verifier,
|
|
20
|
+
})
|
|
21
|
+
const signer = await EdDSASigner.generate()
|
|
22
|
+
const signature = await signer.sign(message)
|
|
23
|
+
const verified = await resolver.verify({
|
|
24
|
+
signature,
|
|
25
|
+
message,
|
|
26
|
+
...signer,
|
|
27
|
+
})
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { EdDSASigner } from 'iso-signatures/signers/eddsa'
|
|
32
|
+
import * as EdDSA from 'iso-signatures/verifiers/eddsa'
|
|
33
|
+
import * as ECDSA from 'iso-signatures/verifiers/ecdsa'
|
|
34
|
+
import * as RSA from 'iso-signatures/verifiers/rsa'
|
|
35
|
+
|
|
36
|
+
const message = new TextEncoder().encode('hello world')
|
|
37
|
+
const resolver = new Resolver(
|
|
38
|
+
{
|
|
39
|
+
...ECDSA.verifier,
|
|
40
|
+
...EdDSA.verifier,
|
|
41
|
+
},
|
|
42
|
+
{ cache: true }
|
|
43
|
+
)
|
|
44
|
+
const signer = await EdDSASigner.generate()
|
|
45
|
+
const signature = await signer.sign(message)
|
|
46
|
+
const verified = await resolver.verify({
|
|
47
|
+
signature,
|
|
48
|
+
message,
|
|
49
|
+
...signer.did, // Signer and DID both have `alg` property that the resolver uses to find the correct verifier
|
|
50
|
+
})
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Docs
|
|
54
|
+
|
|
55
|
+
Check <https://hugomrdias.github.io/iso-repo/modules/iso_signatures.html>
|
|
56
|
+
|
|
57
|
+
## License
|
|
58
|
+
|
|
59
|
+
MIT © [Hugo Dias](http://hugodias.me)
|
package/src/asn1.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASN1 Tags as per https://luca.ntop.org/Teaching/Appunti/asn1.html
|
|
3
|
+
*/
|
|
4
|
+
const TAG_SIZE = 1
|
|
5
|
+
export const INT_TAG = 0x02
|
|
6
|
+
export const BITSTRING_TAG = 0x03
|
|
7
|
+
export const OCTET_STRING_TAG = 0x04
|
|
8
|
+
export const NULL_TAG = 0x05
|
|
9
|
+
export const OBJECT_TAG = 0x06
|
|
10
|
+
export const SEQUENCE_TAG = 0x30
|
|
11
|
+
|
|
12
|
+
export const UNUSED_BIT_PAD = 0x00
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {number} length
|
|
16
|
+
* @returns {Uint8Array}
|
|
17
|
+
*/
|
|
18
|
+
export const encodeDERLength = (length) => {
|
|
19
|
+
if (length <= 127) {
|
|
20
|
+
return new Uint8Array([length])
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** @type {number[]} */
|
|
24
|
+
const octets = []
|
|
25
|
+
while (length !== 0) {
|
|
26
|
+
octets.push(length & 0xff)
|
|
27
|
+
length = length >>> 8
|
|
28
|
+
}
|
|
29
|
+
octets.reverse()
|
|
30
|
+
return new Uint8Array([0x80 | (octets.length & 0xff), ...octets])
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {Uint8Array} bytes
|
|
35
|
+
* @param {number} offset
|
|
36
|
+
* @returns {{number: number, consumed: number}}
|
|
37
|
+
*/
|
|
38
|
+
export const readDERLength = (bytes, offset = 0) => {
|
|
39
|
+
if ((bytes[offset] & 0x80) === 0) {
|
|
40
|
+
return { number: bytes[offset], consumed: 1 }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const numberBytes = bytes[offset] & 0x7f
|
|
44
|
+
/* c8 ignore next 5 */
|
|
45
|
+
if (bytes.length < numberBytes + 1) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`ASN parsing error: Too few bytes. Expected encoded length's length to be at least ${numberBytes}`
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let length = 0
|
|
52
|
+
for (let i = 0; i < numberBytes; i++) {
|
|
53
|
+
length = length << 8
|
|
54
|
+
length = length | bytes[offset + i + 1]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { number: length, consumed: numberBytes + 1 }
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {Uint8Array} input
|
|
62
|
+
* @param {number} expectedTag
|
|
63
|
+
* @param {number} position
|
|
64
|
+
* @returns {number}
|
|
65
|
+
*/
|
|
66
|
+
export const skip = (input, expectedTag, position) => {
|
|
67
|
+
const parsed = into(input, expectedTag, position)
|
|
68
|
+
return parsed.position + parsed.length
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* @param {Uint8Array} input
|
|
73
|
+
* @param {number} expectedTag
|
|
74
|
+
* @param {number} offset
|
|
75
|
+
* @returns {{ position: number, length: number }}
|
|
76
|
+
*/
|
|
77
|
+
export const into = (input, expectedTag, offset) => {
|
|
78
|
+
const actualTag = input[offset]
|
|
79
|
+
/* c8 ignore next 7 */
|
|
80
|
+
if (actualTag !== expectedTag) {
|
|
81
|
+
throw new Error(
|
|
82
|
+
`ASN parsing error: Expected tag 0x${expectedTag.toString(
|
|
83
|
+
16
|
|
84
|
+
)} at position ${offset}, but got 0x${actualTag.toString(16)}.`
|
|
85
|
+
)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// length
|
|
89
|
+
const length = readDERLength(input, offset + TAG_SIZE)
|
|
90
|
+
const position = offset + TAG_SIZE + length.consumed
|
|
91
|
+
|
|
92
|
+
// content
|
|
93
|
+
return { position, length: length.number }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {Uint8Array} input
|
|
98
|
+
*/
|
|
99
|
+
export const encodeBitString = (input) => {
|
|
100
|
+
// encode input length + 1 for unused bit pad
|
|
101
|
+
const length = encodeDERLength(input.byteLength + 1)
|
|
102
|
+
// allocate a buffer of desired size
|
|
103
|
+
const bytes = new Uint8Array(
|
|
104
|
+
TAG_SIZE + // ASN_BITSTRING_TAG
|
|
105
|
+
length.byteLength +
|
|
106
|
+
1 + // amount of unused bits at the end of our bitstring
|
|
107
|
+
input.byteLength
|
|
108
|
+
)
|
|
109
|
+
|
|
110
|
+
let byteOffset = 0
|
|
111
|
+
// write bytestring tag
|
|
112
|
+
bytes[byteOffset] = BITSTRING_TAG
|
|
113
|
+
byteOffset += TAG_SIZE
|
|
114
|
+
|
|
115
|
+
// write length of the bytestring
|
|
116
|
+
bytes.set(length, byteOffset)
|
|
117
|
+
byteOffset += length.byteLength
|
|
118
|
+
|
|
119
|
+
// write unused bits at the end of our bitstring
|
|
120
|
+
bytes[byteOffset] = UNUSED_BIT_PAD
|
|
121
|
+
byteOffset += 1
|
|
122
|
+
|
|
123
|
+
// write actual data into bitstring
|
|
124
|
+
bytes.set(input, byteOffset)
|
|
125
|
+
|
|
126
|
+
return bytes
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @param {Uint8Array} input
|
|
131
|
+
*/
|
|
132
|
+
export const encodeOctetString = (input) => {
|
|
133
|
+
// encode input length
|
|
134
|
+
const length = encodeDERLength(input.byteLength)
|
|
135
|
+
// allocate a buffer of desired size
|
|
136
|
+
const bytes = new Uint8Array(TAG_SIZE + length.byteLength + input.byteLength)
|
|
137
|
+
|
|
138
|
+
let byteOffset = 0
|
|
139
|
+
// write octet string tag
|
|
140
|
+
bytes[byteOffset] = OCTET_STRING_TAG
|
|
141
|
+
byteOffset += TAG_SIZE
|
|
142
|
+
|
|
143
|
+
// write octet string length
|
|
144
|
+
bytes.set(length, byteOffset)
|
|
145
|
+
byteOffset += length.byteLength
|
|
146
|
+
|
|
147
|
+
// write actual data into bitstring
|
|
148
|
+
bytes.set(input, byteOffset)
|
|
149
|
+
|
|
150
|
+
return bytes
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @param {Uint8Array[]} sequence
|
|
155
|
+
*/
|
|
156
|
+
export const encodeSequence = (sequence) => {
|
|
157
|
+
// calculate bytelength for all the parts
|
|
158
|
+
let byteLength = 0
|
|
159
|
+
for (const item of sequence) {
|
|
160
|
+
byteLength += item.byteLength
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// encode sequence byte length
|
|
164
|
+
const length = encodeDERLength(byteLength)
|
|
165
|
+
|
|
166
|
+
// allocate the buffer to write sequence into
|
|
167
|
+
const bytes = new Uint8Array(TAG_SIZE + length.byteLength + byteLength)
|
|
168
|
+
|
|
169
|
+
let byteOffset = 0
|
|
170
|
+
|
|
171
|
+
// write the sequence tag
|
|
172
|
+
bytes[byteOffset] = SEQUENCE_TAG
|
|
173
|
+
byteOffset += TAG_SIZE
|
|
174
|
+
|
|
175
|
+
// write sequence length
|
|
176
|
+
bytes.set(length, byteOffset)
|
|
177
|
+
byteOffset += length.byteLength
|
|
178
|
+
|
|
179
|
+
// write each item in the sequence
|
|
180
|
+
for (const item of sequence) {
|
|
181
|
+
bytes.set(item, byteOffset)
|
|
182
|
+
byteOffset += item.byteLength
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return bytes
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @param {Uint8Array} bytes
|
|
190
|
+
* @param {number} offset
|
|
191
|
+
*/
|
|
192
|
+
export const readSequence = (bytes, offset = 0) => {
|
|
193
|
+
const { position, length } = into(bytes, SEQUENCE_TAG, offset)
|
|
194
|
+
|
|
195
|
+
return new Uint8Array(bytes.buffer, bytes.byteOffset + position, length)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* @param {Uint8Array} input
|
|
200
|
+
*/
|
|
201
|
+
export const encodeInt = (input) => {
|
|
202
|
+
const extra = input.byteLength === 0 || input[0] & 0x80 ? 1 : 0
|
|
203
|
+
|
|
204
|
+
// encode input length
|
|
205
|
+
const length = encodeDERLength(input.byteLength + extra)
|
|
206
|
+
// allocate a buffer of desired size
|
|
207
|
+
const bytes = new Uint8Array(
|
|
208
|
+
TAG_SIZE + // INT_TAG
|
|
209
|
+
length.byteLength +
|
|
210
|
+
input.byteLength +
|
|
211
|
+
extra
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
let byteOffset = 0
|
|
215
|
+
// write octet string tag
|
|
216
|
+
bytes[byteOffset] = INT_TAG
|
|
217
|
+
byteOffset += TAG_SIZE
|
|
218
|
+
|
|
219
|
+
// write int length
|
|
220
|
+
bytes.set(length, byteOffset)
|
|
221
|
+
byteOffset += length.byteLength
|
|
222
|
+
|
|
223
|
+
// add 0 if the most-significant bit is set
|
|
224
|
+
if (extra > 0) {
|
|
225
|
+
bytes[byteOffset] = UNUSED_BIT_PAD
|
|
226
|
+
byteOffset += extra
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// write actual data into bitstring
|
|
230
|
+
bytes.set(input, byteOffset)
|
|
231
|
+
|
|
232
|
+
return bytes
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* @param {Uint8Array} bytes
|
|
237
|
+
* @param {number} offset
|
|
238
|
+
* @returns {number}
|
|
239
|
+
*/
|
|
240
|
+
|
|
241
|
+
export const enterSequence = (bytes, offset = 0) =>
|
|
242
|
+
into(bytes, SEQUENCE_TAG, offset).position
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @param {Uint8Array} bytes
|
|
246
|
+
* @param {number} offset
|
|
247
|
+
* @returns {number}
|
|
248
|
+
*/
|
|
249
|
+
export const skipSequence = (bytes, offset = 0) =>
|
|
250
|
+
skip(bytes, SEQUENCE_TAG, offset)
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* @param {Uint8Array} bytes
|
|
254
|
+
* @param {number} offset
|
|
255
|
+
* @returns {number}
|
|
256
|
+
*/
|
|
257
|
+
export const skipInt = (bytes, offset = 0) => skip(bytes, INT_TAG, offset)
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* @param {Uint8Array} bytes
|
|
261
|
+
* @param {number} offset
|
|
262
|
+
* @returns {Uint8Array}
|
|
263
|
+
*/
|
|
264
|
+
export const readBitString = (bytes, offset = 0) => {
|
|
265
|
+
const { position, length } = into(bytes, BITSTRING_TAG, offset)
|
|
266
|
+
const tag = bytes[position]
|
|
267
|
+
/* c8 ignore next 5 */
|
|
268
|
+
if (tag !== UNUSED_BIT_PAD) {
|
|
269
|
+
throw new Error(
|
|
270
|
+
`Can not read bitstring, expected length to be multiple of 8, but got ${tag} unused bits in last byte.`
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
return new Uint8Array(
|
|
275
|
+
bytes.buffer,
|
|
276
|
+
bytes.byteOffset + position + 1,
|
|
277
|
+
length - 1
|
|
278
|
+
)
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* @param {Uint8Array} bytes
|
|
283
|
+
* @param {number} byteOffset
|
|
284
|
+
* @returns {Uint8Array}
|
|
285
|
+
*/
|
|
286
|
+
export const readInt = (bytes, byteOffset = 0) => {
|
|
287
|
+
const { position, length } = into(bytes, INT_TAG, byteOffset)
|
|
288
|
+
let delta = 0
|
|
289
|
+
|
|
290
|
+
// drop leading 0s
|
|
291
|
+
while (bytes[position + delta] === 0) {
|
|
292
|
+
delta++
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return new Uint8Array(
|
|
296
|
+
bytes.buffer,
|
|
297
|
+
bytes.byteOffset + position + delta,
|
|
298
|
+
length - delta
|
|
299
|
+
)
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* @param {Uint8Array} bytes
|
|
304
|
+
* @param {number} offset
|
|
305
|
+
* @returns {Uint8Array}
|
|
306
|
+
*/
|
|
307
|
+
export const readOctetString = (bytes, offset = 0) => {
|
|
308
|
+
const { position, length } = into(bytes, OCTET_STRING_TAG, offset)
|
|
309
|
+
|
|
310
|
+
return new Uint8Array(bytes.buffer, bytes.byteOffset + position, length)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* @typedef {(bytes:Uint8Array, offset:number) => Uint8Array} Reader
|
|
315
|
+
* @param {[Reader, ...Reader[]]} readers
|
|
316
|
+
* @param {Uint8Array} source
|
|
317
|
+
* @param {number} byteOffset
|
|
318
|
+
*/
|
|
319
|
+
export const readSequenceWith = (readers, source, byteOffset = 0) => {
|
|
320
|
+
const results = []
|
|
321
|
+
const sequence = readSequence(source, byteOffset)
|
|
322
|
+
let offset = 0
|
|
323
|
+
for (const read of readers) {
|
|
324
|
+
const chunk = read(sequence, offset)
|
|
325
|
+
results.push(chunk)
|
|
326
|
+
offset = chunk.byteOffset + chunk.byteLength - sequence.byteOffset
|
|
327
|
+
}
|
|
328
|
+
return results
|
|
329
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
throw new Error('Incorrect "iso-signatures" usage. Import submodules instead')
|