|
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