1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
|
/**
* DOLCE 파일 다운로드용 DES 암호화 유틸리티
* C# DESCryptoServiceProvider와 호환되는 Node.js 구현
*
* OpenSSL 3.0 호환 처리:
* - Node.js 17+ 환경에서 DES는 레거시 알고리즘으로 분류됨
* - 기본적으로 crypto-js 기반 구현 사용 (OpenSSL 독립적)
* - 환경 변수로 Native crypto 사용 가능: USE_NATIVE_CRYPTO=true
*/
import crypto from "crypto";
// 암호화 키 (8바이트)
const DES_KEY = Buffer.from("4fkkdijg", "ascii");
// OpenSSL Native Crypto 사용 여부 (기본: false, crypto-js 사용)
const USE_NATIVE_CRYPTO = process.env.USE_NATIVE_CRYPTO === "true";
// OpenSSL 3.0 환경 감지
let useModernCrypto = USE_NATIVE_CRYPTO;
/**
* DES ECB 모드로 문자열 암호화
* @param plainText 암호화할 평문
* @returns Base64 인코딩된 암호문
*/
export function encryptDES(plainText: string): string {
// 기본적으로 레거시 구현(crypto-js) 사용
if (!useModernCrypto) {
return encryptDESLegacy(plainText);
}
// Native crypto 시도 (USE_NATIVE_CRYPTO=true인 경우만)
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 에러 감지 - 레거시로 폴백
if (
error.code === "ERR_OSSL_EVP_UNSUPPORTED" ||
error.message?.includes("unsupported") ||
error.message?.includes("digital envelope")
) {
console.warn("[DOLCE] OpenSSL DES 미지원, crypto-js로 전환합니다.");
useModernCrypto = false;
return encryptDESLegacy(plainText);
}
throw error;
}
}
/**
* 레거시 DES 암호화 (crypto-js 기반, OpenSSL 독립적)
*/
function encryptDESLegacy(plainText: string): string {
try {
const { encryptDES: legacyEncrypt } = require("./crypto-utils-legacy");
return legacyEncrypt(plainText);
} catch (error) {
console.error("[DOLCE] DES 암호화 실패:", error);
throw new Error(`암호화 중 오류가 발생했습니다: ${error}`);
}
}
/**
* DES ECB 모드로 문자열 복호화
* @param encryptedText Base64 인코딩된 암호문
* @returns 복호화된 평문
*/
export function decryptDES(encryptedText: string): string {
// 기본적으로 레거시 구현(crypto-js) 사용
if (!useModernCrypto) {
return decryptDESLegacy(encryptedText);
}
// Native crypto 시도 (USE_NATIVE_CRYPTO=true인 경우만)
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) {
// OpenSSL 에러 감지 - 레거시로 폴백
if (
error.code === "ERR_OSSL_EVP_UNSUPPORTED" ||
error.message?.includes("unsupported") ||
error.message?.includes("digital envelope")
) {
console.warn("[DOLCE] OpenSSL DES 미지원, crypto-js로 전환합니다.");
useModernCrypto = false;
return decryptDESLegacy(encryptedText);
}
throw error;
}
}
/**
* 레거시 DES 복호화 (crypto-js 기반, OpenSSL 독립적)
*/
function decryptDESLegacy(encryptedText: string): string {
try {
const { decryptDES: legacyDecrypt } = require("./crypto-utils-legacy");
return legacyDecrypt(encryptedText);
} catch (error) {
console.error("[DOLCE] 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,
};
}
|