diff options
Diffstat (limited to 'lib/dolce/crypto-utils.ts')
| -rw-r--r-- | lib/dolce/crypto-utils.ts | 142 |
1 files changed, 142 insertions, 0 deletions
diff --git a/lib/dolce/crypto-utils.ts b/lib/dolce/crypto-utils.ts new file mode 100644 index 00000000..1fb310b2 --- /dev/null +++ b/lib/dolce/crypto-utils.ts @@ -0,0 +1,142 @@ +/** + * DOLCE 파일 다운로드용 DES 암호화 유틸리티 + * C# DESCryptoServiceProvider와 호환되는 Node.js 구현 + * + * OpenSSL 3.0 호환 처리: + * - Node.js 17+ 환경에서 DES는 레거시 알고리즘으로 분류됨 + * - 에러 발생 시 crypto-utils-legacy.ts의 수동 구현 사용 + */ + +import crypto from "crypto"; + +// 암호화 키 (8바이트) +const DES_KEY = Buffer.from("4fkkdijg", "ascii"); + +// OpenSSL 3.0 환경 감지 +let useModernCrypto = true; + +/** + * DES ECB 모드로 문자열 암호화 + * @param plainText 암호화할 평문 + * @returns Base64 인코딩된 암호문 + */ +export function encryptDES(plainText: string): string { + // 처음 호출 시 OpenSSL 지원 여부 확인 + if (useModernCrypto) { + try { + const cipher = crypto.createCipheriv("des-ecb", DES_KEY, Buffer.alloc(0)); + cipher.setAutoPadding(true); + + let encrypted = cipher.update(plainText, "utf8", "base64"); + encrypted += cipher.final("base64"); + + return encrypted.replace(/\+/g, "|||"); + } catch (error: any) { + // OpenSSL 3.0 에러 감지 + if (error.message?.includes("unsupported") || error.message?.includes("digital envelope")) { + console.warn("[DOLCE] OpenSSL 3.0 감지, 레거시 구현으로 전환합니다."); + useModernCrypto = false; + // 레거시 구현으로 재시도 + return encryptDESLegacy(plainText); + } + throw error; + } + } else { + return encryptDESLegacy(plainText); + } +} + +/** + * 레거시 DES 암호화 (OpenSSL 3.0 대체) + */ +function encryptDESLegacy(plainText: string): string { + try { + const { encryptDES: legacyEncrypt } = require("./crypto-utils-legacy"); + return legacyEncrypt(plainText); + } catch (error) { + console.error("DES 암호화 실패:", error); + throw new Error(`암호화 중 오류가 발생했습니다: ${error}`); + } +} + +/** + * DES ECB 모드로 문자열 복호화 + * @param encryptedText Base64 인코딩된 암호문 + * @returns 복호화된 평문 + */ +export function decryptDES(encryptedText: string): string { + if (useModernCrypto) { + try { + const restored = encryptedText.replace(/\|\|\|/g, "+"); + const decipher = crypto.createDecipheriv("des-ecb", DES_KEY, Buffer.alloc(0)); + decipher.setAutoPadding(true); + + let decrypted = decipher.update(restored, "base64", "utf8"); + decrypted += decipher.final("utf8"); + + return decrypted.replace(/\0+$/, ""); + } catch (error: any) { + if (error.message?.includes("unsupported") || error.message?.includes("digital envelope")) { + console.warn("[DOLCE] OpenSSL 3.0 감지, 레거시 구현으로 전환합니다."); + useModernCrypto = false; + return decryptDESLegacy(encryptedText); + } + throw error; + } + } else { + return decryptDESLegacy(encryptedText); + } +} + +/** + * 레거시 DES 복호화 (OpenSSL 3.0 대체) + */ +function decryptDESLegacy(encryptedText: string): string { + try { + const { decryptDES: legacyDecrypt } = require("./crypto-utils-legacy"); + return legacyDecrypt(encryptedText); + } catch (error) { + console.error("DES 복호화 실패:", error); + throw new Error(`복호화 중 오류가 발생했습니다: ${error}`); + } +} + +/** + * DOLCE 파일 다운로드용 암호화 키 생성 + * @param fileId 파일 ID + * @param userId 사용자 ID + * @param fileName 파일명 + * @returns 암호화된 키 + */ +export function createDolceDownloadKey( + fileId: string, + userId: string, + fileName: string +): string { + // FileId↔UserId↔FileName 형식으로 조합 + const plainText = `${fileId}↔${userId}↔${fileName}`; + + // DES 암호화 + return encryptDES(plainText); +} + +/** + * 테스트용: 암호화/복호화 검증 + */ +export function testDESEncryption(testString: string): { + original: string; + encrypted: string; + decrypted: string; + match: boolean; +} { + const encrypted = encryptDES(testString); + const decrypted = decryptDES(encrypted); + + return { + original: testString, + encrypted, + decrypted, + match: testString === decrypted, + }; +} + |
