@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.
Files changed (2) hide show
  1. package/package.json +6 -1
  2. 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.11",
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 临时密钥 + HKDF-SHA256 + AES-256-GCM,与 Auth/ys_base 对齐。 */
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 ephemeral = await crypto.subtle.generateKey({ name: "X25519" }, true, [
81
- "deriveBits",
82
- ]);
83
- const recipient = await crypto.subtle.importKey(
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 = new Uint8Array(
114
- await crypto.subtle.encrypt(
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 ephPk = new Uint8Array(
121
- await crypto.subtle.exportKey("raw", ephemeral.publicKey),
95
+ const packed = new Uint8Array(
96
+ ephemeralPublic.byteLength + packedCt.byteLength,
122
97
  );
123
- const packed = new Uint8Array(ephPk.byteLength + packedCt.byteLength);
124
- packed.set(ephPk, 0);
125
- packed.set(packedCt, ephPk.byteLength);
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