350 lines
11 KiB
Plaintext
350 lines
11 KiB
Plaintext
{*******************************************************}
|
|
{ }
|
|
{ Tocsg.AIP }
|
|
{ }
|
|
{ Copyright (C) 2024 kku }
|
|
{ }
|
|
{*******************************************************}
|
|
|
|
unit Tocsg.AIP;
|
|
|
|
interface
|
|
|
|
uses
|
|
System.SysUtils, System.Classes, Winapi.ActiveX;
|
|
|
|
const
|
|
SIGN_AIP_DRM: array [0..23] of Byte = ($2E, $70, $66, $69, $6C, $65, $03, $00,
|
|
$00, $00, $00, $00, $00, $00, $8C, $01,
|
|
$00, $00, $0D, $0A, $0D, $0A, $0D, $0A); // .pfile 로 시작
|
|
|
|
function IsAipEncrytedPDF(sPath: String): Boolean;
|
|
function GetAipLabelNameFromPDF(sPath: String): String;
|
|
|
|
function IsAipEncrytedOldOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
|
|
function GetAipLabelNameFromOldOfficeDoc(sPath: String): String;
|
|
|
|
function IsAipEncrytedOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
|
|
function GetAipLabelNameFromOfficeDoc(sPath: String): String;
|
|
|
|
function CheckMsPfileExt(sPath: String): Boolean;
|
|
function CheckAipEncSign(sPath: String): Boolean;
|
|
function IsAipEncryted(sPath: String; sTempDir: String = ''; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
|
|
function ConvAipEncExt(sPath: String): String;
|
|
|
|
implementation
|
|
|
|
uses
|
|
Tocsg.Exception, Tocsg.Hex, Winapi.Windows, Tocsg.Strings, Tocsg.Safe,
|
|
AbUnzper, System.Zip, Tocsg.Path, Tocsg.OLE.Stg, Tocsg.Files;
|
|
|
|
function IsAipEncrytedPDF(sPath: String): Boolean;
|
|
var
|
|
fs: TFileStream;
|
|
pBuf: TBytes;
|
|
sDelPath: String;
|
|
begin
|
|
Result := false;
|
|
try
|
|
sDelPath := 'C:\ProgramData\HE\AEN\';
|
|
if sPath.ToUpper.StartsWith(sDelPath.ToUpper) then
|
|
exit;
|
|
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncrytedPDF() .. Path=%s, TempDir=%s', [sPath, sDelPath]));
|
|
|
|
if ForceDirectories(sDelPath) then
|
|
begin
|
|
sDelPath := sDelPath + '$' + ExtractFileName(sPath);
|
|
if CopyFile(PChar(sPath), PChar(sDelPath), false) then
|
|
begin
|
|
try
|
|
Guard(fs, TFileStream.Create(sDelPath, fmOpenRead or fmShareDenyNone));
|
|
SetLength(pBuf, 2048);
|
|
if fs.Read(pBuf[0], 2048) <> 2048 then
|
|
exit;
|
|
Result := PosBin(TEncoding.UTF8.GetBytes('MicrosoftIRMServices Protected PDF'), pBuf) <> -1;
|
|
finally
|
|
if sDelPath <> '' then
|
|
DeleteFileForce(sDelPath);
|
|
end;
|
|
end;
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. IsAipEncryted()');
|
|
end;
|
|
end;
|
|
|
|
function GetAipLabelNameFromPDF(sPath: String): String;
|
|
//const
|
|
// p: array [0..13] of Byte = ($FE, $FF, $C7, $7C, $BC, $18, $00, $20, $B8, $08, $C7, $74, $BE, $14); // "일반 레이블"
|
|
var
|
|
fs: TFileStream;
|
|
pBuf, pLabel: TBytes;
|
|
nBufLen, nPos, nEnd, nLabelLen: Integer;
|
|
begin
|
|
Result := 'Unknown';
|
|
try
|
|
if not FileExists(sPath) then
|
|
exit;
|
|
|
|
nBufLen := 1024;
|
|
SetLength(pBuf, nBufLen);
|
|
|
|
fs := TFileStream.Create(sPath, fmOpenRead or fmShareDenyNone);
|
|
// 암호화 레이블로 적용되었는지 확인
|
|
if fs.Read(pBuf[0], nBufLen) <> nBufLen then
|
|
exit;
|
|
|
|
if PosBin(TEncoding.UTF8.GetBytes('MicrosoftIRMServices Protected PDF'), pBuf) <> -1 then
|
|
begin
|
|
// 암호화된 레이블 정보 위치
|
|
fs.Seek(27440, soBeginning);
|
|
fs.Read(pBuf[0], nBufLen);
|
|
end else begin
|
|
// 일반 레이블 정보 위치
|
|
fs.Seek(-1024, soEnd);
|
|
fs.Read(pBuf[0], nBufLen);
|
|
end;
|
|
|
|
nPos := PosBin(TEncoding.UTF8.GetBytes('/MSIP_Label_'), pBuf);
|
|
if nPos > -1 then
|
|
begin
|
|
nPos := PosBin(TEncoding.UTF8.GetBytes('_Name ('), pBuf, nPos);
|
|
if nPos > -1 then
|
|
begin
|
|
Inc(nPos, 7);
|
|
nEnd := PosBin(TEncoding.UTF8.GetBytes(')'), pBuf, nPos);
|
|
nLabelLen := nEnd - nPos;
|
|
if (nEnd > -1) and (nLabelLen > 0) then
|
|
begin
|
|
SetLength(pLabel, nLabelLen);
|
|
CopyMemory(pLabel, @pBuf[nPos], nLabelLen);
|
|
if pLabel[0] = $FE then
|
|
Result := TEncoding.BigEndianUnicode.GetString(pLabel)
|
|
else
|
|
Result := TEncoding.ANSI.GetString(pLabel);
|
|
end;
|
|
end;
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. GetAipLabelNameFromPDF()');
|
|
end;
|
|
end;
|
|
|
|
function IsAipEncrytedOldOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
|
|
var
|
|
// fs: TFileStream;
|
|
// pBuf: TBytes;
|
|
// nBufLen: Integer;
|
|
pvStg: IStorage;
|
|
sData: WideString;
|
|
enum: IEnumStatStg;
|
|
elt: TStatStg;
|
|
sDelPath: String;
|
|
begin
|
|
Result := false;
|
|
try
|
|
if sPath.ToUpper.StartsWith(sTempDir.ToUpper) then
|
|
exit;
|
|
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncrytedOldOfficeDoc() .. Path=%s, TempDir=%s', [sPath, sTempDir]));
|
|
|
|
pvStg := nil;
|
|
sDelPath := '';
|
|
try
|
|
// 쉘 익스텐션 GetIconLocation() 에선 STGM_SHARE_EXCLUSIVE 모드 사용 시 스톱되서 아래처럼 처리 25_0122 14:03:25 kku
|
|
if not StgStorageFileOpen(sPath, pvStg, nMode) then
|
|
begin
|
|
if (sTempDir <> '') and ForceDirectories(sTempDir) then
|
|
begin
|
|
// MS 파일은 사용중이면 안열려서 이렇게 처리 24_1114 09:24:47 kku
|
|
sDelPath := sTempDir + '$' + ExtractFileName(sPath);
|
|
if CopyFile(PChar(sPath), PChar(sDelPath), false) then
|
|
begin
|
|
if not StgStorageFileOpen(sDelPath, pvStg) then
|
|
exit;
|
|
end else exit;
|
|
end else exit;
|
|
end;
|
|
|
|
if pvStg = nil then
|
|
exit;
|
|
|
|
enum := nil;
|
|
if StgGetEnumElements(pvStg, enum) then
|
|
Result := StgGetStatStgLike(enum, 'DRMContent', elt);
|
|
finally
|
|
enum := nil;
|
|
pvStg := nil;
|
|
if sDelPath <> '' then
|
|
DeleteFileForce(sDelPath);
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. IsAipEncrytedOldOfficeDoc()');
|
|
end;
|
|
end;
|
|
|
|
function GetAipLabelNameFromOldOfficeDoc(sPath: String): String;
|
|
begin
|
|
Result := 'Unknown';
|
|
end;
|
|
|
|
function IsAipEncrytedOfficeDoc(sPath, sTempDir: String; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
|
|
var
|
|
pvStg: IStorage;
|
|
sData: WideString;
|
|
sDelPath: String;
|
|
begin
|
|
Result := false;
|
|
try
|
|
if sPath.ToUpper.StartsWith(sTempDir.ToUpper) then
|
|
exit;
|
|
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncrytedOfficeDoc() .. Path=%s, TempDir=%s', [sPath, sTempDir]));
|
|
|
|
pvStg := nil;
|
|
sDelPath := '';
|
|
try
|
|
// 쉘 익스텐션 GetIconLocation() 에선 STGM_SHARE_EXCLUSIVE 모드 사용 시 스톱되서 아래처럼 처리 25_0122 14:03:25 kku
|
|
if not StgStorageFileOpen(sPath, pvStg, nMode) then
|
|
begin
|
|
// MS 파일은 사용중이면 안열려서 이렇게 처리 24_1114 09:24:47 kku
|
|
if (sTempDir <> '') and ForceDirectories(sTempDir) then
|
|
begin
|
|
// MS 파일은 사용중이면 안열려서 이렇게 처리 24_1114 09:24:47 kku
|
|
sDelPath := sTempDir + '$' + ExtractFileName(sPath);
|
|
if CopyFile(PChar(sPath), PChar(sDelPath), false) then
|
|
begin
|
|
if not StgStorageFileOpen(sDelPath, pvStg) then
|
|
exit;
|
|
end else exit;
|
|
end else exit;
|
|
end;
|
|
|
|
if pvStg = nil then
|
|
exit;
|
|
|
|
Result := StgGetStreamToText(pvStg, 'EncryptedPackage', sData);
|
|
finally
|
|
pvStg := nil;
|
|
if sDelPath <> '' then
|
|
DeleteFileForce(sDelPath);
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. IsAipEncrytedOldOfficeDoc()');
|
|
end;
|
|
end;
|
|
|
|
function GetAipLabelNameFromOfficeDoc(sPath: String): String;
|
|
begin
|
|
Result := 'Unknown';
|
|
end;
|
|
|
|
// MS문서 중 .pfile로 변경 가능성이 있는 확장자인지 체크 25_1222 17:52:57 kku
|
|
function CheckMsPfileExt(sPath: String): Boolean;
|
|
var
|
|
sExt: String;
|
|
begin
|
|
sExt := GetFileExt(sPath).ToUpper;
|
|
Result := (sExt = 'DOC') or (sExt = 'XLS') or (sExt = 'PPT') or
|
|
(sExt = 'DOT') or (sExt = 'PPS') or (sExt = 'POT') or
|
|
(sExt = 'XLT') or (sExt = 'XLTM') or (sExt = 'XLTX') or
|
|
(sExt = 'XPS') or (sExt = 'DOTM') or (sExt = 'PPSM') or
|
|
(sExt = 'PPSX') or (sExt = 'PPTM') or (sExt = 'XPS');
|
|
end;
|
|
|
|
function CheckAipEncSign(sPath: String): Boolean;
|
|
begin
|
|
Result := false;
|
|
try
|
|
if not FileExists(sPath) then
|
|
exit;
|
|
|
|
Result := CheckSign(sPath, @SIGN_AIP_DRM[0], 24);
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. CheckAipEncSign()');
|
|
end;
|
|
end;
|
|
|
|
function IsAipEncryted(sPath: String; sTempDir: String = ''; nMode: Integer = STGM_READ or STGM_SHARE_EXCLUSIVE): Boolean;
|
|
var
|
|
sExt: String;
|
|
begin
|
|
Result := false;
|
|
try
|
|
if not FileExists(sPath) then
|
|
exit;
|
|
|
|
if sPath.ToUpper.StartsWith(sTempDir.ToUpper) then
|
|
exit;
|
|
// WriteLnFileEndUTF8('C:\ProgramData\HE\ov_log.txt', Format('IsAipEncryted() .. Path=%s, TempDir=%s', [sPath, sTempDir]));
|
|
|
|
Result := CheckAipEncSign(sPath);
|
|
if not Result then
|
|
begin
|
|
sExt := GetFileExt(sPath).ToUpper;
|
|
if sExt = 'PDF' then
|
|
begin
|
|
Result := IsAipEncrytedPDF(sPath);
|
|
end else
|
|
if CheckMsPfileExt(sPath) then
|
|
begin
|
|
Result := IsAipEncrytedOldOfficeDoc(sPath, sTempDir, nMode);
|
|
if not Result then
|
|
Result := IsAipEncrytedOfficeDoc(sPath, sTempDir, nMode);
|
|
end else
|
|
if (sExt = 'DOCX') or (sExt = 'XLSX') or (sExt = 'PPTX') or
|
|
(sExt = 'DOCM') or (sExt = 'DOTX') or (sExt = 'XLSM') or
|
|
(sExt = 'XLSB') then
|
|
begin
|
|
Result := IsAipEncrytedOfficeDoc(sPath, sTempDir, nMode);
|
|
end;
|
|
end;
|
|
except
|
|
on E: Exception do
|
|
ETgException.TraceException(E, 'Fail .. IsAipEncryted()');
|
|
end;
|
|
end;
|
|
|
|
function ConvAipEncExt(sPath: String): String;
|
|
var
|
|
sExt, sPathNoExt: String;
|
|
begin
|
|
Result := sPath;
|
|
if sPath = '' then
|
|
exit;
|
|
|
|
sExt := GetFileExt(sPath).ToUpper;
|
|
sPathNoExt := CutFileExt(sPath);
|
|
|
|
if sExt = 'TXT' then
|
|
Result := sPathNoExt + '.ptxt'
|
|
else if sExt = 'XML' then
|
|
Result := sPathNoExt + '.pxml'
|
|
else if sExt = 'PNG' then
|
|
Result := sPathNoExt + '.ppng'
|
|
else if sExt = 'BMP' then
|
|
Result := sPathNoExt + '.pbmp'
|
|
else if sExt = 'JPG' then
|
|
Result := sPathNoExt + '.pjpg'
|
|
else if sExt = 'JPEG' then
|
|
Result := sPathNoExt + '.pjpeg'
|
|
else if (sExt <> 'DOCX') and (sExt <> 'XLSX') and
|
|
(sExt <> 'PPTX') and (sExt <> 'PDF') and
|
|
(sExt <> 'XLSB') and (sExt <> 'XLSM') and
|
|
(sExt <> 'DOTX') and (sExt <> 'DOCM') and
|
|
(sExt <> 'DOC') and (sExt <> 'XLS') and
|
|
(sExt <> 'PPT') and (sExt <> 'DOT') and
|
|
(sExt <> 'PPS') and (sExt <> 'POT') and
|
|
(sExt <> 'XLT') and (sExt <> 'XLTM') and (sExt <> 'XLTX') and
|
|
(sExt <> 'XPS') and (sExt <> 'DOTM') and (sExt <> 'PPSM') and
|
|
(sExt <> 'PPSX') and (sExt <> 'PPTM') and (sExt <> 'XPS') then
|
|
begin
|
|
Result := sPath + '.pfile';
|
|
end;
|
|
end;
|
|
|
|
end.
|