BSOne.SFC/Tocsg.Module/TocsgDRM/LIB_Common/Tocsg.DRM.Encrypt.pas

424 lines
10 KiB
Plaintext

{*******************************************************}
{ }
{ 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.