{*******************************************************} { } { Tocsg.Fasoo } { } { Copyright (C) 2024 kku } { } {*******************************************************} unit Tocsg.Fasoo; interface uses Tocsg.Obj, System.SysUtils, Winapi.Windows, System.Classes; const {$IFDEF WIN64} DLL_FASOO = 'WorkPackagerV3_64.dll'; {$ELSE} DLL_FASOO = 'WorkPackagerV3.dll'; {$ENDIF} FASOO_COM_OLD = 'WorkPackager.WorkPackagerADK'; // 구버전, CJ에서 사용 FASOO_COM = 'WorkPackagerV3.WorkPackagerADK'; // 새버전, 2020년 4월 부터 변경됐다고 함, 삼성중공업에서 사용 DSD_CODE_LOTTEMART = '0100000000002054'; // 롯데마트 DSD_CODE_SHI = '0000000000001833'; // 삼성중공업 DSD_CODE_CJ = '0000000000002519'; // CJ DSD_CODE_WFNI = '0100000000004457'; // 웰릭스에프앤아이 (구 웰컴에프앤디) DSD_CODE_WFND = '0100000000001803'; // 웰컴에프앤디 DSD_CODE_GIORDANO = '0100000000004318'; // 지오다노 const // Error Code (FED4.0, FED5.0 공통) E_SERVERID_NOT_EXIST = 3; // server id가 입력되지 않았을 경우 E_INVALID_PARAM = 4; // 필수 인자값이 입력되지 않았을 경우 E_REQ_INFO_NOT_EXIST = 16; // Home Dir이 입력되지 않거나 필수 속성이 존재하지 않을 경우 E_INVALID_FILE_EXT_NSPRT = 11; // 지원하지 않는 파일 확장자 E_FILE_NOT_EXIST = 20; // 파일이 존재하지 않을 경우. E_FILE_SIZE_ZERO = 21; // 파일 크기가 0일 경우 E_FILE_OPEN_FAIL = 22; // 파일 열람에 실패할 경우. E_FILE_READ_FAIL = 23; // 파일 읽기에 실패할 경우 E_PACKAGED_FILE = 26; // FSD 파일 E_OLD_OLE_FILE = 27; // 지원하지 않는 OLE 파일 타입. E_NOT_PACKAGED_FILE = 29; // 일반 파일 E_FILE_DELETE_FAIL = 30; // 파일 삭제에 실패할 경우 E_CHECK_CERTIFICATE_FAIL = 40; // 인증서가 없거나 유효하지 않을 경우 E_COCREATE_INST_FAIL = 41; // COM 객체 생성 실패 E_DECODING_FAIL = 51; // 디코딩 실패 E_SYMMDEC_FAIL = 54; // 암호화 실패 E_MEMALLOCFAIL = 70; // 메모리 할당 실패 E_NOT_INITIALIZE = 72; // 메모리 초기화 실패 // Error Code 참조 (FED5.0 전용) SC_FILE_FED5_PACKAGED = 1150; // FED5.0 FSD 문서 SC_FILE_FED5_FSN_PACKAGED = 1151; // FED5.0 FSN 문서 SC_FILE_FED5_FSE_PACKAGED = 1152; // FED5.0 FSE 문서 SC_FILE_FED5_NX_PACKAGED = 1153; // FED5.0 NX 문서 SC_NOT_SUPPORT_RIGHT = 1166; // 문서 타입 변환시 해당 문서에 ‘CONVERSION’ 또는 ‘SAVE’ 권한이 없을 경우 SC_DISABLED_LOGGING = 1167; // 로그 전송 설정이 되어 있지 않거나 인증서가 설정되어 있지 않을 경우 SC_NOT_FED_VERSION = 1176; // conf 파일의 [PACKAGER] 필드에 VERSION 값이 존재하지 않을 경우 (FED4.0 conf 파일에는 해당값이 존재하지 않음) SC_FAILED_GET_RIGHTS = 1178; // 문서 복호화시 서버나 클라이언트에 복호화 권한 확인시 권한이 없거나 권한 확인에 실패할 경우 SC_NOT_SUPPORT_ALGORITHM = 1180; // 지원하지 않는 알고리즘 SC_FAILED_SECTION_FIND = 1201; // 문서 헤더에서 섹션을 찾는데 실패할 경우 SC_FAILED_HMAC_COMPARE = 1205; // 문서 헤더의 HMAC 확인에 실패할 경우 (문서 헤더 위변조 여부 확인) SC_FAILED_GET_DOMAINKEY = 1214; // 인증서에서 도메인키를 가져오는데 실패할 경우 SC_DISCARD_APPCERT = 1216; // 폐기된 인증서를 호출할 경우 SC_DISCARD_DKCOUNT = 1217; // 폐기된 도메인키 카운트를 적용할 경우 SC_FAILED_CERT_SIGN = 1500; // cert에 실패할 경우 SC_FAILED_GET_KEY = 1501; // 키를 가져오는데 실패할 경우 SC_FAILED_PFX_LOAD = 1502; // 인증서 로드에 실패할 경우 SC_FAILED_GET_APPKEY = 1503; // 응용서버 인증서 디코드에 실패할 경우 type TTgFasoo = class(TTgObject) private nVer_: Integer; // 0 = COM 개체 획득 못함, 1 = 올드, 2 = 2020년 4월 이후 ComObj_: Variant; sFsdFsnPath_, // FSN 문서 복호화 키(폴더) 경로 sFsdNxPath_, // NX 문서 복호화 키(폴더) 경로 sFixedCPID_: String; // CPID(구 Server ID)를 고정해서 사용할때 사용 public Constructor Create(sFsdFsnPath: String; sFsdNxPath: String = ''); function IsReady: Boolean; function GetFileType(sEncPath: String): Integer; function GetFileHeader(sEncPath: String): String; function IsPackageFile(sEncPath: String): Boolean; // 복호화 function DoExtract(sEncPath, sDecPath: String; bLogonUser: Boolean = false; pnResult: PInteger = nil): Boolean; // 암호화 function DoPackagingFsn(sSrcPath, sDestPath: String; pnResult: PInteger = nil): Boolean; function DoPackagingFsn2(sSrcPath, sDestPath: String; pnResult: PInteger = nil): Boolean; function DoPackaging(sSrcPath, sDestPath: String; pnResult: PInteger = nil): Boolean; end; {$IFDEF _CJ_} function IsFasooLogon: Integer; function GetFasooUserID: String; {$ENDIF} procedure SetDSD_CODE(sCode: String); var DSD_CODE: String = DSD_CODE_LOTTEMART; // 암호화 시 사용 _sWriteId_: String = 'dlpadmin';// 'csm_tocsg';; _sWriteName: String = 'dlpadmin';//'최성민'; _sWriteDeptCode: String = 'COMPANY'; _sWriteDeptName: String = 'DeptName'; _sSecurityLevel: String = 'a890dab1a2964ddfba69a04c3d4431ba'; implementation uses {$IFDEF _CJ_} Winapi.ActiveX, F_SSOLib_TLB, {$ENDIF} System.Win.ComObj, System.Variants, Tocsg.Safe, Tocsg.Exception, Tocsg.Strings; procedure SetDSD_CODE(sCode: String); begin DSD_CODE := sCode; if DSD_CODE = DSD_CODE_LOTTEMART then begin _sWriteDeptName := '롯데마트'; _sSecurityLevel := 'a890dab1a2964ddfba69a04c3d4431ba'; end else if DSD_CODE = DSD_CODE_WFNI then begin _sWriteId_ := 'admin'; _sWriteName := 'admin'; _sWriteDeptName := '웰릭스에프앤아이'; //'웰컴에프앤디'; // _sSecurityLevel := '39e43183f99f4170be6227255a07dadd'; // 기본보안등급 _sSecurityLevel := '320ce4ed95a34221be960d8f362cbcce'; // 개인정보등급 end else if DSD_CODE = DSD_CODE_WFND then begin _sWriteId_ := 'admin'; _sWriteName := 'admin'; _sWriteDeptName := '웰컴에프앤디'; // _sSecurityLevel := '39e43183f99f4170be6227255a07dadd'; // 기본보안등급 _sSecurityLevel := '320ce4ed95a34221be960d8f362cbcce'; // 개인정보등급 end else begin _sWriteDeptName := 'Unknown'; _sSecurityLevel := ''; end; end; { TTgFasoo } Constructor TTgFasoo.Create(sFsdFsnPath: String; sFsdNxPath: String = ''); procedure Init; begin // try // ComObj_ := CreateOleObject(FASOO_COM_OLD); // nVer_ := 1; // except // on E: Exception do // ETgException.TraceException(Self, E, Format('Create() .. Fail load .. "%s"', [FASOO_COM_OLD])); // end; if nVer_ <= 0 then begin try ComObj_ := CreateOleObject(FASOO_COM); nVer_ := 2; _Trace('Create() .. Success'); except on E: Exception do ETgException.TraceException(Self, E, Format('Create() .. Fail load .. "%s"', [FASOO_COM])); end; end; end; begin Inherited Create; nVer_ := -1; ComObj_ := varEmpty; sFixedCPID_ := ''; sFsdFsnPath_ := sFsdFsnPath; if sFsdNxPath = '' then sFsdNxPath := sFsdFsnPath; sFsdNxPath_ := sFsdNxPath; Init; if (nVer_ = 2) and (DirectoryExists(sFsdNxPath_)) then // 2020년 이후 신버전 sFixedCPID_ := DSD_CODE; end; function TTgFasoo.IsReady: Boolean; begin Result := nVer_ <> -1; end; function TTgFasoo.GetFileType(sEncPath: String): Integer; begin try if not VarIsEmpty(ComObj_) then Result := ComObj_.GetFileType(sEncPath) else Result := -1; except on E: Exception do ETgException.TraceException(E, 'Fail .. GetFileType()'); end; end; function TTgFasoo.GetFileHeader(sEncPath: String): String; begin if not VarIsEmpty(ComObj_) then Result := ComObj_.GetFileHeader(sEncPath) else Result := ''; end; function TTgFasoo.IsPackageFile(sEncPath: String): Boolean; begin if not VarIsEmpty(ComObj_) then Result := ComObj_.IsPackageFile(sEncPath) = 1 else Result := false; end; function TTgFasoo.DoExtract(sEncPath, sDecPath: String; bLogonUser: Boolean = false; pnResult: PInteger = nil): Boolean; var nType, nResult: Integer; sCPID, sFHeader, sFsdPath: String; FHeaderList: TStringList; begin Result := false; try nResult := -1; if pnResult <> nil then pnResult^ := -1; if nVer_ = 0 then exit; if VarIsEmpty(ComObj_) then exit; if not FileExists(sEncPath) then exit; sFsdPath := ''; nType := GetFileType(sEncPath); case nType of 103 : // FSN begin if DirectoryExists(sFsdFsnPath_) then sFsdPath := sFsdFsnPath_; end; 106 : // NX begin if DirectoryExists(sFsdNxPath_) then sFsdPath := sFsdNxPath_; end else exit; end; if sFsdPath = '' then exit; if FileExists(sDecPath) then DeleteFile(PChar(sDecPath)); // 타사 고객사/계열사 암호화 파일인지 체크하도록 변경 25_0414 13:58:51 kku // sCPID := sFixedCPID_; // if sCPID = '' then begin sFHeader := GetFileHeader(sEncPath); if sFHeader = '' then exit; Guard(FHeaderList, TStringList.Create); SplitString(sFHeader, ';', FHeaderList, true); if FHeaderList.Count < 18 then exit; sCPID := FHeaderList[17]; // 18번째에 있음 end; // ServerID 체크 추가 25_0408 09:23:39 kku // ServerID가 다른 암호화 파일을 복호화 시도하면 "타사 제품으로 암호화된 문서이므로 열람 할 수 없습니다."라는 메시지가 나온다고 함 if DSD_CODE <> sCPID then begin if pnResult <> nil then pnResult^ := -2; _Trace('Fail .. DoExtract() .. Invalid ServerID, Get=%s, Chk=%s', [sCPID, DSD_CODE], 3); exit; end; if bLogonUser then nResult := ComObj_.DoExtract_c(sFsdPath, sCPID, sEncPath, sDecPath, 'VIEW') else nResult := ComObj_.DoExtract(sFsdPath, sCPID, sEncPath, sDecPath); if pnResult <> nil then pnResult^ := nResult; Result := FileExists(sDecPath); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DoExtract()'); end; end; function TTgFasoo.DoPackagingFsn(sSrcPath, sDestPath: String; pnResult: PInteger = nil): Boolean; var nResult: Integer; begin Result := false; nResult := -1; if pnResult <> nil then pnResult^ := -1; if nVer_ = 0 then exit; if _sSecurityLevel = '' then exit; if VarIsEmpty(ComObj_) then exit; if not FileExists(sSrcPath) then exit; if not DirectoryExists(sFsdFsnPath_) then exit; case GetFileType(sSrcPath) of 103 : exit; // FSN 106 : exit; // NX end; if FileExists(sDestPath) then DeleteFile(PChar(sDestPath)); try nResult := ComObj_.DoPackagingFsn(sFsdFsnPath_, DSD_CODE, sSrcPath, sDestPath, ExtractFileName(sSrcPath), _sWriteId_, _sWriteName, _sWriteId_, _sWriteName, _sWriteDeptCode, _sWriteDeptName, _sWriteId_, _sWriteName, _sWriteDeptCode, _sWriteDeptName, _sSecurityLevel); if pnResult <> nil then pnResult^ := nResult; Result := FileExists(sDestPath); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DoPackagingFsn()'); end; end; function TTgFasoo.DoPackagingFsn2(sSrcPath, sDestPath: String; pnResult: PInteger = nil): Boolean; var nType, nResult: Integer; begin Result := false; nResult := -1; if pnResult <> nil then pnResult^ := -1; if nVer_ = 0 then exit; if _sSecurityLevel = '' then exit; if VarIsEmpty(ComObj_) then exit; if not FileExists(sSrcPath) then exit; if not DirectoryExists(sFsdFsnPath_) then exit; nType := GetFileType(sSrcPath); // _Trace('DoPackagingFsn2() .. 5, Type=%d', [nType]); case GetFileType(sSrcPath) of 103 : exit; // FSN 106 : exit; // NX end; // _Trace('DoPackagingFsn2() .. 6'); if FileExists(sDestPath) then DeleteFile(PChar(sDestPath)); try nResult := ComObj_.DoPackagingFsn2(sFsdFsnPath_, DSD_CODE, sSrcPath, sDestPath, ExtractFileName(sSrcPath), _sWriteId_, _sWriteName, _sWriteId_, _sWriteName, _sWriteDeptCode, _sWriteDeptName, _sWriteId_, _sWriteName, _sWriteDeptCode, _sWriteDeptName, _sSecurityLevel); if pnResult <> nil then pnResult^ := nResult; Result := FileExists(sDestPath); // _Trace('DoPackagingFsn2() .. 7'); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DoPackagingFsn2()'); end; end; function TTgFasoo.DoPackaging(sSrcPath, sDestPath: String; pnResult: PInteger = nil): Boolean; var nResult: Integer; begin Result := false; nResult := -1; if pnResult <> nil then pnResult^ := -1; if nVer_ = 0 then exit; if _sSecurityLevel = '' then exit; if VarIsEmpty(ComObj_) then exit; if not FileExists(sSrcPath) then exit; if not DirectoryExists(sFsdFsnPath_) then exit; case GetFileType(sSrcPath) of 103 : exit; // FSN 106 : exit; // NX end; if FileExists(sDestPath) then DeleteFile(PChar(sDestPath)); try nResult := ComObj_.DoPackaging(sFsdFsnPath_, DSD_CODE, sSrcPath, sDestPath, ExtractFileName(sSrcPath), _sWriteId_, _sWriteName, '', '', '', '', ''); if pnResult <> nil then pnResult^ := nResult; Result := FileExists(sDestPath); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DoPackagingFsn2()'); end; end; {$IFDEF _CJ_} var USER_KEY: String = 'CUID'; // 실패 : -1 // 로그온 : 1 // 로그오프 : 0 function IsFasooLogon: Integer; var hr: HResult; iSSO: IxSSO; begin Result := -1; try CoInitializeEx(nil, COINIT_APARTMENTTHREADED); try iSSO := nil; hr := CoCreateInstance(CLASS_FasooSSO, nil, CLSCTX_INPROC_SERVER, IID_IxSSO, iSSO); if SUCCEEDED(hr) and (iSSO <> nil) then Result := iSSO.IsLogon(DSD_CODE); finally CoUninitialize; end; except // .. end; end; // 로그 아웃 상태에서 시도하면 파수 로그인창이 뜨면서 "빈값"을 반환함 function GetFasooUserID: String; var hr: HResult; iSSO: IxSSO; begin Result := '*Fail%_'; // Result := ''; try CoInitializeEx(nil, COINIT_APARTMENTTHREADED); try iSSO := nil; hr := CoCreateInstance(CLASS_FasooSSO, nil, CLSCTX_INPROC_SERVER, IID_IxSSO, iSSO); if SUCCEEDED(hr) and (iSSO <> nil) then Result := iSSO.GetUserInfo(DSD_CODE, USER_KEY); finally CoUninitialize; end; except // .. end; end; {$ENDIF} end.