@ocap/mcrypto 1.18.166 → 1.19.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/README.md +7 -7
- package/esm/crypter/aes-legacy.d.ts +8 -0
- package/esm/crypter/aes-legacy.js +26 -0
- package/esm/crypter/aes.d.ts +9 -0
- package/esm/crypter/aes.js +25 -0
- package/esm/crypter/rsa-browserify.d.ts +9 -0
- package/esm/crypter/rsa-browserify.js +33 -0
- package/esm/crypter/rsa.d.ts +11 -0
- package/esm/crypter/rsa.js +28 -0
- package/esm/encode.d.ts +8 -0
- package/esm/encode.js +19 -0
- package/esm/hasher/keccak.d.ts +13 -0
- package/esm/hasher/keccak.js +37 -0
- package/esm/hasher/sha2.d.ts +13 -0
- package/esm/hasher/sha2.js +43 -0
- package/esm/hasher/sha3.d.ts +13 -0
- package/esm/hasher/sha3.js +37 -0
- package/esm/index.d.ts +233 -0
- package/esm/index.js +219 -0
- package/esm/protocols/crypter.d.ts +2 -0
- package/esm/protocols/crypter.js +4 -0
- package/esm/protocols/hasher.d.ts +2 -0
- package/esm/protocols/hasher.js +4 -0
- package/esm/protocols/signer.d.ts +2 -0
- package/esm/protocols/signer.js +4 -0
- package/esm/signer/ed25519.d.ts +53 -0
- package/esm/signer/ed25519.js +82 -0
- package/esm/signer/ethereum.d.ts +16 -0
- package/esm/signer/ethereum.js +35 -0
- package/esm/signer/passkey.d.ts +27 -0
- package/esm/signer/passkey.js +59 -0
- package/esm/signer/secp256k1.d.ts +39 -0
- package/esm/signer/secp256k1.js +95 -0
- package/lib/crypter/rsa-browserify.js +1 -1
- package/lib/crypter/rsa.d.ts +0 -1
- package/lib/encode.d.ts +0 -1
- package/lib/encode.js +1 -2
- package/lib/index.d.ts +9 -7
- package/lib/index.js +9 -4
- package/lib/signer/passkey.d.ts +27 -0
- package/lib/signer/passkey.js +65 -0
- package/package.json +29 -14
package/esm/index.js
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import randomBytes from 'randombytes';
|
|
2
|
+
import { encode } from './encode';
|
|
3
|
+
import keccak from './hasher/keccak';
|
|
4
|
+
import sha2 from './hasher/sha2';
|
|
5
|
+
import sha3 from './hasher/sha3';
|
|
6
|
+
import ed25519 from './signer/ed25519';
|
|
7
|
+
import ethereum from './signer/ethereum';
|
|
8
|
+
import secp256k1 from './signer/secp256k1';
|
|
9
|
+
import passkey from './signer/passkey';
|
|
10
|
+
/**
|
|
11
|
+
* Contains all supported signers, eg: `Ed25519` and `Secp256k1`
|
|
12
|
+
*
|
|
13
|
+
* @readonly
|
|
14
|
+
* @type {object}
|
|
15
|
+
* @name Signer
|
|
16
|
+
* @static
|
|
17
|
+
* @example
|
|
18
|
+
* const { Signer } = require('@ocap/mcrypto');
|
|
19
|
+
* const message = 'some message to sign';
|
|
20
|
+
*
|
|
21
|
+
* // Use Signer directly
|
|
22
|
+
* const keyPair = Signer.Ed25519.genKeyPair();
|
|
23
|
+
* const signature = Signer.Ed25519.sign(message, keyPair.secretKey);
|
|
24
|
+
* const result = Signer.Ed25519.verify(message, signature, keyPair.publicKey);
|
|
25
|
+
* assert.ok(result);
|
|
26
|
+
*/
|
|
27
|
+
export const Signer = {
|
|
28
|
+
Ed25519: ed25519,
|
|
29
|
+
Secp256k1: secp256k1,
|
|
30
|
+
Ethereum: ethereum,
|
|
31
|
+
Passkey: passkey,
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Contains all supported hasher, eg: `SHA2`,`SHA3` and `Keccak`, each of them supports `hash224`, `hash256`, `hash384`, `hash512`
|
|
35
|
+
*
|
|
36
|
+
* @readonly
|
|
37
|
+
* @type {object}
|
|
38
|
+
* @name Hasher
|
|
39
|
+
* @static
|
|
40
|
+
* @example
|
|
41
|
+
* const { Hasher } = require('@ocap/mcrypto');
|
|
42
|
+
*
|
|
43
|
+
* const message = 'message to hash';
|
|
44
|
+
* const hash = Hasher.SHA2.hash256(message);
|
|
45
|
+
*/
|
|
46
|
+
export const Hasher = {
|
|
47
|
+
SHA2: sha2,
|
|
48
|
+
SHA3: sha3,
|
|
49
|
+
Keccak: keccak,
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Contains type constants that represent can be used to compose different crypto method, each crypto method consist one of:
|
|
53
|
+
* FIXME: enum definition of forge-abi and abt-did-elixir are not exactly the same
|
|
54
|
+
*
|
|
55
|
+
* @readonly
|
|
56
|
+
* @type {object}
|
|
57
|
+
* @name types
|
|
58
|
+
* @static
|
|
59
|
+
* @example
|
|
60
|
+
* const { types } = require('@ocap/mcrypto');
|
|
61
|
+
*
|
|
62
|
+
* // types.RoleType.ROLE_ACCOUNT
|
|
63
|
+
* // types.KeyType.ED25519
|
|
64
|
+
* // types.HashType.SHA3
|
|
65
|
+
* // types.EncodingType.BASE58
|
|
66
|
+
*/
|
|
67
|
+
export const types = {
|
|
68
|
+
/**
|
|
69
|
+
* Key-pair derivation algorithms
|
|
70
|
+
*
|
|
71
|
+
* @readonly
|
|
72
|
+
* @enum {number}
|
|
73
|
+
* @name types.KeyType
|
|
74
|
+
* @memberof types
|
|
75
|
+
* @static
|
|
76
|
+
*/
|
|
77
|
+
KeyType: {
|
|
78
|
+
ED25519: 0,
|
|
79
|
+
SECP256K1: 1,
|
|
80
|
+
ETHEREUM: 2,
|
|
81
|
+
PASSKEY: 3,
|
|
82
|
+
},
|
|
83
|
+
/**
|
|
84
|
+
* Hashing algorithms
|
|
85
|
+
*
|
|
86
|
+
* @readonly
|
|
87
|
+
* @enum {number}
|
|
88
|
+
* @name types.HashType
|
|
89
|
+
* @memberof types
|
|
90
|
+
* @static
|
|
91
|
+
*/
|
|
92
|
+
HashType: {
|
|
93
|
+
KECCAK: 0,
|
|
94
|
+
SHA3: 1,
|
|
95
|
+
KECCAK_384: 2,
|
|
96
|
+
SHA3_384: 3,
|
|
97
|
+
KECCAK_512: 4,
|
|
98
|
+
SHA3_512: 5,
|
|
99
|
+
SHA2: 6,
|
|
100
|
+
},
|
|
101
|
+
/**
|
|
102
|
+
* DID wallet role type
|
|
103
|
+
*
|
|
104
|
+
* @readonly
|
|
105
|
+
* @enum {number}
|
|
106
|
+
* @name types.RoleType
|
|
107
|
+
* @memberof types
|
|
108
|
+
* @static
|
|
109
|
+
*/
|
|
110
|
+
RoleType: {
|
|
111
|
+
ROLE_ACCOUNT: 0,
|
|
112
|
+
ROLE_NODE: 1,
|
|
113
|
+
ROLE_DEVICE: 2,
|
|
114
|
+
ROLE_APPLICATION: 3,
|
|
115
|
+
ROLE_SMART_CONTRACT: 4,
|
|
116
|
+
ROLE_BOT: 5,
|
|
117
|
+
ROLE_ASSET: 6,
|
|
118
|
+
ROLE_STAKE: 7,
|
|
119
|
+
ROLE_VALIDATOR: 8,
|
|
120
|
+
ROLE_GROUP: 9,
|
|
121
|
+
ROLE_TX: 10,
|
|
122
|
+
ROLE_TETHER: 11,
|
|
123
|
+
ROLE_SWAP: 12,
|
|
124
|
+
ROLE_DELEGATION: 13,
|
|
125
|
+
ROLE_VC: 14,
|
|
126
|
+
ROLE_BLOCKLET: 15,
|
|
127
|
+
ROLE_STORE: 16,
|
|
128
|
+
ROLE_TOKEN: 17,
|
|
129
|
+
ROLE_FACTORY: 18,
|
|
130
|
+
ROLE_ROLLUP: 19,
|
|
131
|
+
ROLE_STORAGE: 20,
|
|
132
|
+
ROLE_PROFILE: 21,
|
|
133
|
+
ROLE_PASSKEY: 22,
|
|
134
|
+
ROLE_ANY: 63,
|
|
135
|
+
},
|
|
136
|
+
/**
|
|
137
|
+
* Address encoding algorithm, defaults to `base58btc`
|
|
138
|
+
*
|
|
139
|
+
* @readonly
|
|
140
|
+
* @enum {number}
|
|
141
|
+
* @name types.RoleType
|
|
142
|
+
* @memberof types
|
|
143
|
+
* @static
|
|
144
|
+
*/
|
|
145
|
+
EncodingType: {
|
|
146
|
+
BASE16: 0,
|
|
147
|
+
BASE58: 1,
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Get signer instance
|
|
152
|
+
*
|
|
153
|
+
* @function
|
|
154
|
+
* @param {number} type - algorithm used to derive key pair, possible values are
|
|
155
|
+
* - types.KeyType.ED25519
|
|
156
|
+
* - types.KeyType.SECP256k1
|
|
157
|
+
* - types.KeyType.ETHEREUM
|
|
158
|
+
* @returns {object} signer instance
|
|
159
|
+
* @example
|
|
160
|
+
* const { getSigner, types } = require('@ocap/mcrypto');
|
|
161
|
+
* const message = 'some message to sign';
|
|
162
|
+
*
|
|
163
|
+
* const signer = getSigner(types.KeyType.ED25519);
|
|
164
|
+
* const keyPair1 = signer.genKeyPair();
|
|
165
|
+
* const signature1 = signer.sign(message, keyPair1.secretKey);
|
|
166
|
+
* const result1 = signer.verify(message, signature1, keyPair1.publicKey);
|
|
167
|
+
* assert.ok(result1);
|
|
168
|
+
*/
|
|
169
|
+
export function getSigner(type) {
|
|
170
|
+
if (typeof Signers[type] === 'undefined') {
|
|
171
|
+
throw new Error(`Unsupported signer type: ${type}`);
|
|
172
|
+
}
|
|
173
|
+
// @ts-ignore
|
|
174
|
+
return Signers[type];
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Get hasher instance
|
|
178
|
+
*
|
|
179
|
+
* @function
|
|
180
|
+
* @param {number} type - algorithm used to hash data, possible values
|
|
181
|
+
* - types.HashType.KECCAK
|
|
182
|
+
* - types.HashType.KECCAK_384
|
|
183
|
+
* - types.HashType.KECCAK_512
|
|
184
|
+
* - types.HashType.SHA3
|
|
185
|
+
* - types.HashType.SHA3_384
|
|
186
|
+
* - types.HashType.SHA3_512
|
|
187
|
+
* @returns {object} hasher instance
|
|
188
|
+
* @example
|
|
189
|
+
* const { getHasher, types } = require('@ocap/mcrypto');
|
|
190
|
+
*
|
|
191
|
+
* const hashFn = getHasher(types.HashType.SHA3);
|
|
192
|
+
* const hash2 = hashFn(message);
|
|
193
|
+
*/
|
|
194
|
+
export function getHasher(type) {
|
|
195
|
+
if (typeof Hashers[type] === 'undefined') {
|
|
196
|
+
throw new Error(`Unsupported hash type: ${type}`);
|
|
197
|
+
}
|
|
198
|
+
// @ts-ignore
|
|
199
|
+
return Hashers[type];
|
|
200
|
+
}
|
|
201
|
+
export function getRandomBytes(length = 32, encoding = 'hex') {
|
|
202
|
+
return encode(randomBytes(length), encoding);
|
|
203
|
+
}
|
|
204
|
+
export const Signers = Object.freeze({
|
|
205
|
+
[types.KeyType.ED25519]: Signer.Ed25519,
|
|
206
|
+
[types.KeyType.SECP256K1]: Signer.Secp256k1,
|
|
207
|
+
[types.KeyType.ETHEREUM]: Signer.Ethereum,
|
|
208
|
+
[types.KeyType.PASSKEY]: Signer.Passkey,
|
|
209
|
+
});
|
|
210
|
+
export const Hashers = Object.freeze({
|
|
211
|
+
[types.HashType.KECCAK]: Hasher.Keccak.hash256,
|
|
212
|
+
[types.HashType.KECCAK_384]: Hasher.Keccak.hash384,
|
|
213
|
+
[types.HashType.KECCAK_512]: Hasher.Keccak.hash512,
|
|
214
|
+
[types.HashType.SHA3]: Hasher.SHA3.hash256,
|
|
215
|
+
[types.HashType.SHA3_384]: Hasher.SHA3.hash384,
|
|
216
|
+
[types.HashType.SHA3_512]: Hasher.SHA3.hash512,
|
|
217
|
+
[types.HashType.SHA2]: Hasher.SHA2.hash256,
|
|
218
|
+
});
|
|
219
|
+
export const toTxHash = (buf) => Hasher.SHA2.hash256(buf, 1, 'hex').replace(/^0x/, '').toUpperCase();
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { BytesType, EncodingType, KeyPairType } from '@ocap/util';
|
|
2
|
+
import BaseSigner from '../protocols/signer';
|
|
3
|
+
/**
|
|
4
|
+
* Signer implementation for ed25519, based on `tweetnacl`
|
|
5
|
+
*
|
|
6
|
+
* @class Ed25519Signer
|
|
7
|
+
*/
|
|
8
|
+
declare class Ed25519Signer extends BaseSigner {
|
|
9
|
+
constructor();
|
|
10
|
+
/**
|
|
11
|
+
* @public
|
|
12
|
+
* @typedefKeyPairType
|
|
13
|
+
* @prop {string} publicKey - publicKey in hex format
|
|
14
|
+
* @prop {string} secretKey - secretKey in hex format
|
|
15
|
+
* @memberof Ed25519Signer
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Generate random secret/public key pair
|
|
19
|
+
*
|
|
20
|
+
* @param {Buffer|Uint8Array} [userSeed=undefined]
|
|
21
|
+
* @param {string} [encoding='hex']
|
|
22
|
+
* @returns {KeyPairType}
|
|
23
|
+
* @memberof Ed25519Signer
|
|
24
|
+
*/
|
|
25
|
+
genKeyPair(encoding?: EncodingType, userSeed?: BytesType): KeyPairType;
|
|
26
|
+
/**
|
|
27
|
+
* Get publicKey from secretKey
|
|
28
|
+
*
|
|
29
|
+
* @param {hex|buffer|base58|Uint8Array} sk - can be either a hex encoded string or a buffer
|
|
30
|
+
* @returns {string} hex encoded publicKey
|
|
31
|
+
*/
|
|
32
|
+
getPublicKey(sk: BytesType, encoding?: EncodingType): BytesType;
|
|
33
|
+
/**
|
|
34
|
+
* Sign a message and get the signature hex
|
|
35
|
+
*
|
|
36
|
+
* @param {hex|base58|buffer|Uint8Array} message
|
|
37
|
+
* @param {hex|base58|buffer|Uint8Array} sk
|
|
38
|
+
* @returns {string} hex encoded signature
|
|
39
|
+
*/
|
|
40
|
+
sign(message: BytesType, sk: BytesType, encoding?: EncodingType): BytesType;
|
|
41
|
+
/**
|
|
42
|
+
* Verify if a signature is valid
|
|
43
|
+
*
|
|
44
|
+
* @param {string|buffer} message
|
|
45
|
+
* @param {string|buffer} signature
|
|
46
|
+
* @param {string|buffer} pk
|
|
47
|
+
* @returns {bool}
|
|
48
|
+
*/
|
|
49
|
+
verify(message: BytesType, signature: BytesType, pk: BytesType): boolean;
|
|
50
|
+
}
|
|
51
|
+
declare const _default: Ed25519Signer;
|
|
52
|
+
export default _default;
|
|
53
|
+
export { Ed25519Signer };
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-useless-constructor */
|
|
2
|
+
import tweetnacl from 'tweetnacl';
|
|
3
|
+
import randomBytes from 'randombytes';
|
|
4
|
+
import { toUint8Array } from '@ocap/util';
|
|
5
|
+
import BaseSigner from '../protocols/signer';
|
|
6
|
+
import { encode } from '../encode';
|
|
7
|
+
const ed25519 = tweetnacl.sign;
|
|
8
|
+
/**
|
|
9
|
+
* Signer implementation for ed25519, based on `tweetnacl`
|
|
10
|
+
*
|
|
11
|
+
* @class Ed25519Signer
|
|
12
|
+
*/
|
|
13
|
+
class Ed25519Signer extends BaseSigner {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* @public
|
|
19
|
+
* @typedefKeyPairType
|
|
20
|
+
* @prop {string} publicKey - publicKey in hex format
|
|
21
|
+
* @prop {string} secretKey - secretKey in hex format
|
|
22
|
+
* @memberof Ed25519Signer
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Generate random secret/public key pair
|
|
26
|
+
*
|
|
27
|
+
* @param {Buffer|Uint8Array} [userSeed=undefined]
|
|
28
|
+
* @param {string} [encoding='hex']
|
|
29
|
+
* @returns {KeyPairType}
|
|
30
|
+
* @memberof Ed25519Signer
|
|
31
|
+
*/
|
|
32
|
+
genKeyPair(encoding = 'hex', userSeed) {
|
|
33
|
+
const seed = userSeed ? toUint8Array(userSeed) : new Uint8Array(randomBytes(32));
|
|
34
|
+
if (seed.byteLength !== 32) {
|
|
35
|
+
throw new Error('Invalid seed to generate key pair');
|
|
36
|
+
}
|
|
37
|
+
const keyPair = ed25519.keyPair.fromSeed(seed);
|
|
38
|
+
keyPair.publicKey = encode(keyPair.publicKey, encoding);
|
|
39
|
+
keyPair.secretKey = encode(keyPair.secretKey, encoding);
|
|
40
|
+
return keyPair;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get publicKey from secretKey
|
|
44
|
+
*
|
|
45
|
+
* @param {hex|buffer|base58|Uint8Array} sk - can be either a hex encoded string or a buffer
|
|
46
|
+
* @returns {string} hex encoded publicKey
|
|
47
|
+
*/
|
|
48
|
+
getPublicKey(sk, encoding = 'hex') {
|
|
49
|
+
const skBytes = toUint8Array(sk);
|
|
50
|
+
const pk = ed25519.keyPair.fromSecretKey(skBytes).publicKey;
|
|
51
|
+
return encode(pk, encoding);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Sign a message and get the signature hex
|
|
55
|
+
*
|
|
56
|
+
* @param {hex|base58|buffer|Uint8Array} message
|
|
57
|
+
* @param {hex|base58|buffer|Uint8Array} sk
|
|
58
|
+
* @returns {string} hex encoded signature
|
|
59
|
+
*/
|
|
60
|
+
sign(message, sk, encoding = 'hex') {
|
|
61
|
+
const skBytes = toUint8Array(sk);
|
|
62
|
+
const messageBytes = toUint8Array(message);
|
|
63
|
+
const signature = ed25519.detached(messageBytes, skBytes);
|
|
64
|
+
return encode(signature, encoding);
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Verify if a signature is valid
|
|
68
|
+
*
|
|
69
|
+
* @param {string|buffer} message
|
|
70
|
+
* @param {string|buffer} signature
|
|
71
|
+
* @param {string|buffer} pk
|
|
72
|
+
* @returns {bool}
|
|
73
|
+
*/
|
|
74
|
+
verify(message, signature, pk) {
|
|
75
|
+
const pkBytes = toUint8Array(pk);
|
|
76
|
+
const messageBytes = toUint8Array(message);
|
|
77
|
+
const signatureBytes = toUint8Array(signature);
|
|
78
|
+
return ed25519.detached.verify(messageBytes, signatureBytes, pkBytes);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export default new Ed25519Signer();
|
|
82
|
+
export { Ed25519Signer };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Secp256k1Signer } from './secp256k1';
|
|
2
|
+
/**
|
|
3
|
+
* Signer implementation for secp256k1, based on `elliptic`, and ethereum compatible
|
|
4
|
+
*
|
|
5
|
+
* @class EthereumSigner
|
|
6
|
+
*/
|
|
7
|
+
declare class EthereumSigner extends Secp256k1Signer {
|
|
8
|
+
pkHasFormatPrefix: boolean;
|
|
9
|
+
constructor();
|
|
10
|
+
ethHash(data: string): string;
|
|
11
|
+
ethSign(data: string, privateKey: string): string;
|
|
12
|
+
ethRecover(data: string, signature: string): string;
|
|
13
|
+
}
|
|
14
|
+
declare const _default: EthereumSigner;
|
|
15
|
+
export default _default;
|
|
16
|
+
export { EthereumSigner };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
|
2
|
+
// @ts-ignore
|
|
3
|
+
import Account from 'eth-lib/lib/account';
|
|
4
|
+
// @ts-ignore
|
|
5
|
+
import Hash from 'eth-lib/lib/hash';
|
|
6
|
+
import { isHexStrict, utf8ToHex, hexToBytes } from '@ocap/util';
|
|
7
|
+
import { Secp256k1Signer } from './secp256k1';
|
|
8
|
+
/**
|
|
9
|
+
* Signer implementation for secp256k1, based on `elliptic`, and ethereum compatible
|
|
10
|
+
*
|
|
11
|
+
* @class EthereumSigner
|
|
12
|
+
*/
|
|
13
|
+
class EthereumSigner extends Secp256k1Signer {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.pkHasFormatPrefix = false;
|
|
17
|
+
}
|
|
18
|
+
ethHash(data) {
|
|
19
|
+
const messageHex = isHexStrict(data) ? data : utf8ToHex(data);
|
|
20
|
+
const messageBytes = hexToBytes(messageHex);
|
|
21
|
+
const messageBuffer = Buffer.from(messageBytes);
|
|
22
|
+
const preamble = `\x19Ethereum Signed Message:\n${messageBytes.length}`;
|
|
23
|
+
const preambleBuffer = Buffer.from(preamble);
|
|
24
|
+
const ethMessage = Buffer.concat([preambleBuffer, messageBuffer]);
|
|
25
|
+
return Hash.keccak256s(ethMessage);
|
|
26
|
+
}
|
|
27
|
+
ethSign(data, privateKey) {
|
|
28
|
+
return Account.sign(data, privateKey);
|
|
29
|
+
}
|
|
30
|
+
ethRecover(data, signature) {
|
|
31
|
+
return Account.recover(data, signature);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export default new EthereumSigner();
|
|
35
|
+
export { EthereumSigner };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { BytesType, EncodingType, KeyPairType } from '@ocap/util';
|
|
2
|
+
import BaseSigner from '../protocols/signer';
|
|
3
|
+
/**
|
|
4
|
+
* Signer implementation for passkey, based on `@simplewebauthn/server`
|
|
5
|
+
* Since passkey supports only verification, we do not need to implement the sign method
|
|
6
|
+
* And passkeys can used multiple algorithms, we do not need to implement the algorithm selection
|
|
7
|
+
*
|
|
8
|
+
* @class PasskeySigner
|
|
9
|
+
*/
|
|
10
|
+
declare class PasskeySigner extends BaseSigner {
|
|
11
|
+
constructor();
|
|
12
|
+
genKeyPair(encoding?: EncodingType, userSeed?: BytesType): KeyPairType;
|
|
13
|
+
getPublicKey(sk: BytesType, encoding?: EncodingType): BytesType;
|
|
14
|
+
sign(message: BytesType, sk: BytesType, encoding?: EncodingType): BytesType;
|
|
15
|
+
/**
|
|
16
|
+
* Verify if a signature is valid
|
|
17
|
+
*
|
|
18
|
+
* @param {string|buffer} challenge - the challenge sent to passkey, should be txHash when signing a transaction
|
|
19
|
+
* @param {string|buffer} signature - signature from passkey
|
|
20
|
+
* @param {string|buffer} pk - credentialPublicKey from passkey, must be parsed with `parseAuthenticatorData`
|
|
21
|
+
* @returns {bool}
|
|
22
|
+
*/
|
|
23
|
+
verify(challenge: BytesType, signature: BytesType, pk: BytesType, extra: string): Promise<boolean>;
|
|
24
|
+
}
|
|
25
|
+
declare const _default: PasskeySigner;
|
|
26
|
+
export default _default;
|
|
27
|
+
export { PasskeySigner };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-useless-constructor */
|
|
2
|
+
import { toBuffer, fromBase64, toBase64 } from '@ocap/util';
|
|
3
|
+
import { decodeClientDataJSON, isoBase64URL, isoUint8Array, toHash, verifySignature, } from '@simplewebauthn/server/helpers';
|
|
4
|
+
import BaseSigner from '../protocols/signer';
|
|
5
|
+
/**
|
|
6
|
+
* Signer implementation for passkey, based on `@simplewebauthn/server`
|
|
7
|
+
* Since passkey supports only verification, we do not need to implement the sign method
|
|
8
|
+
* And passkeys can used multiple algorithms, we do not need to implement the algorithm selection
|
|
9
|
+
*
|
|
10
|
+
* @class PasskeySigner
|
|
11
|
+
*/
|
|
12
|
+
class PasskeySigner extends BaseSigner {
|
|
13
|
+
constructor() {
|
|
14
|
+
super();
|
|
15
|
+
}
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
17
|
+
genKeyPair(encoding = 'hex', userSeed) {
|
|
18
|
+
throw new Error('Not supported');
|
|
19
|
+
}
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
21
|
+
getPublicKey(sk, encoding = 'hex') {
|
|
22
|
+
throw new Error('Not supported');
|
|
23
|
+
}
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
25
|
+
sign(message, sk, encoding = 'hex') {
|
|
26
|
+
throw new Error('Not supported');
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Verify if a signature is valid
|
|
30
|
+
*
|
|
31
|
+
* @param {string|buffer} challenge - the challenge sent to passkey, should be txHash when signing a transaction
|
|
32
|
+
* @param {string|buffer} signature - signature from passkey
|
|
33
|
+
* @param {string|buffer} pk - credentialPublicKey from passkey, must be parsed with `parseAuthenticatorData`
|
|
34
|
+
* @returns {bool}
|
|
35
|
+
*/
|
|
36
|
+
async verify(challenge, signature, pk, extra) {
|
|
37
|
+
const parsed = JSON.parse(extra);
|
|
38
|
+
if (!parsed.authenticatorData || !parsed.clientDataJSON) {
|
|
39
|
+
throw new Error('extra.authenticatorData or extra.clientDataJSON is required for passkey signature verification');
|
|
40
|
+
}
|
|
41
|
+
const authDataBuffer = toBuffer(fromBase64(parsed.authenticatorData));
|
|
42
|
+
const clientDataHash = await toHash(isoBase64URL.toBuffer(parsed.clientDataJSON));
|
|
43
|
+
const clientData = decodeClientDataJSON(parsed.clientDataJSON);
|
|
44
|
+
if (clientData.challenge !== toBase64(challenge)) {
|
|
45
|
+
throw new Error('challenge mismatch for passkey signature');
|
|
46
|
+
}
|
|
47
|
+
// FIXME: @wangshijun add more check here
|
|
48
|
+
// if (clientData.type !== 'ocap.tx.sign') {
|
|
49
|
+
// throw new Error('Invalid client data type');
|
|
50
|
+
// }
|
|
51
|
+
return verifySignature({
|
|
52
|
+
signature: isoBase64URL.toBuffer(typeof signature === 'string' ? signature : toBase64(signature)),
|
|
53
|
+
data: isoUint8Array.concat([authDataBuffer, clientDataHash]),
|
|
54
|
+
credentialPublicKey: pk,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
export default new PasskeySigner();
|
|
59
|
+
export { PasskeySigner };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { BytesType, KeyPairType, EncodingType } from '@ocap/util';
|
|
2
|
+
import Signer from '../protocols/signer';
|
|
3
|
+
/**
|
|
4
|
+
* Signer implementation for secp256k1, based on `elliptic`
|
|
5
|
+
*
|
|
6
|
+
* @class Secp256k1Signer
|
|
7
|
+
*/
|
|
8
|
+
declare class Secp256k1Signer extends Signer {
|
|
9
|
+
pkCompressed: boolean;
|
|
10
|
+
pkHasFormatPrefix: boolean;
|
|
11
|
+
constructor();
|
|
12
|
+
isValidSK(sk: Uint8Array): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* @public
|
|
15
|
+
* @typedefKeyPairType
|
|
16
|
+
* @prop {string} publicKey - publicKey in hex format
|
|
17
|
+
* @prop {string} secretKey - secretKey in hex format
|
|
18
|
+
* @memberof Secp256k1Signer
|
|
19
|
+
*/
|
|
20
|
+
/**
|
|
21
|
+
* Generate random secret/public key pair
|
|
22
|
+
*/
|
|
23
|
+
genKeyPair(encoding?: EncodingType): KeyPairType;
|
|
24
|
+
/**
|
|
25
|
+
* Get publicKey from secretKey
|
|
26
|
+
*/
|
|
27
|
+
getPublicKey(sk: BytesType, encoding?: EncodingType): BytesType;
|
|
28
|
+
/**
|
|
29
|
+
* Sign a message and get the signature hex
|
|
30
|
+
*/
|
|
31
|
+
sign(message: BytesType, sk: BytesType, encoding?: EncodingType): BytesType;
|
|
32
|
+
/**
|
|
33
|
+
* Verify if a signature is valid
|
|
34
|
+
*/
|
|
35
|
+
verify(message: BytesType, signature: BytesType, pk: BytesType): boolean;
|
|
36
|
+
}
|
|
37
|
+
declare const _default: Secp256k1Signer;
|
|
38
|
+
export default _default;
|
|
39
|
+
export { Secp256k1Signer };
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import elliptic from 'elliptic';
|
|
2
|
+
import { BN, stripHexPrefix, toHex, toBuffer, toUint8Array } from '@ocap/util';
|
|
3
|
+
import randomBytes from 'randombytes';
|
|
4
|
+
import Signer from '../protocols/signer';
|
|
5
|
+
import { encode } from '../encode';
|
|
6
|
+
/* eslint-disable class-methods-use-this */
|
|
7
|
+
/* eslint-disable no-useless-constructor */
|
|
8
|
+
const EC = elliptic.ec;
|
|
9
|
+
const secp256k1 = new EC('secp256k1');
|
|
10
|
+
/**
|
|
11
|
+
* Signer implementation for secp256k1, based on `elliptic`
|
|
12
|
+
*
|
|
13
|
+
* @class Secp256k1Signer
|
|
14
|
+
*/
|
|
15
|
+
class Secp256k1Signer extends Signer {
|
|
16
|
+
constructor() {
|
|
17
|
+
super();
|
|
18
|
+
this.pkHasFormatPrefix = true;
|
|
19
|
+
this.pkCompressed = false;
|
|
20
|
+
}
|
|
21
|
+
isValidSK(sk) {
|
|
22
|
+
if (sk.byteLength !== 32) {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
const bn = new BN(sk);
|
|
26
|
+
return bn.cmp(secp256k1.curve.n) < 0 && !bn.isZero();
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* @public
|
|
30
|
+
* @typedefKeyPairType
|
|
31
|
+
* @prop {string} publicKey - publicKey in hex format
|
|
32
|
+
* @prop {string} secretKey - secretKey in hex format
|
|
33
|
+
* @memberof Secp256k1Signer
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Generate random secret/public key pair
|
|
37
|
+
*/
|
|
38
|
+
genKeyPair(encoding = 'hex') {
|
|
39
|
+
let sk = null;
|
|
40
|
+
do {
|
|
41
|
+
sk = new Uint8Array(randomBytes(32));
|
|
42
|
+
} while (!this.isValidSK(sk));
|
|
43
|
+
const pk = this.getPublicKey(toHex(sk));
|
|
44
|
+
return { secretKey: encode(sk, encoding), publicKey: encode(pk, encoding) };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Get publicKey from secretKey
|
|
48
|
+
*/
|
|
49
|
+
getPublicKey(sk, encoding = 'hex') {
|
|
50
|
+
if (!this.isValidSK(toUint8Array(sk))) {
|
|
51
|
+
throw new Error('Invalid secret key');
|
|
52
|
+
}
|
|
53
|
+
let pk = secp256k1.keyFromPrivate(toBuffer(sk)).getPublic(this.pkCompressed, 'hex');
|
|
54
|
+
if (this.pkHasFormatPrefix === false) {
|
|
55
|
+
pk = pk.slice(2);
|
|
56
|
+
}
|
|
57
|
+
return encode(`0x${pk}`, encoding);
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Sign a message and get the signature hex
|
|
61
|
+
*/
|
|
62
|
+
sign(message, sk, encoding = 'hex') {
|
|
63
|
+
let msg = message;
|
|
64
|
+
try {
|
|
65
|
+
msg = toUint8Array(message);
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
// Do nothing;
|
|
69
|
+
}
|
|
70
|
+
const signature = secp256k1
|
|
71
|
+
.keyFromPrivate(toBuffer(sk))
|
|
72
|
+
.sign(stripHexPrefix(msg), { canonical: true })
|
|
73
|
+
.toDER('hex');
|
|
74
|
+
return encode(`0x${signature}`, encoding);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Verify if a signature is valid
|
|
78
|
+
*/
|
|
79
|
+
verify(message, signature, pk) {
|
|
80
|
+
let msg = message;
|
|
81
|
+
try {
|
|
82
|
+
msg = toUint8Array(message);
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
// Do nothing;
|
|
86
|
+
}
|
|
87
|
+
let pkBuffer = toBuffer(pk);
|
|
88
|
+
if (this.pkHasFormatPrefix === false && pkBuffer[0] !== 0x04 && pkBuffer.byteLength === 64) {
|
|
89
|
+
pkBuffer = Buffer.concat([Buffer.from([0x04]), pkBuffer]);
|
|
90
|
+
}
|
|
91
|
+
return secp256k1.keyFromPublic(pkBuffer).verify(stripHexPrefix(msg), stripHexPrefix(toHex(signature)));
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export default new Secp256k1Signer();
|
|
95
|
+
export { Secp256k1Signer };
|
|
@@ -10,7 +10,7 @@ const ab2str = (buffer) => String.fromCharCode.apply(null, new Uint8Array(buffer
|
|
|
10
10
|
const RSA_ALGORITHM = 'RSA-OAEP';
|
|
11
11
|
// RSA-OAEP
|
|
12
12
|
class RSABrowserCrypter {
|
|
13
|
-
|
|
13
|
+
genKeyPair(length = 2048) {
|
|
14
14
|
return crypto.generateKey({
|
|
15
15
|
name: RSA_ALGORITHM,
|
|
16
16
|
modulusLength: length,
|
package/lib/crypter/rsa.d.ts
CHANGED
package/lib/encode.d.ts
CHANGED