|
1 | | -import { createDecipheriv, createHash } from "crypto"; |
| 1 | +import { createDecipheriv, pbkdf2Sync } from "crypto"; |
2 | 2 | import { badRequest } from "../common/error"; |
3 | 3 |
|
4 | | -// Spring's Encryptors.text uses AES-256-CBC with a key derived from password and salt (hex). |
5 | | -// The encrypted string format is: hex(salt) + encryptedBase64 |
6 | | -// See: https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/encrypt/Encryptors.html |
7 | | - |
| 4 | +// Spring's Encryptors.text uses AES-256-CBC with PBKDF2 (HmacSHA1, 1024 iterations). |
8 | 5 | const ALGORITHM = "aes-256-cbc"; |
9 | 6 | const KEY_LENGTH = 32; // 256 bits |
10 | 7 | const IV_LENGTH = 16; // 128 bits |
| 8 | +const ITERATIONS = 1024; |
| 9 | +const DIGEST = "sha1"; |
11 | 10 |
|
12 | 11 | // You must set these to match your Java config: |
13 | 12 | const PASSWORD = process.env.LOWCODER_NODE_SERVICE_SECRET || "lowcoderpwd"; |
14 | 13 | const SALT_HEX = process.env.LOWCODER_NODE_SERVICE_SECRET_SALT || "lowcodersalt"; |
15 | 14 |
|
16 | 15 | /** |
17 | | - * Convert a string to its binary representation, then to a hex string. |
18 | | - */ |
19 | | -function stringToHexFromBinary(str: string): string { |
20 | | - // Convert string to binary (Buffer), then to hex string |
21 | | - return Buffer.from(str, "utf8").toString("hex"); |
22 | | -} |
23 | | - |
24 | | -/** |
25 | | - * Derive key from password and salt using SHA-256 (Spring's default). |
| 16 | + * Derive key from password and salt using PBKDF2WithHmacSHA1 (Spring's default). |
26 | 17 | */ |
27 | 18 | function deriveKey(password: string, saltHex: string): Buffer { |
28 | | - // Convert salt string to binary, then to hex string |
29 | | - const saltHexFromBinary = stringToHexFromBinary(saltHex); |
30 | | - const salt = Buffer.from(saltHexFromBinary, "hex"); |
31 | | - const hash = createHash("sha256"); |
32 | | - hash.update(password); |
33 | | - hash.update(salt); |
34 | | - return hash.digest(); |
| 19 | + const salt = Buffer.from(saltHex, "utf8"); |
| 20 | + return pbkdf2Sync(password, salt, ITERATIONS, KEY_LENGTH, DIGEST); |
35 | 21 | } |
36 | 22 |
|
37 | 23 | /** |
38 | 24 | * Decrypt a string encrypted by Spring's Encryptors.text. |
39 | 25 | */ |
40 | 26 | export async function decryptString(encrypted: string): Promise<string> { |
41 | 27 | try { |
42 | | - // Spring's format: hex(salt) + encryptedBase64 |
43 | | - // But if you know salt, encrypted is just Base64(IV + ciphertext) |
| 28 | + // Spring's format: hex(salt) + encryptedHex(IV + ciphertext) |
44 | 29 | const key = deriveKey(PASSWORD, SALT_HEX); |
45 | 30 |
|
46 | | - // Spring's Encryptors.text prepends a random IV (16 bytes) to the ciphertext, all base64 encoded. |
47 | | - const encryptedBuf = Buffer.from(encrypted, "base64"); |
| 31 | + const encryptedBuf = Buffer.from(encrypted, "hex"); |
48 | 32 | const iv = encryptedBuf.slice(0, IV_LENGTH); |
49 | 33 | const ciphertext = encryptedBuf.slice(IV_LENGTH); |
50 | 34 |
|
|
0 commit comments