{*******************************************************} { } { Tocsg.DRM.Encrypt } { } { Copyright (C) 2022 kkuzil } { } {*******************************************************} unit Tocsg.DRM.Encrypt; interface uses Tocsg.Obj, System.SysUtils, System.Classes, Winapi.Windows; const DRM_VER = 3; // 2 : 헤더 문자열 정보에 솔트 추가 22_1019 12:48:14 kku MAX_HEAD_STR = 260; type TTgDrmHead = packed record // size = 1574 wVer: WORD; dwCustomerCode: DWORD; sEmpNo, sHostName, sPartName, sPgName, sReserve1, sReserve2: array [0..MAX_HEAD_STR-1] of UTF8Char; dtEnc: TDateTime; // ullEncTS: ULONGLONG; // DRM_VER 3 이상 // sReserve3: array [0..17] of AnsiChar; // DRM_VER 3 이상 end; TTgDrmBase = class(TTgObject) protected bFreeStream_: Boolean; Stream_: TStream; Head_: TTgDrmHead; public Constructor Create(aStream: TStream; bFreeStream: Boolean = true); Destructor Destroy; override; end; TTgDrmEnc = class(TTgDrmBase) public Constructor Create(sPath: String); function SetHaed(sKey, sSig, sEmpNo, sHostName, sPartName, sPgName: UTF8String; dwCode: DWORD): Boolean; function EncryptFromFile(sKey: String; sPath: String): Boolean; function EncryptFromStream(sKey: String; aSrcStream: TStream): Boolean; end; TTgDrmDec = class(TTgDrmBase) private sEmpNo_, sHostName_, sPartName_, sPgName_: String; public Constructor Create(sEncPath: String); overload; Constructor Create(aStream: TStream; bFreeStream: Boolean = true); overload; function CheckSig(sSig: AnsiString): Boolean; function ExtrHead(sKey: String): Boolean; function DecryptToFile(sKey: String; sPath: String): Boolean; function DecryptToStream(sKey: String; aDecStream: TStream): Boolean; property Head: TTgDrmHead read Head_; property EmpNo: String read sEmpNo_; property HostName: String read sHostName_; property PartName: String read sPartName_; property PolicyGroup: String read sPgName_; end; implementation uses Tocsg.Encrypt, Tocsg.Safe, Tocsg.Exception, Tocsg.Strings; { TTgDrmBase } Constructor TTgDrmBase.Create(aStream: TStream; bFreeStream: Boolean = true); begin Inherited Create; ZeroMemory(@Head_, SizeOf(Head_)); Head_.wVer := DRM_VER; Stream_ := aStream; bFreeStream_ := bFreeStream; end; Destructor TTgDrmBase.Destroy; begin if bFreeStream_ and (Stream_ <> nil) then FreeAndNil(Stream_); Inherited; end; { TTgDrmEnc } Constructor TTgDrmEnc.Create(sPath: String); var fs: TFileStream; begin try fs := TFileStream.Create(sPath, fmCreate); except on E: Exception do begin Inherited Create(nil, false); ETgException.TraceException(Self, E, 'Fail .. Create(Path)'); exit; end; end; Inherited Create(fs); end; function TTgDrmEnc.SetHaed(sKey, sSig, sEmpNo, sHostName, sPartName, sPgName: UTF8String; dwCode: DWORD): Boolean; var enc: TTgEncrypt; nLen: Integer; pEncBuf: TBytes; begin Result := false; try {$IFDEF DEBUG} ASSERT(Stream_ <> nil); {$ENDIF} if Stream_ = nil then begin _Trace('Fail .. SetHaed() .. Stream is nil'); exit; end; Stream_.Position := 0; if sSig <> '' then Stream_.Write(sSig[1], Length(sSig)); if Length(sEmpNo) < 250 then sEmpNo := sEmpNo + '§+' + GetRandomStr(5, 8); if Length(sHostName) < 250 then sHostName := sHostName + '§+' + GetRandomStr(5, 8); if Length(sPartName) < 250 then sPartName := sPartName + '§+' + GetRandomStr(5, 8); if Length(sPgName) < 250 then sPgName := sPgName + '§+' + GetRandomStr(5, 8); StrCopy(Head_.sEmpNo, PUTF8Char(sEmpNo)); StrCopy(Head_.sHostName, PUTF8Char(sHostName)); StrCopy(Head_.sPartName, PUTF8Char(sPartName)); StrCopy(Head_.sPgName, PUTF8Char(sPgName)); Head_.dwCustomerCode := dwCode; // Head_.dtEnc := Now; Guard(enc, TTgEncrypt.Create(sKey, ekAes256cbc)); nLen := SizeOf(Head_); enc.InitEncrypt; pEncBuf := enc.EncryptBuffer(@Head_, nLen); {$IFDEF DEBUG} ASSERT(Length(pEncBuf) = nLen); {$ELSE} if Length(pEncBuf) <> nLen then begin _Trace('Fail .. Encrypt Head .. HeadLen=%d, OutLen=%d', [nLen, Length(pEncBuf)]); exit; end; {$ENDIF} Stream_.Write(pEncBuf[0], nLen); Result := true; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. SetHaed()'); end; end; function TTgDrmEnc.EncryptFromFile(sKey: String; sPath: String): Boolean; var fs: TFileStream; begin Result := false; try Guard(fs, TFileStream.Create(sPath, fmOpenRead)); Result := EncryptFromStream(sKey, fs); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. EncryptFromFile()'); end; end; function TTgDrmEnc.EncryptFromStream(sKey: String; aSrcStream: TStream): Boolean; var enc: TTgEncrypt; sDateTime: String; begin Result := false; {$IFDEF DEBUG} ASSERT(Stream_ <> nil); {$ENDIF} if Stream_ = nil then begin _Trace('Fail .. EncryptFromStream() .. Stream is nil'); exit; end; try if Head_.dtEnc <> 0 then sDateTime := FormatDateTime('yyyymmddhhnnss', Head_.dtEnc) else sDateTime := ''; Guard(enc, TTgEncrypt.Create(sDateTime + sKey, ekAes256cbc)); Result := enc.EncryptStream(aSrcStream, Stream_, '', phNone); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. EncryptFromStream()'); end; end; { TTgDrmDec } Constructor TTgDrmDec.Create(sEncPath: String); var fs: TFileStream; begin try fs := TFileStream.Create(sEncPath, fmOpenRead or fmShareDenyNone); except on E: Exception do begin Create(nil, false); ETgException.TraceException(Self, E, 'Fail .. Create(Path)'); exit; end; end; Create(fs); end; Constructor TTgDrmDec.Create(aStream: TStream; bFreeStream: Boolean = true); begin Inherited Create(aStream, bFreeStream); end; function TTgDrmDec.CheckSig(sSig: AnsiString): Boolean; var nLen: Integer; pBuf: TBytes; begin Result := false; {$IFDEF DEBUG} ASSERT(Stream_ <> nil); {$ENDIF} if Stream_ = nil then begin if Stream_ is TFileStream then _Trace('Fail .. CheckSig() .. Stream is nil, FileName=%s', [TFileStream(Stream_).FileName]) else _Trace('Fail .. CheckSig() .. Stream is nil'); exit; end; try nLen := Length(sSig); if Stream_.Size <= nLen then begin if Stream_ is TFileStream then _Trace('Fail .. CheckSig() .. Stream size not enouth, FileName=%s, StreamSize=%d', [TFileStream(Stream_).FileName, Stream_.Size]) else _Trace('Fail .. CheckSig() .. Stream size not enouth, StreamSize=%d', [Stream_.Size]); exit; end; Stream_.Position := 0; if nLen > 0 then begin SetLength(pBuf, nLen); Stream_.Read(pBuf[0], nLen); Result := CompareMem(@pBuf[0], @sSig[1], nLen); end else Result := true; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. CheckSig()'); end; end; function TTgDrmDec.ExtrHead(sKey: String): Boolean; function GetStr(var arrStr: array of UTF8Char): String; var nPos: Integer; begin Result := UTF8String(arrStr); if Head_.wVer <= 1 then exit; nPos := Pos('§+', Result); if nPos = 0 then exit; SetLength(Result, nPos - 1); FillChar(arrStr[nPos - 1], MAX_HEAD_STR - nPos, #0); end; var nLen: Integer; enc: TTgEncrypt; pEncBuf, pBuf: TBytes; // bRetry: Boolean; //Label // LB_Retry; begin Result := false; {$IFDEF DEBUG} ASSERT(Stream_ <> nil); {$ENDIF} if Stream_ = nil then begin _Trace('Fail .. ExtrHead() .. Stream is nil'); exit; end; // bRetry := false; try nLen := SizeOf(Head_); if (Stream_.Size - Stream_.Position) <= nLen then begin _Trace('Fail .. CheckSig() .. Stream size not enouth, StreamSize=%d', [Stream_.Size]); exit; end; // LB_Retry : SetLength(pEncBuf, nLen); Stream_.Read(pEncBuf[0], nLen); enc := TTgEncrypt.Create(sKey, ekAes256cbc); try enc.InitDecrypt; pBuf := enc.DecryptBuffer(@pEncBuf[0], nLen); if Length(pBuf) <> nLen then begin _Trace('Fail .. ExtrHead() .. DecryptBufferEx()'); exit; end; finally enc.Free; end; // var fs: TFileStream; // Guard(fs, TFileStream.Create('C:\taskToCSG\eCrmHE\Utils\EXE_Bs1Drm4c\x64\Debug\test_d.dat', fmCreate)); // fs.Write(pBuf[0], nLen); CopyMemory(@Head_, @pBuf[0], nLen); Result := Head_.wVer <> 0; sEmpNo_ := GetStr(Head_.sEmpNo); sHostName_ := GetStr(Head_.sHostName); sPartName_ := GetStr(Head_.sPartName); sPgName_ := GetStr(Head_.sPgName); // if not bRetry and (Head_.wVer < 3) then // begin // ZeroMemory(@Head_, SizeOf(Head_)); // nLen := 1574; // 구버전 헤더 크기 // Stream_.Position := 5; // bRetry := true; // goto LB_Retry; // end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. ExtrHead()'); end; end; function TTgDrmDec.DecryptToFile(sKey: String; sPath: String): Boolean; var fs: TFileStream; begin Result := false; try Guard(fs, TFileStream.Create(sPath, fmCreate)); Result := DecryptToStream(sKey, fs); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DecryptToFile()'); end; end; function TTgDrmDec.DecryptToStream(sKey: String; aDecStream: TStream): Boolean; var enc: TTgEncrypt; sDateTime: String; begin Result := false; {$IFDEF DEBUG} ASSERT(Stream_ <> nil); {$ENDIF} if Stream_ = nil then begin _Trace('Fail .. DecryptToStream() .. Stream is nil'); exit; end; try if Head_.wVer = 0 then begin _Trace('Fail .. DecryptToStream() .. No Extract headInfo'); exit; end; if Head_.dtEnc <> 0 then sDateTime := FormatDateTime('yyyymmddhhnnss', Head_.dtEnc) else sDateTime := ''; Guard(enc, TTgEncrypt.Create(sDateTime + sKey, ekAes256cbc)); Result := enc.DecryptStream(Stream_, aDecStream, '', phNone); except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. DecryptToStream()'); end; end; end.