@ysgroup/core 0.1.11 → 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 -44
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,52 +84,20 @@ 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
|
-
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("raw", shared, "HKDF", false, [
|
|
98
|
-
"deriveBits",
|
|
99
|
-
]);
|
|
100
|
-
const aesRaw = await crypto.subtle.deriveBits(
|
|
101
|
-
{ name: "HKDF", hash: "SHA-256", salt: SALT, info: INFO },
|
|
102
|
-
hkdfKey,
|
|
103
|
-
256,
|
|
104
|
-
);
|
|
105
|
-
const aesKey = await crypto.subtle.importKey(
|
|
106
|
-
"raw",
|
|
107
|
-
aesRaw,
|
|
108
|
-
{ name: "AES-GCM" },
|
|
109
|
-
false,
|
|
110
|
-
["encrypt"],
|
|
111
|
-
);
|
|
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);
|
|
112
91
|
const aad = new TextEncoder().encode(`${PREFIX}${kid}`);
|
|
113
|
-
const packedCt =
|
|
114
|
-
|
|
115
|
-
{ name: "AES-GCM", iv: NONCE, additionalData: aad, tagLength: 128 },
|
|
116
|
-
aesKey,
|
|
117
|
-
new TextEncoder().encode(plaintext),
|
|
118
|
-
),
|
|
92
|
+
const packedCt = gcm(aesRaw, NONCE, aad).encrypt(
|
|
93
|
+
new TextEncoder().encode(plaintext),
|
|
119
94
|
);
|
|
120
|
-
const
|
|
121
|
-
|
|
95
|
+
const packed = new Uint8Array(
|
|
96
|
+
ephemeralPublic.byteLength + packedCt.byteLength,
|
|
122
97
|
);
|
|
123
|
-
|
|
124
|
-
packed.set(
|
|
125
|
-
|
|
98
|
+
packed.set(ephemeralPublic, 0);
|
|
99
|
+
packed.set(packedCt, ephemeralPublic.byteLength);
|
|
100
|
+
ephemeralSecret.fill(0);
|
|
126
101
|
return `${PREFIX}${kid}.${b64uEncode(packed)}`;
|
|
127
102
|
}
|
|
128
103
|
|