@ysgroup/core 0.1.12 → 0.1.13
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/package.json +6 -1
- package/src/password.ts +19 -65
package/package.json
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ysgroup/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "src/index.ts",
|
|
6
6
|
"types": "src/index.ts",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@noble/ciphers": "2.4.0",
|
|
9
|
+
"@noble/curves": "2.4.0",
|
|
10
|
+
"@noble/hashes": "2.4.0"
|
|
11
|
+
},
|
|
7
12
|
"peerDependencies": {
|
|
8
13
|
"pinia": ">=2.2",
|
|
9
14
|
"vue": ">=3.5"
|
package/src/password.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
/* 登录口令密封:X25519
|
|
1
|
+
/* 登录口令密封:X25519 + HKDF-SHA256 + AES-256-GCM。
|
|
2
|
+
使用 @noble/* 纯 JS,不依赖 Web Crypto SubtleCrypto。
|
|
3
|
+
HTTP(非安全上下文)与 HTTPS 同一路径,信封格式与 Auth/ys_base 对齐。 */
|
|
4
|
+
|
|
5
|
+
import { gcm } from "@noble/ciphers/aes.js";
|
|
6
|
+
import { x25519 } from "@noble/curves/ed25519.js";
|
|
7
|
+
import { hkdf } from "@noble/hashes/hkdf.js";
|
|
8
|
+
import { sha256 } from "@noble/hashes/sha2.js";
|
|
2
9
|
|
|
3
10
|
export interface PasswordWrap {
|
|
4
11
|
password_wrap: string;
|
|
@@ -77,76 +84,23 @@ export async function sealPassword(
|
|
|
77
84
|
const recipientRaw = b64uDecode(publicKeyB64);
|
|
78
85
|
if (recipientRaw.byteLength !== 32) throw new Error("登录公钥长度无效");
|
|
79
86
|
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
"raw",
|
|
85
|
-
asArrayBuffer(recipientRaw),
|
|
86
|
-
{ name: "X25519" },
|
|
87
|
-
false,
|
|
88
|
-
[],
|
|
89
|
-
);
|
|
90
|
-
const shared = new Uint8Array(
|
|
91
|
-
await crypto.subtle.deriveBits(
|
|
92
|
-
{ name: "X25519", public: recipient },
|
|
93
|
-
ephemeral.privateKey,
|
|
94
|
-
256,
|
|
95
|
-
),
|
|
96
|
-
);
|
|
97
|
-
const hkdfKey = await crypto.subtle.importKey(
|
|
98
|
-
"raw",
|
|
99
|
-
asArrayBuffer(shared),
|
|
100
|
-
"HKDF",
|
|
101
|
-
false,
|
|
102
|
-
["deriveBits"],
|
|
103
|
-
);
|
|
104
|
-
const aesRaw = await crypto.subtle.deriveBits(
|
|
105
|
-
{
|
|
106
|
-
name: "HKDF",
|
|
107
|
-
hash: "SHA-256",
|
|
108
|
-
salt: asArrayBuffer(SALT),
|
|
109
|
-
info: asArrayBuffer(INFO),
|
|
110
|
-
},
|
|
111
|
-
hkdfKey,
|
|
112
|
-
256,
|
|
113
|
-
);
|
|
114
|
-
const aesKey = await crypto.subtle.importKey(
|
|
115
|
-
"raw",
|
|
116
|
-
aesRaw,
|
|
117
|
-
{ name: "AES-GCM" },
|
|
118
|
-
false,
|
|
119
|
-
["encrypt"],
|
|
120
|
-
);
|
|
87
|
+
const ephemeralSecret = x25519.utils.randomSecretKey();
|
|
88
|
+
const ephemeralPublic = x25519.getPublicKey(ephemeralSecret);
|
|
89
|
+
const shared = x25519.getSharedSecret(ephemeralSecret, recipientRaw);
|
|
90
|
+
const aesRaw = hkdf(sha256, shared, SALT, INFO, 32);
|
|
121
91
|
const aad = new TextEncoder().encode(`${PREFIX}${kid}`);
|
|
122
|
-
const packedCt =
|
|
123
|
-
|
|
124
|
-
{
|
|
125
|
-
name: "AES-GCM",
|
|
126
|
-
iv: asArrayBuffer(NONCE),
|
|
127
|
-
additionalData: aad,
|
|
128
|
-
tagLength: 128,
|
|
129
|
-
},
|
|
130
|
-
aesKey,
|
|
131
|
-
new TextEncoder().encode(plaintext),
|
|
132
|
-
),
|
|
92
|
+
const packedCt = gcm(aesRaw, NONCE, aad).encrypt(
|
|
93
|
+
new TextEncoder().encode(plaintext),
|
|
133
94
|
);
|
|
134
|
-
const
|
|
135
|
-
|
|
95
|
+
const packed = new Uint8Array(
|
|
96
|
+
ephemeralPublic.byteLength + packedCt.byteLength,
|
|
136
97
|
);
|
|
137
|
-
|
|
138
|
-
packed.set(
|
|
139
|
-
|
|
98
|
+
packed.set(ephemeralPublic, 0);
|
|
99
|
+
packed.set(packedCt, ephemeralPublic.byteLength);
|
|
100
|
+
ephemeralSecret.fill(0);
|
|
140
101
|
return `${PREFIX}${kid}.${b64uEncode(packed)}`;
|
|
141
102
|
}
|
|
142
103
|
|
|
143
|
-
function asArrayBuffer(bytes: Uint8Array): ArrayBuffer {
|
|
144
|
-
return bytes.buffer.slice(
|
|
145
|
-
bytes.byteOffset,
|
|
146
|
-
bytes.byteOffset + bytes.byteLength,
|
|
147
|
-
) as ArrayBuffer;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
104
|
function b64uEncode(raw: Uint8Array): string {
|
|
151
105
|
let bin = "";
|
|
152
106
|
for (const byte of raw) bin += String.fromCharCode(byte);
|