sm-crypto-v2 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/index.d.mts +175 -0
- package/dist/index.d.ts +18 -47
- package/dist/index.js +13 -0
- package/dist/index.mjs +9 -0
- package/miniprogram_dist/index.d.ts +175 -0
- package/miniprogram_dist/index.js +3780 -0
- package/package.json +8 -4
- package/{tsup.config.ts → tsup.config.miniprogram.ts} +9 -4
- package/src/index.ts +0 -3
- package/src/sm2/asn1.ts +0 -210
- package/src/sm2/bn.ts +0 -4
- package/src/sm2/ec.ts +0 -24
- package/src/sm2/hmac.ts +0 -76
- package/src/sm2/index.ts +0 -319
- package/src/sm2/kx.ts +0 -83
- package/src/sm2/rng.ts +0 -77
- package/src/sm2/sm3.ts +0 -241
- package/src/sm2/utils.ts +0 -164
- package/src/sm3/index.ts +0 -72
- package/src/sm3/utils.ts +0 -117
- package/src/sm4/_slow.ts +0 -286
- package/src/sm4/index.ts +0 -322
- package/tsconfig.json +0 -21
- package/vitest.config.ts +0 -22
- package/webpack.config.js +0 -26
package/package.json
CHANGED
@@ -1,17 +1,20 @@
|
|
1
1
|
{
|
2
2
|
"name": "sm-crypto-v2",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.9.0",
|
4
4
|
"description": "sm-crypto-v2",
|
5
5
|
"main": "dist/index.js",
|
6
6
|
"module": "dist/index.mjs",
|
7
|
+
"miniprogram": "miniprogram_dist",
|
7
8
|
"types": "dist/index.d.ts",
|
8
9
|
"scripts": {
|
9
10
|
"prepublish": "npm run build",
|
10
11
|
"lint": "eslint \"src/**/*.js\" --fix",
|
11
|
-
"
|
12
|
+
"prerelease": "vitest run && npm run build && npm run build-mp",
|
13
|
+
"build": "tsup",
|
14
|
+
"build-mp": "tsup --config=tsup.config.miniprogram.ts",
|
12
15
|
"watch": "tsup --watch",
|
13
16
|
"test": "vitest",
|
14
|
-
"release": "npm run
|
17
|
+
"release": "npm run prerelease && standard-version && git push --follow-tags origin master",
|
15
18
|
"coverage": "vitest run --coverage"
|
16
19
|
},
|
17
20
|
"repository": {
|
@@ -44,12 +47,13 @@
|
|
44
47
|
"@vitest/runner": "^0.33.0",
|
45
48
|
"@vitest/ui": "^0.31.0",
|
46
49
|
"conventional-changelog-cli": "^2.2.2",
|
50
|
+
"esbuild": "^0.19.10",
|
47
51
|
"eslint": "^8.15.0",
|
48
52
|
"eslint-config-prettier": "^8.3.0",
|
49
53
|
"eslint-plugin-prettier": "^4.0.0",
|
50
54
|
"prettier": "^2.6.2",
|
51
55
|
"standard-version": "^9.5.0",
|
52
|
-
"tsup": "^
|
56
|
+
"tsup": "^8.0.1",
|
53
57
|
"typescript": "^4.7.2",
|
54
58
|
"vite": "^4.3.9",
|
55
59
|
"vitest": "^0.31.0"
|
@@ -3,15 +3,20 @@ import { defineConfig } from 'tsup';
|
|
3
3
|
export default defineConfig({
|
4
4
|
entry: ['./src/index.ts'],
|
5
5
|
clean: true,
|
6
|
-
outDir: '
|
6
|
+
outDir: 'miniprogram_dist',
|
7
7
|
dts: true,
|
8
8
|
// we need to keep minify false, since webpack magic comments
|
9
9
|
// will be stripped if minify.
|
10
10
|
minify: false,
|
11
|
-
format: ['
|
12
|
-
target: '
|
11
|
+
format: ['cjs'],
|
12
|
+
target: 'es5',
|
13
|
+
noExternal: ['@noble/curves'],
|
13
14
|
tsconfig: 'tsconfig.json',
|
14
15
|
esbuildOptions(options) {
|
15
|
-
options.define.__BUILD_TS__ = Date.now();
|
16
|
+
options.define.__BUILD_TS__ = Date.now().toString();
|
17
|
+
options.define.import = 'require';
|
18
|
+
options.supported = {
|
19
|
+
'dynamic-import': false,
|
20
|
+
}
|
16
21
|
}
|
17
22
|
});
|
package/src/index.ts
DELETED
package/src/sm2/asn1.ts
DELETED
@@ -1,210 +0,0 @@
|
|
1
|
-
/* eslint-disable class-methods-use-this */
|
2
|
-
|
3
|
-
import * as utils from '@noble/curves/abstract/utils';
|
4
|
-
import { ONE } from './bn';
|
5
|
-
import { utf8ToHex } from './utils';
|
6
|
-
|
7
|
-
export function bigintToValue(bigint: bigint) {
|
8
|
-
let h = bigint.toString(16)
|
9
|
-
if (h[0] !== '-') {
|
10
|
-
// 正数
|
11
|
-
if (h.length % 2 === 1) h = '0' + h // 补齐到整字节
|
12
|
-
else if (!h.match(/^[0-7]/)) h = '00' + h // 非0开头,则补一个全0字节
|
13
|
-
} else {
|
14
|
-
// 负数
|
15
|
-
h = h.substring(1)
|
16
|
-
let len = h.length
|
17
|
-
if (len % 2 === 1) len += 1 // 补齐到整字节
|
18
|
-
else if (!h.match(/^[0-7]/)) len += 2 // 非0开头,则补一个全0字节
|
19
|
-
|
20
|
-
let maskString = ''
|
21
|
-
for (let i = 0; i < len; i++) maskString += 'f'
|
22
|
-
let mask = utils.hexToNumber(maskString)
|
23
|
-
|
24
|
-
// 对绝对值取反,加1
|
25
|
-
|
26
|
-
let output = (mask ^ bigint) + ONE
|
27
|
-
h = output.toString(16).replace(/^-/, '')
|
28
|
-
}
|
29
|
-
return h
|
30
|
-
}
|
31
|
-
|
32
|
-
class ASN1Object {
|
33
|
-
constructor(
|
34
|
-
public tlv: string | null = null,
|
35
|
-
public t = '00',
|
36
|
-
public l = '00',
|
37
|
-
public v = ''
|
38
|
-
) { }
|
39
|
-
|
40
|
-
/**
|
41
|
-
* 获取 der 编码比特流16进制串
|
42
|
-
*/
|
43
|
-
getEncodedHex() {
|
44
|
-
if (!this.tlv) {
|
45
|
-
this.v = this.getValue()
|
46
|
-
this.l = this.getLength()
|
47
|
-
this.tlv = this.t + this.l + this.v
|
48
|
-
}
|
49
|
-
return this.tlv
|
50
|
-
}
|
51
|
-
|
52
|
-
getLength() {
|
53
|
-
const n = this.v.length / 2 // 字节数
|
54
|
-
let nHex = n.toString(16)
|
55
|
-
if (nHex.length % 2 === 1) nHex = '0' + nHex // 补齐到整字节
|
56
|
-
|
57
|
-
if (n < 128) {
|
58
|
-
// 短格式,以 0 开头
|
59
|
-
return nHex
|
60
|
-
} else {
|
61
|
-
// 长格式,以 1 开头
|
62
|
-
const head = 128 + nHex.length / 2 // 1(1位) + 真正的长度占用字节数(7位) + 真正的长度
|
63
|
-
return head.toString(16) + nHex
|
64
|
-
}
|
65
|
-
}
|
66
|
-
|
67
|
-
getValue() {
|
68
|
-
return ''
|
69
|
-
}
|
70
|
-
}
|
71
|
-
|
72
|
-
class DERInteger extends ASN1Object {
|
73
|
-
constructor(bigint: bigint) {
|
74
|
-
super()
|
75
|
-
|
76
|
-
this.t = '02' // 整型标签说明
|
77
|
-
if (bigint) this.v = bigintToValue(bigint)
|
78
|
-
}
|
79
|
-
|
80
|
-
getValue() {
|
81
|
-
return this.v
|
82
|
-
}
|
83
|
-
}
|
84
|
-
|
85
|
-
class DEROctetString extends ASN1Object {
|
86
|
-
public hV: string = ''
|
87
|
-
constructor(public s: string) {
|
88
|
-
super()
|
89
|
-
|
90
|
-
this.t = '04' // octstr 标签说明
|
91
|
-
if (s) this.v = s.toLowerCase()
|
92
|
-
}
|
93
|
-
|
94
|
-
getValue() {
|
95
|
-
return this.v
|
96
|
-
}
|
97
|
-
}
|
98
|
-
|
99
|
-
class DERSequence extends ASN1Object {
|
100
|
-
public t = '30'
|
101
|
-
constructor(public asn1Array: ASN1Object[]) {
|
102
|
-
super()
|
103
|
-
}
|
104
|
-
|
105
|
-
getValue() {
|
106
|
-
this.v = this.asn1Array.map(asn1Object => asn1Object.getEncodedHex()).join('')
|
107
|
-
return this.v
|
108
|
-
}
|
109
|
-
}
|
110
|
-
|
111
|
-
/**
|
112
|
-
* 获取 l 占用字节数
|
113
|
-
*/
|
114
|
-
function getLenOfL(str: string, start: number) {
|
115
|
-
if (+str[start + 2] < 8) return 1 // l 以0开头,则表示短格式,只占一个字节
|
116
|
-
return +str.substring(start + 2, start + 4) & 0x7f + 1 // 长格式,取第一个字节后7位作为长度真正占用字节数,再加上本身
|
117
|
-
}
|
118
|
-
|
119
|
-
/**
|
120
|
-
* 获取 l
|
121
|
-
*/
|
122
|
-
function getL(str: string, start: number) {
|
123
|
-
// 获取 l
|
124
|
-
const len = getLenOfL(str, start)
|
125
|
-
const l = str.substring(start + 2, start + 2 + len * 2)
|
126
|
-
|
127
|
-
if (!l) return -1
|
128
|
-
const bigint = +l[0] < 8 ? utils.hexToNumber(l): utils.hexToNumber(l.substring(2))
|
129
|
-
|
130
|
-
return +bigint.toString()
|
131
|
-
}
|
132
|
-
|
133
|
-
/**
|
134
|
-
* 获取 v 的位置
|
135
|
-
*/
|
136
|
-
function getStartOfV(str: string, start: number) {
|
137
|
-
const len = getLenOfL(str, start)
|
138
|
-
return start + (len + 1) * 2
|
139
|
-
}
|
140
|
-
|
141
|
-
/**
|
142
|
-
* ASN.1 der 编码,针对 sm2 签名
|
143
|
-
*/
|
144
|
-
export function encodeDer(r: bigint, s: bigint) {
|
145
|
-
const derR = new DERInteger(r)
|
146
|
-
const derS = new DERInteger(s)
|
147
|
-
const derSeq = new DERSequence([derR, derS])
|
148
|
-
|
149
|
-
return derSeq.getEncodedHex()
|
150
|
-
}
|
151
|
-
|
152
|
-
export function encodeEnc(x: bigint, y: bigint, hash: string, cipher: string) {
|
153
|
-
const derX = new DERInteger(x)
|
154
|
-
const derY = new DERInteger(y)
|
155
|
-
const derHash = new DEROctetString(hash)
|
156
|
-
const derCipher = new DEROctetString(cipher)
|
157
|
-
const derSeq = new DERSequence([derX, derY, derHash, derCipher])
|
158
|
-
return derSeq.getEncodedHex()
|
159
|
-
}
|
160
|
-
/**
|
161
|
-
* 解析 ASN.1 der,针对 sm2 验签
|
162
|
-
*/
|
163
|
-
export function decodeDer(input: string) {
|
164
|
-
// 结构:
|
165
|
-
// input = | tSeq | lSeq | vSeq |
|
166
|
-
// vSeq = | tR | lR | vR | tS | lS | vS |
|
167
|
-
const start = getStartOfV(input, 0)
|
168
|
-
|
169
|
-
const vIndexR = getStartOfV(input, start)
|
170
|
-
const lR = getL(input, start)
|
171
|
-
const vR = input.substring(vIndexR, vIndexR +lR * 2)
|
172
|
-
|
173
|
-
const nextStart = vIndexR + vR.length
|
174
|
-
const vIndexS = getStartOfV(input, nextStart)
|
175
|
-
const lS = getL(input, nextStart)
|
176
|
-
const vS = input.substring(vIndexS, vIndexS + lS * 2)
|
177
|
-
|
178
|
-
// const r = new BigInteger(vR, 16)
|
179
|
-
// const s = new BigInteger(vS, 16)
|
180
|
-
const r = utils.hexToNumber(vR)
|
181
|
-
const s = utils.hexToNumber(vS)
|
182
|
-
|
183
|
-
return { r, s }
|
184
|
-
}
|
185
|
-
|
186
|
-
/**
|
187
|
-
* 解析 ASN.1 der,针对 sm2 加密
|
188
|
-
*/
|
189
|
-
export function decodeEnc(input: string) {
|
190
|
-
// Extracts a sequence from the input based on the current start index.
|
191
|
-
function extractSequence(input: string, start: number): { value: string; nextStart: number } {
|
192
|
-
const vIndex = getStartOfV(input, start);
|
193
|
-
const length = getL(input, start);
|
194
|
-
const value = input.substring(vIndex, vIndex + length * 2);
|
195
|
-
const nextStart = vIndex + value.length;
|
196
|
-
return { value, nextStart };
|
197
|
-
}
|
198
|
-
|
199
|
-
const start = getStartOfV(input, 0);
|
200
|
-
|
201
|
-
const { value: vR, nextStart: startS } = extractSequence(input, start);
|
202
|
-
const { value: vS, nextStart: startHash } = extractSequence(input, startS);
|
203
|
-
const { value: hash, nextStart: startCipher } = extractSequence(input, startHash);
|
204
|
-
const { value: cipher } = extractSequence(input, startCipher);
|
205
|
-
|
206
|
-
const x = utils.hexToNumber(vR);
|
207
|
-
const y = utils.hexToNumber(vS);
|
208
|
-
|
209
|
-
return { x, y, hash, cipher };
|
210
|
-
}
|
package/src/sm2/bn.ts
DELETED
package/src/sm2/ec.ts
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
import { weierstrass } from '@noble/curves/abstract/weierstrass';
|
2
|
-
import { Field } from '@noble/curves/abstract/modular'; // finite field for mod arithmetics
|
3
|
-
import { ONE } from './bn';
|
4
|
-
import { randomBytes } from './rng';
|
5
|
-
import { sm3 } from './sm3';
|
6
|
-
import { hmac } from './hmac';
|
7
|
-
import { concatBytes } from '@noble/curves/abstract/utils';
|
8
|
-
|
9
|
-
export const sm2Fp = Field(BigInt('115792089210356248756420345214020892766250353991924191454421193933289684991999'))
|
10
|
-
export const sm2Curve = weierstrass({
|
11
|
-
// sm2: short weierstrass.
|
12
|
-
a: BigInt('115792089210356248756420345214020892766250353991924191454421193933289684991996'),
|
13
|
-
b: BigInt('18505919022281880113072981827955639221458448578012075254857346196103069175443'),
|
14
|
-
Fp: sm2Fp,
|
15
|
-
h: ONE,
|
16
|
-
n: BigInt('115792089210356248756420345214020892766061623724957744567843809356293439045923'),
|
17
|
-
Gx: BigInt('22963146547237050559479531362550074578802567295341616970375194840604139615431'),
|
18
|
-
Gy: BigInt('85132369209828568825618990617112496413088388631904505083283536607588877201568'),
|
19
|
-
hash: sm3,
|
20
|
-
hmac: (key: Uint8Array, ...msgs: Uint8Array[]) => hmac(sm3, key, concatBytes(...msgs)),
|
21
|
-
randomBytes,
|
22
|
-
});
|
23
|
-
// 有限域运算
|
24
|
-
export const field = Field(BigInt(sm2Curve.CURVE.n))
|
package/src/sm2/hmac.ts
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
import { Hash, CHash, Input, toBytes } from '../sm3/utils';
|
2
|
-
// HMAC (RFC 2104)
|
3
|
-
export class HMAC<T extends Hash<T>> extends Hash<HMAC<T>> {
|
4
|
-
oHash: T;
|
5
|
-
iHash: T;
|
6
|
-
blockLen: number;
|
7
|
-
outputLen: number;
|
8
|
-
private finished = false;
|
9
|
-
private destroyed = false;
|
10
|
-
|
11
|
-
constructor(hash: CHash, _key: Input) {
|
12
|
-
super();
|
13
|
-
const key = toBytes(_key);
|
14
|
-
this.iHash = hash.create() as T;
|
15
|
-
if (typeof this.iHash.update !== 'function')
|
16
|
-
throw new Error('Expected instance of class which extends utils.Hash');
|
17
|
-
this.blockLen = this.iHash.blockLen;
|
18
|
-
this.outputLen = this.iHash.outputLen;
|
19
|
-
const blockLen = this.blockLen;
|
20
|
-
const pad = new Uint8Array(blockLen);
|
21
|
-
// blockLen can be bigger than outputLen
|
22
|
-
pad.set(key.length > blockLen ? hash.create().update(key).digest() : key);
|
23
|
-
for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36;
|
24
|
-
this.iHash.update(pad);
|
25
|
-
// By doing update (processing of first block) of outer hash here we can re-use it between multiple calls via clone
|
26
|
-
this.oHash = hash.create() as T;
|
27
|
-
// Undo internal XOR && apply outer XOR
|
28
|
-
for (let i = 0; i < pad.length; i++) pad[i] ^= 0x36 ^ 0x5c;
|
29
|
-
this.oHash.update(pad);
|
30
|
-
pad.fill(0);
|
31
|
-
}
|
32
|
-
update(buf: Input) {
|
33
|
-
this.iHash.update(buf);
|
34
|
-
return this;
|
35
|
-
}
|
36
|
-
digestInto(out: Uint8Array) {
|
37
|
-
this.finished = true;
|
38
|
-
this.iHash.digestInto(out);
|
39
|
-
this.oHash.update(out);
|
40
|
-
this.oHash.digestInto(out);
|
41
|
-
this.destroy();
|
42
|
-
}
|
43
|
-
digest() {
|
44
|
-
const out = new Uint8Array(this.oHash.outputLen);
|
45
|
-
this.digestInto(out);
|
46
|
-
return out;
|
47
|
-
}
|
48
|
-
_cloneInto(to?: HMAC<T>): HMAC<T> {
|
49
|
-
// Create new instance without calling constructor since key already in state and we don't know it.
|
50
|
-
to ||= Object.create(Object.getPrototypeOf(this), {});
|
51
|
-
const { oHash, iHash, finished, destroyed, blockLen, outputLen } = this;
|
52
|
-
to = to as this;
|
53
|
-
to.finished = finished;
|
54
|
-
to.destroyed = destroyed;
|
55
|
-
to.blockLen = blockLen;
|
56
|
-
to.outputLen = outputLen;
|
57
|
-
to.oHash = oHash._cloneInto(to.oHash);
|
58
|
-
to.iHash = iHash._cloneInto(to.iHash);
|
59
|
-
return to;
|
60
|
-
}
|
61
|
-
destroy() {
|
62
|
-
this.destroyed = true;
|
63
|
-
this.oHash.destroy();
|
64
|
-
this.iHash.destroy();
|
65
|
-
}
|
66
|
-
}
|
67
|
-
|
68
|
-
/**
|
69
|
-
* HMAC: RFC2104 message authentication code.
|
70
|
-
* @param hash - function that would be used e.g. sha256
|
71
|
-
* @param key - message key
|
72
|
-
* @param message - message data
|
73
|
-
*/
|
74
|
-
export const hmac = (hash: CHash, key: Input, message: Input): Uint8Array =>
|
75
|
-
new HMAC<any>(hash, key).update(message).digest();
|
76
|
-
hmac.create = (hash: CHash, key: Input) => new HMAC<any>(hash, key);
|
package/src/sm2/index.ts
DELETED
@@ -1,319 +0,0 @@
|
|
1
|
-
/* eslint-disable no-use-before-define */
|
2
|
-
import { encodeDer, decodeDer, encodeEnc, decodeEnc } from './asn1'
|
3
|
-
import { arrayToHex, arrayToUtf8, generateKeyPairHex, hexToArray, leftPad, utf8ToHex } from './utils'
|
4
|
-
import { sm3 } from './sm3'
|
5
|
-
import * as utils from '@noble/curves/abstract/utils';
|
6
|
-
import { field, sm2Curve } from './ec';
|
7
|
-
import { ONE, ZERO } from './bn';
|
8
|
-
import { bytesToHex } from '@/sm3/utils';
|
9
|
-
import { ProjPointType } from '@noble/curves/abstract/weierstrass';
|
10
|
-
|
11
|
-
export * from './utils'
|
12
|
-
export { initRNGPool } from './rng'
|
13
|
-
export { calculateSharedKey } from './kx'
|
14
|
-
|
15
|
-
const C1C2C3 = 0
|
16
|
-
// a empty array, just make tsc happy
|
17
|
-
export const EmptyArray = new Uint8Array()
|
18
|
-
/**
|
19
|
-
* 加密
|
20
|
-
*/
|
21
|
-
export function doEncrypt(msg: string | Uint8Array, publicKey: string | ProjPointType<bigint>, cipherMode = 1, options?: {
|
22
|
-
asn1?: boolean // 使用 ASN.1 对 C1 编码
|
23
|
-
}) {
|
24
|
-
|
25
|
-
const msgArr = typeof msg === 'string' ? hexToArray(utf8ToHex(msg)) : Uint8Array.from(msg)
|
26
|
-
const publicKeyPoint = typeof publicKey === 'string' ? sm2Curve.ProjectivePoint.fromHex(publicKey) :
|
27
|
-
publicKey
|
28
|
-
|
29
|
-
const keypair = generateKeyPairHex()
|
30
|
-
const k = utils.hexToNumber(keypair.privateKey)
|
31
|
-
|
32
|
-
// c1 = k * G
|
33
|
-
let c1 = keypair.publicKey
|
34
|
-
|
35
|
-
if (c1.length > 128) c1 = c1.substring(c1.length - 128)
|
36
|
-
const p = publicKeyPoint.multiply(k)
|
37
|
-
|
38
|
-
// (x2, y2) = k * publicKey
|
39
|
-
const x2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.x), 64))
|
40
|
-
const y2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.y), 64))
|
41
|
-
|
42
|
-
// c3 = hash(x2 || msg || y2)
|
43
|
-
const c3 = bytesToHex(sm3(utils.concatBytes(x2, msgArr, y2)));
|
44
|
-
|
45
|
-
xorCipherStream(x2, y2, msgArr)
|
46
|
-
const c2 = bytesToHex(msgArr)
|
47
|
-
if (options?.asn1) {
|
48
|
-
const point = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey)
|
49
|
-
const encode = cipherMode === C1C2C3 ?
|
50
|
-
encodeEnc(point.x, point.y, c2, c3) :
|
51
|
-
encodeEnc(point.x, point.y, c3, c2)
|
52
|
-
return encode
|
53
|
-
}
|
54
|
-
return cipherMode === C1C2C3 ? c1 + c2 + c3 : c1 + c3 + c2
|
55
|
-
}
|
56
|
-
|
57
|
-
function xorCipherStream(x2: Uint8Array, y2: Uint8Array, msg: Uint8Array) {
|
58
|
-
let ct = 1
|
59
|
-
let offset = 0
|
60
|
-
let t = EmptyArray
|
61
|
-
const ctShift = new Uint8Array(4)
|
62
|
-
const nextT = () => {
|
63
|
-
// (1) Hai = hash(z || ct)
|
64
|
-
// (2) ct++
|
65
|
-
ctShift[0] = ct >> 24 & 0x00ff
|
66
|
-
ctShift[1] = ct >> 16 & 0x00ff
|
67
|
-
ctShift[2] = ct >> 8 & 0x00ff
|
68
|
-
ctShift[3] = ct & 0x00ff
|
69
|
-
t = sm3(utils.concatBytes(x2, y2, ctShift))
|
70
|
-
ct++
|
71
|
-
offset = 0
|
72
|
-
}
|
73
|
-
nextT() // 先生成 Ha1
|
74
|
-
|
75
|
-
for (let i = 0, len = msg.length; i < len; i++) {
|
76
|
-
// t = Ha1 || Ha2 || Ha3 || Ha4
|
77
|
-
if (offset === t.length) nextT()
|
78
|
-
|
79
|
-
// c2 = msg ^ t
|
80
|
-
msg[i] ^= t[offset++] & 0xff
|
81
|
-
}
|
82
|
-
|
83
|
-
}
|
84
|
-
|
85
|
-
/**
|
86
|
-
* 解密
|
87
|
-
*/
|
88
|
-
export function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
|
89
|
-
output: 'array'
|
90
|
-
asn1?: boolean
|
91
|
-
}): Uint8Array
|
92
|
-
export function doDecrypt(encryptData: string, privateKey: string, cipherMode?: number, options?: {
|
93
|
-
output: 'string',
|
94
|
-
asn1?: boolean
|
95
|
-
}): string
|
96
|
-
export function doDecrypt(encryptData: string, privateKey: string, cipherMode = 1, {
|
97
|
-
output = 'string',
|
98
|
-
asn1 = false,
|
99
|
-
} = {}) {
|
100
|
-
const privateKeyInteger = utils.hexToNumber(privateKey)
|
101
|
-
|
102
|
-
let c1: ProjPointType<bigint>
|
103
|
-
let c2: string
|
104
|
-
let c3: string
|
105
|
-
|
106
|
-
|
107
|
-
if (asn1) {
|
108
|
-
const {x, y, cipher, hash} = decodeEnc(encryptData)
|
109
|
-
c1 = sm2Curve.ProjectivePoint.fromAffine({ x, y })
|
110
|
-
c3 = hash
|
111
|
-
c2 = cipher
|
112
|
-
if (cipherMode === C1C2C3) {
|
113
|
-
[c2, c3] = [c3, c2]
|
114
|
-
}
|
115
|
-
} else {
|
116
|
-
// c1c3c2
|
117
|
-
c1 = sm2Curve.ProjectivePoint.fromHex('04' + encryptData.substring(0, 128))!
|
118
|
-
c3 = encryptData.substring(128, 128 + 64)
|
119
|
-
c2 = encryptData.substring(128 + 64)
|
120
|
-
|
121
|
-
if (cipherMode === C1C2C3) {
|
122
|
-
c3 = encryptData.substring(encryptData.length - 64)
|
123
|
-
c2 = encryptData.substring(128, encryptData.length - 64)
|
124
|
-
}
|
125
|
-
}
|
126
|
-
|
127
|
-
|
128
|
-
const msg = hexToArray(c2)
|
129
|
-
const p = c1.multiply(privateKeyInteger)
|
130
|
-
const x2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.x), 64))
|
131
|
-
const y2 = hexToArray(leftPad(utils.numberToHexUnpadded(p.y), 64))
|
132
|
-
|
133
|
-
xorCipherStream(x2, y2, msg)
|
134
|
-
// c3 = hash(x2 || msg || y2)
|
135
|
-
const checkC3 = arrayToHex(Array.from(sm3(utils.concatBytes(x2, msg, y2))))
|
136
|
-
|
137
|
-
if (checkC3 === c3.toLowerCase()) {
|
138
|
-
return output === 'array' ? msg : arrayToUtf8(msg)
|
139
|
-
} else {
|
140
|
-
return output === 'array' ? [] : ''
|
141
|
-
}
|
142
|
-
}
|
143
|
-
|
144
|
-
export interface SignaturePoint {
|
145
|
-
k: bigint
|
146
|
-
x1: bigint
|
147
|
-
}
|
148
|
-
|
149
|
-
/**
|
150
|
-
* 签名
|
151
|
-
*/
|
152
|
-
export function doSignature(msg: Uint8Array | string, privateKey: string, options: {
|
153
|
-
pointPool?: SignaturePoint[], der?: boolean, hash?: boolean, publicKey?: string, userId?: string
|
154
|
-
} = {}) {
|
155
|
-
let {
|
156
|
-
pointPool, der, hash, publicKey, userId
|
157
|
-
} = options
|
158
|
-
let hashHex = typeof msg === 'string' ? utf8ToHex(msg) : arrayToHex(Array.from(msg))
|
159
|
-
|
160
|
-
if (hash) {
|
161
|
-
// sm3杂凑
|
162
|
-
publicKey = publicKey || getPublicKeyFromPrivateKey(privateKey)
|
163
|
-
hashHex = getHash(hashHex, publicKey, userId)
|
164
|
-
}
|
165
|
-
|
166
|
-
const dA = utils.hexToNumber(privateKey)
|
167
|
-
const e = utils.hexToNumber(hashHex)
|
168
|
-
|
169
|
-
// k
|
170
|
-
let k: bigint | null = null
|
171
|
-
let r: bigint | null = null
|
172
|
-
let s: bigint | null = null
|
173
|
-
|
174
|
-
do {
|
175
|
-
do {
|
176
|
-
let point: SignaturePoint
|
177
|
-
if (pointPool && pointPool.length) {
|
178
|
-
point = pointPool.pop()!
|
179
|
-
} else {
|
180
|
-
point = getPoint()
|
181
|
-
}
|
182
|
-
k = point.k
|
183
|
-
|
184
|
-
// r = (e + x1) mod n
|
185
|
-
r = field.add(e, point.x1)
|
186
|
-
} while (r === ZERO || (r + k) === sm2Curve.CURVE.n)
|
187
|
-
|
188
|
-
// s = ((1 + dA)^-1 * (k - r * dA)) mod n
|
189
|
-
s = field.mul(field.inv(field.addN(dA, ONE)), field.subN(k, field.mulN(r, dA)))
|
190
|
-
} while (s === ZERO)
|
191
|
-
if (der) return encodeDer(r, s) // asn.1 der 编码
|
192
|
-
return leftPad(utils.numberToHexUnpadded(r), 64) + leftPad(utils.numberToHexUnpadded(s), 64)
|
193
|
-
}
|
194
|
-
|
195
|
-
/**
|
196
|
-
* 验签
|
197
|
-
*/
|
198
|
-
export function doVerifySignature(msg: string | Uint8Array, signHex: string, publicKey: string | ProjPointType<bigint>, options: { der?: boolean, hash?: boolean, userId?: string } = {}) {
|
199
|
-
let hashHex: string
|
200
|
-
const {
|
201
|
-
hash,
|
202
|
-
der,
|
203
|
-
userId,
|
204
|
-
} = options
|
205
|
-
const publicKeyHex = typeof publicKey === 'string' ? publicKey : publicKey.toHex(false)
|
206
|
-
if (hash) {
|
207
|
-
// sm3杂凑
|
208
|
-
hashHex = getHash(typeof msg === 'string' ? utf8ToHex(msg) : msg, publicKeyHex, userId)
|
209
|
-
} else {
|
210
|
-
hashHex = typeof msg === 'string' ? utf8ToHex(msg) : arrayToHex(Array.from(msg))
|
211
|
-
}
|
212
|
-
|
213
|
-
let r: bigint;
|
214
|
-
let s: bigint;
|
215
|
-
if (der) {
|
216
|
-
const decodeDerObj = decodeDer(signHex) // asn.1 der 解码
|
217
|
-
r = decodeDerObj.r
|
218
|
-
s = decodeDerObj.s
|
219
|
-
} else {
|
220
|
-
r = utils.hexToNumber(signHex.substring(0, 64))
|
221
|
-
s = utils.hexToNumber(signHex.substring(64))
|
222
|
-
}
|
223
|
-
|
224
|
-
const PA = typeof publicKey === 'string' ? sm2Curve.ProjectivePoint.fromHex(publicKey) : publicKey
|
225
|
-
const e = utils.hexToNumber(hashHex)
|
226
|
-
|
227
|
-
// t = (r + s) mod n
|
228
|
-
const t = field.add(r, s)
|
229
|
-
|
230
|
-
if (t === ZERO) return false
|
231
|
-
|
232
|
-
// x1y1 = s * G + t * PA
|
233
|
-
const x1y1 = sm2Curve.ProjectivePoint.BASE.multiply(s).add(PA.multiply(t))
|
234
|
-
|
235
|
-
// R = (e + x1) mod n
|
236
|
-
// const R = e.add(x1y1.getX().toBigInteger()).mod(n)
|
237
|
-
const R = field.add(e, x1y1.x)
|
238
|
-
|
239
|
-
// return r.equals(R)
|
240
|
-
return r === R
|
241
|
-
}
|
242
|
-
|
243
|
-
export function getZ(publicKey: string, userId = '1234567812345678') {
|
244
|
-
// z = hash(entl || userId || a || b || gx || gy || px || py)
|
245
|
-
userId = utf8ToHex(userId)
|
246
|
-
const a = leftPad(utils.numberToHexUnpadded(sm2Curve.CURVE.a), 64)
|
247
|
-
// const b = leftPad(G.curve.b.toBigInteger().toRadix(16), 64)
|
248
|
-
const b = leftPad(utils.numberToHexUnpadded(sm2Curve.CURVE.b), 64)
|
249
|
-
// const gx = leftPad(G.getX().toBigInteger().toRadix(16), 64)
|
250
|
-
const gx = leftPad(utils.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.x), 64)
|
251
|
-
// const gy = leftPad(G.getY().toBigInteger().toRadix(16), 64)
|
252
|
-
const gy = leftPad(utils.numberToHexUnpadded(sm2Curve.ProjectivePoint.BASE.y), 64)
|
253
|
-
let px: string
|
254
|
-
let py: string
|
255
|
-
if (publicKey.length === 128) {
|
256
|
-
px = publicKey.substring(0, 64)
|
257
|
-
py = publicKey.substring(64, 128)
|
258
|
-
} else {
|
259
|
-
// const point = G.curve.decodePointHex(publicKey)!
|
260
|
-
const point = sm2Curve.ProjectivePoint.fromHex(publicKey)!
|
261
|
-
// px = leftPad(point.getX().toBigInteger().toRadix(16), 64)
|
262
|
-
px = leftPad(utils.numberToHexUnpadded(point.x), 64)
|
263
|
-
// py = leftPad(point.getY().toBigInteger().toRadix(16), 64)
|
264
|
-
py = leftPad(utils.numberToHexUnpadded(point.y), 64)
|
265
|
-
}
|
266
|
-
const data = hexToArray(userId + a + b + gx + gy + px + py)
|
267
|
-
|
268
|
-
const entl = userId.length * 4
|
269
|
-
|
270
|
-
const z = sm3(utils.concatBytes(new Uint8Array([entl >> 8 & 0x00ff, entl & 0x00ff]), data))
|
271
|
-
|
272
|
-
return z
|
273
|
-
}
|
274
|
-
|
275
|
-
/**
|
276
|
-
* sm3杂凑算法
|
277
|
-
*/
|
278
|
-
export function getHash(hashHex: string | Uint8Array, publicKey: string, userId = '1234567812345678') {
|
279
|
-
const z = getZ(publicKey, userId)
|
280
|
-
// e = hash(z || msg)
|
281
|
-
return bytesToHex(sm3(utils.concatBytes(z, typeof hashHex === 'string' ? hexToArray(hashHex) : hashHex)))
|
282
|
-
}
|
283
|
-
|
284
|
-
/**
|
285
|
-
* 预计算公钥点,可用于提升加密性能
|
286
|
-
* @export
|
287
|
-
* @param {string} publicKey 公钥
|
288
|
-
* @param windowSize 计算窗口大小,默认为 8
|
289
|
-
* @returns {ProjPointType<bigint>} 预计算的点
|
290
|
-
*/
|
291
|
-
export function precomputePublicKey(publicKey: string, windowSize?: number) {
|
292
|
-
const point = sm2Curve.ProjectivePoint.fromHex(publicKey)
|
293
|
-
return sm2Curve.utils.precompute(windowSize, point)
|
294
|
-
}
|
295
|
-
|
296
|
-
/**
|
297
|
-
* 计算公钥
|
298
|
-
*/
|
299
|
-
export function getPublicKeyFromPrivateKey(privateKey: string) {
|
300
|
-
const pubKey = sm2Curve.getPublicKey(privateKey, false)
|
301
|
-
const pubPad = leftPad(utils.bytesToHex(pubKey), 64)
|
302
|
-
return pubPad
|
303
|
-
}
|
304
|
-
|
305
|
-
/**
|
306
|
-
* 获取椭圆曲线点
|
307
|
-
*/
|
308
|
-
export function getPoint() {
|
309
|
-
const keypair = generateKeyPairHex()
|
310
|
-
const PA = sm2Curve.ProjectivePoint.fromHex(keypair.publicKey)
|
311
|
-
const k = utils.hexToNumber(keypair.privateKey)
|
312
|
-
|
313
|
-
return {
|
314
|
-
...keypair,
|
315
|
-
k,
|
316
|
-
x1: PA!.x,
|
317
|
-
}
|
318
|
-
}
|
319
|
-
|