보안인증확인서 사용자 인증 및 암복호화

1. 사용자 인증 : Tocsg.Module\UserAuthentification
2. 암복호화 클래스
 - Tocsg.Lib\VCL\Tocsg.COLib.Encrypt.pas
 - Tocsg.Lib\VCL\Tocsg.COLib.pas
3. 캠페인 및 암호화
 - Tocsg.Module\ContentSearch\EXE_KvCttSch\ThdCttSch.pas
This commit is contained in:
yh.kim 2026-03-20 17:21:37 +09:00
parent c2ba523c24
commit a2da00c688
369 changed files with 253692 additions and 250648 deletions

View File

@ -0,0 +1,664 @@
unit Tocsg.COLib.Encrypt;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, Vcl.Dialogs, System.Math, System.IOUtils,
Tocsg.COLib, Tocsg.Safe;
const
SIG_CO_DRM = 'ToCSG_CO';
DRM_CO_VER = 1;
MAX_HEAD_STR = 260;
type
// 헤더 구조체 (Packed로 선언하여 메모리 정렬 고정)
TTgDrmHead = packed record
wVer: WORD;
dwCustomerCode: DWORD;
sEmpNo,
sHostName,
sPartName,
sPgName: array [0..MAX_HEAD_STR - 1] of UTF8Char;
dtEnc: TDateTime;
end;
TTgColibDrm = class
private
class function EncryptKEK(const pKek: TBytes; const sFilePath: string): Boolean;
class function DecryptKEK(const sPath: string): TBytes;
class procedure EncryptDEKtoKEK(const pDek, pKek: TBytes);
class function DecryptDEKtoKEK(sPath:string; pKek:TBytes): TBytes;
class function CheckSig(aStream: TStream): Boolean;
// 헤더 정보를 읽고 복호화하여 스트림 위치를 데이터 시작점으로 이동
class function ExtractHead(aSrcStream: TStream; pDek: TBytes; var aHead: TTgDrmHead): Boolean;
public
class function CreateSalt(const iKeylen: Integer): TBytes;
class function CreateKEK(const sPass, sSalt: AnsiString; Iterations, iKeyLen: Integer): TBytes;
class procedure CreateDEK(const iKeylen: Integer; pKek: TBytes);
class function GetKEK(sPath:string ): TBytes;
class function GetDEK(sPath:string; pKek:TBytes): TBytes;
// 헤더 정보를 생성하고 파일 스트림에 기록
//class function SetHead(aDstStream: TStream; pDek: TBytes; sEmpNo, sHostName, sPartName, sPgName: UTF8String): Boolean;
//class procedure DoEncrypt(sPath: string; pDek: TBytes; sEmpNo, sHostName, sPartName, sPgName: UTF8String);
class function SetHead(aDstStream: TStream; pDek: TBytes): Boolean;
class function DoEncrypt(sPath: string; pDek: TBytes): Boolean;
class procedure DoDecrypt(sPath: string; pDek: TBytes);
class function IsEncrypt(sPath: string): Boolean;
end;
implementation
{ TTgColibDrm }
type
TDataBlob = record
cbData: DWORD;
pbData: PByte;
end;
PDataBlob = ^TDataBlob;
function CryptProtectData(pDataIn: PDataBlob; szDataDescr: PWideChar;
pOptionalEntropy: PDataBlob; pvReserved: Pointer; pPromptStruct: Pointer;
dwFlags: DWORD; pDataOut: PDataBlob): BOOL; stdcall;
external 'crypt32.dll' name 'CryptProtectData';
function CryptUnprotectData(pDataIn: PDataBlob; ppszDataDescr: PPWideChar;
pOptionalEntropy: PDataBlob; pvReserved: Pointer; pPromptStruct: Pointer;
dwFlags: DWORD; pDataOut: PDataBlob): BOOL; stdcall;
external 'crypt32.dll' name 'CryptUnprotectData';
function ConcatBytes(const pBuf1, pBuf2: TBytes): TBytes;
begin
SetLength(Result, Length(pBuf1) + Length(pBuf2));
Move(pBuf1[0], Result[0], Length(pBuf1));
Move(pBuf2[0], Result[Length(pBuf1)], Length(pBuf2));
end;
procedure XORBytes(var pBuf1: TBytes; const pBuf2: TBytes);
var
i: Integer;
begin
for i := 0 to Min(Length(pBuf1), Length(pBuf2)) - 1 do
pBuf1[i] := pBuf1[i] xor pBuf2[i];
end;
class function TTgColibDrm.CreateSalt(const iKeylen: Integer): TBytes;
var
nResult: Integer;
pSalt: TBytes;
sPath: string;
begin
sPath := 'salt.bin';
if TFile.Exists(sPath) then
begin
Result := TFile.ReadAllBytes(sPath);
Exit;
end;
// 파일이 없는 경우: 새로운 Salt 생성
SetLength(pSalt, iKeylen);
// SHA-256 난수
nResult := COLibDrbg(@pSalt[0], Length(pSalt), nil, 0, nil, 0, 0);
if nResult = COLIB_SUCCESS then
begin
// 생성 성공 시 파일로 기록
try
TFile.WriteAllBytes(sPath, pSalt);
Result := pSalt;
except
on E: Exception do
begin
ShowMessage('Salt 파일 저장 중 오류: ' + E.Message);
Result := nil;
end;
end;
end
else
begin
// 생성 실패 시 처리
ShowMessage('Salt 생성 실패: ' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
Result := nil;
end;
end;
class function TTgColibDrm.EncryptKEK(const pKek: TBytes; const sFilePath: string): Boolean;
var
DataIn, DataOut: TDataBlob;
FileStream: TFileStream;
begin
Result := False;
if Length(pKek) = 0 then
begin
ShowMessage('KEK가 비어있습니다.');
Exit;
end;
// TBytes 데이터를 DataIn 구조체에 연결
DataIn.pbData := @pKek[0];
DataIn.cbData := Length(pKek);
// DPAPI 암호화 호출 (현재 사용자 계정으로만 복호화 가능하도록 설정)
// 세 번째 인자는 엔트로피(추가 암호)
if CryptProtectData(@DataIn, nil, nil, nil, nil, 0, @DataOut) then
begin
try
FileStream := TFileStream.Create(sFilePath, fmCreate);
try
FileStream.WriteBuffer(DataOut.pbData^, DataOut.cbData);
Result := True;
finally
FileStream.Free;
end;
finally
// DPAPI에서 할당한 메모리 해제
LocalFree(HLOCAL(DataOut.pbData));
end;
end
else
begin
ShowMessage('CryptProtectData is failed: ' + IntToStr(GetLastError));
end;
end;
class function TTgColibDrm.DecryptKEK(const sPath: string): TBytes;
var
DataIn, DataOut: TDataBlob;
ms: TMemoryStream;
begin
SetLength(Result, 0);
if not FileExists(sPath) then
begin
ShowMessage('KEK가 존재하지 않습니다');
Exit;
end;
ms := TMemoryStream.Create;
try
ms.LoadFromFile(sPath);
DataIn.pbData := ms.Memory;
DataIn.cbData := ms.Size;
// DPAPI 복호화 호출
if CryptUnprotectData(@DataIn, nil, nil, nil, nil, 0, @DataOut) then
begin
try
// 복호화된 바이너리 데이터를 TBytes로 복사
SetLength(Result, DataOut.cbData);
if DataOut.cbData > 0 then
Move(DataOut.pbData^, Result[0], DataOut.cbData);
finally
LocalFree(HLOCAL(DataOut.pbData));
end;
end
else
begin
ShowMessage('CryptUnprotectData is failed: ' + IntToStr(GetLastError));
end;
finally
ms.Free;
end;
end;
class function TTgColibDrm.CreateKEK(const sPass, sSalt: AnsiString; Iterations, iKeyLen: Integer): TBytes;
var
i, n, nBlockCnt: Integer;
pSaltAndBlkIdx, pBlockIdx, pTemp, U_prev, U_current, pPass, pSalt: TBytes;
ci: TCIPHER_INFO;
nOut, nResult: Integer;
path: string;
begin
path := 'kek.bin';
if TFile.Exists(path) then
begin
// 파일이 존재하면 복호화후 리턴
//ShowMessage('실제 감지된 경로: ' + TPath.GetFullPath(path));
Result := DecryptKEK(path);
Exit;
end;
SetLength(Result, iKeyLen);
ZeroMemory(Result, iKeyLen);
if (sPass = '') or (sSalt = '') then
exit;
n := Length(sPass);
if n < 16 then
begin
SetLength(pPass, 16);
ZeroMemory(pPass, 16);
end else
SetLength(pPass, n);
CopyMemory(pPass, @sPass[1], n);
n := Length(sSalt);
SetLength(pSalt, n);
CopyMemory(pSalt, @sSalt[1], n);
ZeroMemory(@ci, SizeOf(ci));
SetLength(pBlockIdx, 4);
SetLength(pTemp, iKeyLen);
SetLength(U_prev, iKeyLen);
SetLength(U_current, iKeyLen);
// PBKDF
// 32바이트 단위(SHA256)의 각 블록마다 다음을 수행
// 1) U₁ = HMAC(Pass, Salt || BlockIndex)
// 2) U_n = HMAC(Pass, U_{n-1})
// 3) U_{n-1} XOR U_n
// 32 바이트씩 나눠서 블록개수 계산
nBlockCnt := (iKeyLen + 31) div iKeyLen; // SHA256 = 32 bytes
for i := 1 to nBlockCnt do
begin
// BlockIndex = i (Big Endian)
// 블록 번호를 Big Endian으로 표현한 4바이트 ex) i=[0,0,0,1]
// int(i)로 표현
pBlockIdx[0] := Byte((i shr 24) and $FF);
pBlockIdx[1] := Byte((i shr 16) and $FF);
pBlockIdx[2] := Byte((i shr 8) and $FF);
pBlockIdx[3] := Byte(i and $FF);
// Salt || int(i)
pSaltAndBlkIdx := ConcatBytes(pSalt, pBlockIdx);
nOut := 0;
// 1) U₁ = HMAC(Pass, Salt || BlockIndex)
COLibSetCipherInfo(@ci, COLIB_MODE_HMAC, BLOCK_CRYPTO_MODE_UNUSED, COLIB_PAD_TYPE_UNUSED,
@pPass[0], Length(pPass), nil, 0, @pSaltAndBlkIdx[0], Length(pSaltAndBlkIdx), @U_prev[0], @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
exit;
CopyMemory(pTemp, U_prev, Length(U_prev));
for n := 2 to Iterations do
begin
nOut := 0;
// 2) U_n = HMAC(Pass, U_{n-1})
COLibSetCipherInfo(@ci, COLIB_MODE_HMAC, BLOCK_CRYPTO_MODE_UNUSED, COLIB_PAD_TYPE_UNUSED,
@pPass[0], Length(pPass), nil, 0, @U_prev[0], Length(U_prev), @U_current[0], @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
exit;
// 3) U_{n-1} XOR U_n
XORBytes(pTemp, U_current);
CopyMemory(U_prev, U_current, Length(U_current));
end;
Move(pTemp[0], Result[(i - 1) * iKeyLen], Min(iKeyLen, iKeyLen - (i - 1) * iKeyLen));
end;
if not (EncryptKEK(Result, path)) then
begin
ZeroMemory(Result, iKeyLen);
ShowMessage('EncryptKEK is failed');
end;
end;
class function TTgColibDrm.GetKEK(sPath:string): TBytes;
begin
if TFile.Exists(sPath) then
begin
Result := DecryptKEK(sPath);
end
else
begin
//ShowMessage('KEK가 존재하지 않습니다');
Result := nil;
end;
end;
class function TTgColibDrm.GetDEK(sPath:string; pKek:TBytes): TBytes;
begin
if TFile.Exists(sPath) then
begin
Result := DecryptDEKtoKEK(sPath, pKek);
end
else
begin
//ShowMessage('DEK가 존재하지 않습니다.');
Result := nil;
end;
end;
class procedure TTgColibDrm.EncryptDEKtoKEK(const pDek, pKek: TBytes);
var
nResult, nOut: Integer;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
arrEnc: TBytes;
sOut, sIn: string;
begin
ZeroMemory(@ci, SizeOf(ci));
ZeroMemory(@arrIV, SizeOf(arrIV));
SetLength(arrEnc, Length(pDek)*2);
// for var i := 0 to Length(pDek) - 1 do
// sIn := sIn + Format('%.2x', [pDek[i]]);
// ShowMessage('평문 DEK (Hex) : ' + Inttostr(Length(pDek))+', '+sIn);
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_NO,
@pKek[0], Length(pKek), @arrIV, SizeOf(arrIV),
@pDek[0], Length(pDek), @arrEnc[0], @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
ShowMessage('COLibEncrypt is failed: ' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
Exit;
end;
// for var i := 0 to nOut - 1 do
// sOut := sOut + Format('%.2x', [arrEnc[i]]);
// ShowMessage('암호화 DEK (Hex) : ' + Inttostr(nOut)+', '+sOut);
// 암호화된 DEK를 바이너리 그대로 파일에 저장
TFile.WriteAllBytes('dek.bin', Copy(arrEnc, 0, nOut));
end;
class procedure TTgColibDrm.CreateDEK(const iKeylen: Integer; pKek: TBytes);
var
pDek: TBytes;
sPath: string;
begin
sPath := 'dek.bin';
if TFile.Exists(sPath) then
begin
Exit;
end;
SetLength(pDek, iKeylen);
COLibGetKey(@pDek[0], iKeylen);
EncryptDEKtoKEK(pDek, pKek);
end;
class function TTgColibDrm.DecryptDEKtoKEK(sPath:string; pKek:TBytes): TBytes;
var
nResult, nOut: Integer;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
arrDec, encDek: TBytes;
sOut, sIn: string;
begin
ZeroMemory(@ci, SizeOf(ci));
ZeroMemory(@arrIV, SizeOf(arrIV));
// if not TFile.Exists(sPath) then
// begin
// ShowMessage('DEK 존재하지 않음');
// Result := nil;
// Exit;
// end;
encDek := TFile.ReadAllBytes(sPath);
SetLength(arrDec, Length(encDek)); // 암호문 길이만큼 버퍼 확보
// for var i := 0 to Length(encDek) - 1 do
// sIn := sIn + Format('%.2x', [encDek[i]]);
// ShowMessage('암호화된 DEK (Hex) : ' + Inttostr(Length(encDek))+', '+sIn);
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_NO,
@pKek[0], Length(pKek), @arrIV, SizeOf(arrIV),
@encDek[0], Length(encDek), @arrDec[0], @nOut);
nResult := COLibDecrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
ShowMessage('COLibDecrypt is failed: ' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
Result := nil;
Exit;
end;
// 실제 복호화된 길이만큼 잘라내기
//SetLength(arrDec, nOut);
// for var i := 0 to nOut - 1 do
// sOut := sOut + Format('%.2x', [arrDec[i]]);
// ShowMessage('복호화 DEK (Hex) : ' + Inttostr(Length(arrDec))+', '+sOut);
Result := arrDec;
end;
class function TTgColibDrm.CheckSig(aStream: TStream): Boolean;
var
sSig: AnsiString;
pBuf: array[0..7] of AnsiChar; // SIG_CO_DRM 길이만큼
begin
Result := False;
if aStream.Size < Length(SIG_CO_DRM) then Exit;
aStream.Position := 0;
aStream.Read(pBuf, Length(SIG_CO_DRM));
sSig := Copy(pBuf, 0, Length(SIG_CO_DRM));
Result := (sSig = SIG_CO_DRM);
end;
class function TTgColibDrm.IsEncrypt(sPath: string): Boolean;
var
fs: TFileStream;
begin
Result := False;
if not FileExists(sPath) then Exit;
try
Guard(fs, TFileStream.Create(sPath, fmOpenRead or fmShareDenyNone));
Result := CheckSig(fs);
except
Result := False;
end;
end;
class function TTgColibDrm.SetHead(aDstStream: TStream; pDek: TBytes): Boolean;
var
Head: TTgDrmHead;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
pEncHead: TBytes;
nOut, nResult: Integer;
begin
Result := False;
ZeroMemory(@Head, SizeOf(Head));
Head.wVer := DRM_CO_VER;
Head.dwCustomerCode := 13001;
Head.dtEnc := Now;
//Head.llEncDT := DelphiDtToJavaDt(Now);
StrCopy(Head.sPgName, PUTF8Char(SIG_CO_DRM));
StrCopy(Head.sEmpNo, PUTF8Char(SIG_CO_DRM));
StrCopy(Head.sPartName, PUTF8Char(SIG_CO_DRM));
StrCopy(Head.sHostName, PUTF8Char(SIG_CO_DRM));
// Move(PAnsiChar(sEmpNo)^, Head.sEmpNo[0], Min(Length(sEmpNo), MAX_HEAD_STR));
// Move(PAnsiChar(sHostName)^, Head.sHostName[0], Min(Length(sHostName), MAX_HEAD_STR));
// Move(PAnsiChar(sPartName)^, Head.sPartName[0], Min(Length(sPartName), MAX_HEAD_STR));
// Move(PAnsiChar(sPgName)^, Head.sPgName[0], Min(Length(sPgName), MAX_HEAD_STR));
// 헤더 암호화
ZeroMemory(@ci, SizeOf(ci));
ZeroMemory(@arrIV, SizeOf(arrIV));
SetLength(pEncHead, SizeOf(Head) + 16); // 패딩 고려
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_PKCS,
@pDek[0], Length(pDek), @arrIV, SizeOf(arrIV),
@Head, SizeOf(Head), @pEncHead[0], @nOut);
nResult := COLibEncrypt(@ci);
if nResult = COLIB_SUCCESS then
begin
// 암호화된 헤더 길이(Integer, 4byte)를 먼저 쓰고 데이터를 씀 (복호화 시 필요)
aDstStream.Write(nOut, SizeOf(Integer));
aDstStream.Write(pEncHead[0], nOut);
Result := True;
end;
end;
class function TTgColibDrm.DoEncrypt(sPath: string; pDek: TBytes): Boolean;
const
BUF_LEN_64K = 1024 * 64;
var
fsSrc, fsDst: TFileStream;
arrBuf: array [0..BUF_LEN_64K-1] of Byte;
arrEnc: array [0..BUF_LEN_64K + 31] of Byte; // 패딩 대비 여유 공간
dwRead: DWORD;
nOut, nResult: Integer;
pt: TCOLIB_PAD_TYPE;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
sSig: AnsiString;
begin
sSig := SIG_CO_DRM;
ZeroMemory(@arrIV, SizeOf(arrIV));
Guard(fsSrc, TFileStream.Create(sPath, fmOpenRead));
Guard(fsDst, TFileStream.Create(sPath + '.enc', fmCreate));
// 시그니처 (평문)
fsDst.Write(sSig[1], Length(sSig));
if not SetHead(fsDst, pDek) then Exit;
while fsSrc.Position < fsSrc.Size do
begin
dwRead := fsSrc.Read(arrBuf, BUF_LEN_64K);
// 마지막 블록인 경우 패딩 처리
if fsSrc.Position >= fsSrc.Size then
pt := COLIB_PAD_TYPE_PKCS
else
pt := COLIB_PAD_TYPE_NO;
ZeroMemory(@ci, SizeOf(ci));
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, pt,
@pDek[0], Length(pDek), @arrIV, SizeOf(arrIV),
@arrBuf, dwRead, @arrEnc, @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
ShowMessage('파일 암호화 실패: ' + IntToStr(nResult));
Result := False;
Exit;
end;
fsDst.Write(arrEnc, nOut);
Result := True;
// CBC 모드이므로 다음 블록의 IV는 현재 암호문의 마지막 블록이어야 함 (라이브러리 내부 처리 확인 필요)
// 만약 라이브러리가 IV를 자동 갱신하지 않는다면 여기서 마지막 암호문 블록을 arrIV에 복사해야 한다.
end;
end;
class function TTgColibDrm.ExtractHead(aSrcStream: TStream; pDek: TBytes; var aHead: TTgDrmHead): Boolean;
var
nEncHeadLen, nOut, nResult: Integer;
pEncBuf, pDecBuf: TBytes;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
begin
Result := False;
// 암호화된 헤더 길이 (4바이트)
if aSrcStream.Read(nEncHeadLen, SizeOf(Integer)) <> SizeOf(Integer) then Exit;
// 암호화된 헤더 본문
SetLength(pEncBuf, nEncHeadLen);
if aSrcStream.Read(pEncBuf[0], nEncHeadLen) <> nEncHeadLen then Exit;
// 헤더 복호화
SetLength(pDecBuf, nEncHeadLen);
ZeroMemory(@ci, SizeOf(ci));
ZeroMemory(@arrIV, SizeOf(arrIV));
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_PKCS,
@pDek[0], Length(pDek), @arrIV, SizeOf(arrIV),
@pEncBuf[0], nEncHeadLen, @pDecBuf[0], @nOut);
nResult := COLibDecrypt(@ci);
if nResult = COLIB_SUCCESS then
begin
Move(pDecBuf[0], aHead, SizeOf(TTgDrmHead));
Result := True;
end;
end;
class procedure TTgColibDrm.DoDecrypt(sPath: string; pDek:TBytes);
const
BUF_LEN_64K = 1024 * 64;
var
fsSrc, fsDst: TFileStream;
arrBuf: array [0..BUF_LEN_64K - 1] of Byte;
arrDec: array [0..BUF_LEN_64K + 31] of Byte; // 패딩 대비 여유 공간
dwRead: DWORD;
nOut, nResult: Integer;
pt: TCOLIB_PAD_TYPE;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN - 1] of Byte;
HeaderInfo: TTgDrmHead; // 복호화된 헤더 정보를 담을 변수
begin
Guard(fsSrc, TFileStream.Create(sPath, fmOpenRead or fmShareDenyNone));
// 기존 파일명에서 .enc가 있다면 제거하고 .dec를 붙임
Guard(fsDst, TFileStream.Create(ChangeFileExt(sPath, '') + '.dec', fmCreate));
try
// 시그니처 위치(8바이트) 건너뛰기
fsSrc.Position := Length(SIG_CO_DRM);
// 헤더 추출 및 복호화 (데이터 시작 지점으로 스트림 포인터 이동)
if not ExtractHead(fsSrc, pDek, HeaderInfo) then
begin
ShowMessage('헤더 복호화에 실패했습니다. 키 값이 올바르지 않을 수 있습니다.');
Exit;
end;
// 복호화된 헤더 정보 활용
// ShowMessage('복호화 대상 사번: ' + string(UTF8String(HeaderInfo.sEmpNo)));
ZeroMemory(@arrIV, SizeOf(arrIV));
while fsSrc.Position < fsSrc.Size do
begin
dwRead := fsSrc.Read(arrBuf, BUF_LEN_64K);
// 스트림의 마지막 블록인 경우에만 PKCS 패딩 적용
if fsSrc.Position >= fsSrc.Size then
pt := COLIB_PAD_TYPE_PKCS
else
pt := COLIB_PAD_TYPE_NO;
ZeroMemory(@ci, SizeOf(ci));
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, pt,
@pDek[0], Length(pDek), @arrIV, SizeOf(arrIV),
@arrBuf, dwRead, @arrDec, @nOut);
nResult := COLibDecrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
ShowMessage('데이터 복호화 중 오류 발생: ' + IntToStr(nResult));
Exit;
end;
fsDst.Write(arrDec, nOut);
end;
//ShowMessage('복호화가 완료되었습니다.');
except
on E: Exception do
ShowMessage('복호화 중 예외 발생: ' + E.Message);
end;
end;
end.

View File

@ -0,0 +1,533 @@
{*******************************************************}
{ }
{ Tocsg.COLib }
{ }
{ Copyright (C) 2025 kku }
{ }
{*******************************************************}
unit Tocsg.COLib;
interface
uses
System.SysUtils, Winapi.Windows;
const
{$IFDEF WIN64}
DLL_COLIB = 'colib64.dll';
{$ELSE}
DLL_COLIB = 'colib.dll';
{$ENDIF}
(*************** Definitions / Macros *************************************)
MEM_MARGIN_1 = 1;
MPZ_WORD_LEN = 500 + MEM_MARGIN_1;
COLIB_BLOCK_LEN = 16;
SHA512_DIGEST_SIZE = 64;
SHA256_DIGEST_SIZE = 32;
COLIB_128BIT_KEY_LEN = 16;
COLIB_192BIT_KEY_LEN = 24;
COLIB_256BIT_KEY_LEN = 32;
// Error -----------------------------------------------------------------------
// TCOLIB_ERROR = (
COLIB_SUCCESS = 0;
COLIB_ERROR_FATAL = 100;
COLIB_ERROR_ALREADY_INIT = 101;
COLIB_ERROR_UNSUPPORTED_MODE = 102;
COLIB_ERROR_UNSUPPORTED_RSA_KEY = 103;
COLIB_ERROR_FILE_OPEN = 104;
COLIB_ERROR_FILE_READ = 105;
COLIB_ERROR_CHANGE_STATE = 106;
COLIB_ERROR_ALLOC = 107;
COLIB_ERROR_ENTROPY = 108;
COLIB_ERROR_SELFTEST_DRBG = 500;
COLIB_ERROR_SELFTEST_BLOCK = 501;
COLIB_ERROR_SELFTEST_HASH = 502;
COLIB_ERROR_SELFTEST_ENTROPY = 503;
COLIB_ERROR_SELFTEST_RSA = 504;
COLIB_ERROR_SELFTEST_HMAC = 505;
COLIB_ERROR_MOD_SIGN = 506;
COLIB_ERROR_CRYPTO_BLOCK = 1000;
COLIB_ERROR_CRYPTO_PAD = 1001;
COLIB_ERROR_CRYPTO_INVALID_USERKEYLEN = 1002;
COLIB_ERROR_CRYPTO_DATA_LEN = 1003;
COLIB_ERROR_CRYPTO_CIPHER_LEN = 1004;
COLIB_ERROR_CRYPTO_MODE = 1005;
COLIB_ERROR_CRYPTO_SHA = 1500;
COLIB_ERROR_CRYPTO_HMAC = 1600;
COLIB_ERROR_DRBG = 2000;
COLIB_ERROR_DRBG_SIZE_OVER = 2001;
COLIB_ERROR_DRBG_BUFFER = 2002;
COLIB_ERROR_DRBG_HASH_DF = 2003;
COLIB_ERROR_DRBG_ADDITIONAL = 2004;
COLIB_ERROR_DRBG_MEMORY = 2005;
COLIB_ERROR_DRBG_HASHGEN = 2006;
COLIB_ERROR_RSA = 3000;
COLIB_ERROR_RSA_PUBLICKEY_FORMAT_ERROR = 3001;
COLIB_ERROR_RSA_PRIVITEKEY_FORMAT_ERROR = 3002;
COLIB_ERROR_RSA_INVALID_INPUT = 3003;
COLIB_ERROR_RSA_INVALID_SIGNLEN = 3004;
COLIB_ERROR_RSA_INVALID_PSSEM_LEN = 3005;
COLIB_ERROR_RSA_INVALID_PSSEM_FORMAT = 3006;
COLIB_ERROR_RSA_INVALID_DBMASK_FORMAT = 3007;
COLIB_ERROR_RSA_FAIL_PSSVERIFY = 3008;
COLIB_ERROR_RSA_INVALID_OAEP_FORMAT = 3009;
COLIB_ERROR_RSA_INVALID_OAEP_HASH = 3010;
COLIB_ERROR_RSA_MESSAGE_OUT_OF_RANGE = 3011;
COLIB_ERROR_RSA_CIPHERTEXT_OUT_OF_RANGE = 3012;
COLIB_ERROR_RSA_ENCMESSAGE_TOO_LONG = 3013;
COLIB_ERROR_RSA_DECRYPTION = 3014;
COLIB_ERROR_RSA_ENCODING = 3015;
COLIB_ERROR_RSA_PUBLIC_OP = 3016;
COLIB_ERROR_RSA_PRIVATE_OP = 3017;
COLIB_ERROR_RSA_KEY_PAIR = 3018;
COLIB_ERROR_RSA_FAIL_MALLOC = 3019;
COLIB_ERROR_RSA_KEY_GEN = 3020;
COLIB_ERROR_BN = 4000;
// );
type
TCOLIB_MODE = (
COLIB_MODE_APPROVE = 0,
COLIB_MODE_SEED = 1,
COLIB_MODE_ARIA,
COLIB_MODE_SHA224 = 100,
COLIB_MODE_SHA256,
COLIB_MODE_SHA384,
COLIB_MODE_SHA512,
COLIB_MODE_HMAC,
COLIB_MODE_HASH_DRBG = 200,
COLIB_MODE_RSAES_OAEP = 300,
COLIB_MODE_RSASSA_PSS,
COLIB_MODE_DISAPPROVE = 10000,
COLIB_MODE_AES = 10001,
COLIB_MODE_MAX
);
TCOLIB_RSA_KEY = (
COLIB_RSA_KEY_2048 = 2048
);
TCOLIB_BLOCK_CRYPTO_MODE = (
BLOCK_CRYPTO_MODE_UNUSED = 0,
BLOCK_CRYPTO_MODE_ECB = 1,
BLOCK_CRYPTO_MODE_CBC = 2,
BLOCK_CRYPTO_MODE_OFB = 3,
BLOCK_CRYPTO_MODE_CFB = 4
);
TCOLIB_STATE = (
COLIB_STATE_INIT = 1,
COLIB_STATE_APPROVE,
COLIB_STATE_DISAPPROVE,
COLIB_STATE_FATAL_ERROR,
COLIB_STATE_WARN_ERROR = 5,
COLIB_STATE_SELFTEST,
COLIB_STATE_INIT_DONE,
COLIB_STATE_INIT_DOING
);
TCOLIB_ENC_TYPE = (
ENC_TYPE_ENCRYPT = 0,
ENC_TYPE_DECRYPT = 1
);
TCOLIB_PAD_TYPE = (
COLIB_PAD_TYPE_UNUSED = 0,
COLIB_PAD_TYPE_NO = 1,
COLIB_PAD_TYPE_PKCS = 2
);
TCOLIB_KAT_STATE = (
KAT_STATE_INIT = 0,
KAT_STATE_DOING = 1,
KAT_STATE_DONE = 2
);
TCOLIB_MODE_STATE = record
seed_enc: TCOLIB_KAT_STATE;
seed_dec: TCOLIB_KAT_STATE;
aria_enc: TCOLIB_KAT_STATE;
aria_dec: TCOLIB_KAT_STATE;
sha: TCOLIB_KAT_STATE;
hmac: TCOLIB_KAT_STATE;
hash_drbg: TCOLIB_KAT_STATE;
rsaes_oaep_enc: TCOLIB_KAT_STATE;
rsaes_oaep_dec: TCOLIB_KAT_STATE;
rsassa_pss_sign: TCOLIB_KAT_STATE;
rsassa_pss_veri: TCOLIB_KAT_STATE;
integrity: TCOLIB_KAT_STATE;
end;
(*************** New Data Types *******************************************)
UINT = Cardinal;
COUWORD = Cardinal;
UCHAR = Byte;
SINT = Integer;
PDWORD = ^DWORD;
TMPZ = record
sig : SINT; // 1:positive, 0:zero, -1:negative
dat : PDWORD; // Max 104 WORD = 104 * 32 = 3328 bit
len : SINT;
end;
PCOKEY = ^TCOKEY;
TCOKEY = record
bits : UINT;
ktype : UCHAR; // pri 0, pub 1
p : TMPZ; // 1st prime factor
q : TMPZ; // 2nd prime factor
e : TMPZ; // public exponent
n : TMPZ; // public modulus
d : TMPZ; // private exponent
dp : TMPZ; // d % (p - 1)
dq : TMPZ; // d % (q - 1)
qp : TMPZ; // 1 / (Q % P)
end;
PCOKEY_BUF = ^TCOKEY_BUF;
TCOKEY_BUF = record
p_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
q_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
e_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
n_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
d_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
dp_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
dq_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
qp_dat : array[0..MPZ_WORD_LEN - 1] of COUWORD;
end;
// For RSA Hash Fucntion. This is all hash func of CUBEONE
TCORSA_HASH_TYPE = (
HASH_SHA256
);
TCORSA_KEY_TYPE = (
COKEY_TYPE_PRIVATE = 0,
COKEY_TYPE_PUBLIC = 1
);
PCIPHER_INFO = ^TCIPHER_INFO;
TCIPHER_INFO = record
colib_mode : Integer;
colib_block_crypto_mode : Integer;//TCOLIB_BLOCK_CRYPTO_MODE;
colib_pad_type : Integer;//TCOLIB_PAD_TYPE;
user_key : PBYTE;
user_key_len : UINT;
iv : PBYTE;
iv_len : UINT;
input : PBYTE;
input_len : UINT;
output : PBYTE;
output_len : PUINT;
end;
PRSA_INFO = ^TRSA_INFO;
TRSA_INFO = record
cokey : PCOKEY;
colib_mode : Integer;
rsa_hash_type : TCORSA_HASH_TYPE;
input : PBYTE;
input_len : UINT;
output : PBYTE;
output_len : PUINT;
salt : PBYTE;
salt_len : UINT;
end;
PCOLIB_VERSION = ^TCOLIB_VERSION;
TCOLIB_VERSION = record
name : array[0..5] of AnsiChar;
major : Integer;
minor : Integer;
build : Integer;
version_str : array[0..255] of AnsiChar;
end;
TCOLibSetCipherInfo = procedure(cipher_info: PCIPHER_INFO; colib_mode, colib_block_crypto_mode,
colib_pad_type: Integer; user_key: PBYTE; user_key_len: UINT;
iv: PBYTE; iv_len: UINT; input: PBYTE; input_len: UINT; output:
PBYTE; output_len: PUINT); stdcall;
// TCOLibInitCipherInfo = procedure(cipher_info: PCIPHER_INFO); stdcall; // DLL에 함수 없음, TCOLibZeroCipherInfo()로 대체 된듯
TCOLibSetRsaInfo = procedure(rsa_info: PRSA_INFO; cokey: PCOKEY; colib_mode: Integer;
rsa_hash_type: TCORSA_HASH_TYPE; input: PBYTE; input_len: UINT;
output: PBYTE; output_len: PUINT; salt: PBYTE; salt_len: UINT); stdcall;
// TCOLibInitRsaInfo = procedure(rsa_info: PRSA_INFO); stdcall; // DLL에 함수 없음, TCOLibZeroRsaInfo()로 대체 된듯
TCOLibGetState = function: Integer; stdcall;
TCOLibGetVersion = function(colib_version: PCOLIB_VERSION): Integer; stdcall;
TCOLibSelfTestAll = function: Integer; stdcall;
TCOLibEncrypt = function(cipher_info: PCIPHER_INFO): Integer; stdcall;
TCOLibDecrypt = function(cipher_info: PCIPHER_INFO): Integer; stdcall;
TCOLibGetKey = function(key: PBYTE; key_len: UINT): Integer; stdcall;
TCOLibDrbg = function(buf: PBYTE; buf_len: UINT; addtl: PBYTE; addtl_len: UINT; pers: PBYTE; pers_len: UINT; pr: SINT): Integer; stdcall;
TCOLibEncryptRsa = function(rsa_info: PRSA_INFO): Integer; stdcall;
TCOLibDecryptRsa = function(rsa_info: PRSA_INFO): Integer; stdcall;
TCOLibGetRsaKey = function(bits: Integer; prk, puk: PCOKEY): Integer; stdcall;
TCOLibRsaKeyInit = function(cokey: PCOKEY; cokey_buf: PCOKEY_BUF): Integer; stdcall;
TCOLibGetModeState = procedure(colib_mode_state: PInteger); stdcall;
TCOLibZeroCipherInfo = procedure(cipher_info: PCIPHER_INFO); stdcall;
TCOLibZeroRsaInfo = procedure(rsa_info: PRSA_INFO); stdcall;
TCOLibGetErrorStr = function(colib_error: Integer): PAnsiChar; stdcall;
TCOLibGetModeStr = function(colib_mode: TCOLIB_MODE): PAnsiChar; stdcall;
TCOLibGetStateStr = function(colib_state: TCOLIB_STATE): PAnsiChar; stdcall;
TCOLibGetKatStateStr = function(colib_kat_state: TCOLIB_KAT_STATE): PAnsiChar; stdcall;
procedure COLibSetCipherInfo(cipher_info: PCIPHER_INFO; colib_mode: TCOLIB_MODE; colib_block_crypto_mode: TCOLIB_BLOCK_CRYPTO_MODE;
colib_pad_type: TCOLIB_PAD_TYPE; user_key: PBYTE; user_key_len: UINT;
iv: PBYTE; iv_len: UINT; input: PBYTE; input_len: UINT;
output: PBYTE; output_len: PUINT);
procedure COLibSetRsaInfo(rsa_info: PRSA_INFO; cokey: PCOKEY; colib_mode: Integer;
rsa_hash_type: TCORSA_HASH_TYPE; input: PBYTE; input_len: UINT;
output: PBYTE; output_len: PUINT; salt: PBYTE; salt_len: UINT);
function COLibGetState: Integer;
function COLibGetVersion(colib_version: PCOLIB_VERSION): Integer;
function COLibSelfTestAll: Integer;
function COLibEncrypt(cipher_info: PCIPHER_INFO): Integer;
function COLibDecrypt(cipher_info: PCIPHER_INFO): Integer;
function COLibGetKey(key: PBYTE; key_len: UINT): Integer;
function COLibDrbg(buf: PBYTE; buf_len: UINT; addtl: PBYTE; addtl_len: UINT;
pers: PBYTE; pers_len: UINT; pr: SINT): Integer;
function COLibEncryptRsa(rsa_info: PRSA_INFO): Integer;
function COLibDecryptRsa(rsa_info: PRSA_INFO): Integer;
function COLibGetRsaKey(bits: Integer; prk, puk: PCOKEY): Integer;
function COLibRsaKeyInit(cokey: PCOKEY; cokey_buf: PCOKEY_BUF): Integer;
procedure COLibGetModeState(colib_mode_state: PInteger);
procedure COLibZeroCipherInfo(cipher_info: PCIPHER_INFO);
procedure COLibZeroRsaInfo(rsa_info: PRSA_INFO);
function COLibGetErrorStr(colib_error: Integer): PAnsiChar;
function COLibGetModeStr(colib_mode: TCOLIB_MODE): PAnsiChar;
function COLibGetStateStr(colib_state: TCOLIB_STATE): PAnsiChar;
function COLibGetKatStateStr(colib_kat_state: TCOLIB_KAT_STATE): PAnsiChar;
implementation
uses
Tocsg.Path, Tocsg.Trace;
var
_hCoLib: THandle = 0;
_fnCOLibSetCipherInfo: TCOLibSetCipherInfo = nil;
// _fnCOLibInitCipherInfo: TCOLibInitCipherInfo = nil;
_fnCOLibSetRsaInfo: TCOLibSetRsaInfo = nil;
// _fnCOLibInitRsaInfo: TCOLibInitRsaInfo = nil;
_fnCOLibGetState: TCOLibGetState = nil;
_fnCOLibGetVersion: TCOLibGetVersion = nil;
_fnCOLibSelfTestAll: TCOLibSelfTestAll = nil;
_fnCOLibEncrypt: TCOLibEncrypt = nil;
_fnCOLibDecrypt: TCOLibDecrypt = nil;
_fnCOLibGetKey: TCOLibGetKey = nil;
_fnCOLibDrbg: TCOLibDrbg = nil;
_fnCOLibEncryptRsa: TCOLibEncryptRsa = nil;
_fnCOLibDecryptRsa: TCOLibDecryptRsa = nil;
_fnCOLibGetRsaKey: TCOLibGetRsaKey = nil;
_fnCOLibRsaKeyInit: TCOLibRsaKeyInit = nil;
_fnCOLibGetModeState: TCOLibGetModeState = nil;
_fnCOLibZeroCipherInfo: TCOLibZeroCipherInfo = nil;
_fnCOLibZeroRsaInfo: TCOLibZeroRsaInfo = nil;
_fnCOLibGetErrorStr: TCOLibGetErrorStr = nil;
_fnCOLibGetModeStr: TCOLibGetModeStr = nil;
_fnCOLibGetStateStr: TCOLibGetStateStr = nil;
_fnCOLibGetKatStateStr: TCOLibGetKatStateStr = nil;
function InitCOLibProcedure: Boolean;
var
sPath: String;
begin
if _hCoLib = 0 then
begin
sPath := GetRunExePathDir + DLL_COLIB;
if not FileExists(sPath) then
begin
TTgTrace.T('Fail .. InitCOLibProcedure() .. Not found DLL, Path=%s', [sPath]);
Exit(false);
end;
_hCoLib := LoadLibrary(PChar(sPath));
if _hCoLib <> 0 then
begin
@_fnCOLibSetCipherInfo := GetProcAddress(_hCoLib, 'COLibSetCipherInfo');
ASSERT(@_fnCOLibSetCipherInfo <> nil);
// @_fnCOLibInitCipherInfo := GetProcAddress(_hCoLib, 'COLibInitCipherInfo');
// ASSERT(@_fnCOLibInitCipherInfo <> nil);
@_fnCOLibSetRsaInfo := GetProcAddress(_hCoLib, 'COLibSetRsaInfo');
ASSERT(@_fnCOLibSetRsaInfo <> nil);
// @_fnCOLibInitRsaInfo := GetProcAddress(_hCoLib, 'COLibInitRsaInfo');
// ASSERT(@_fnCOLibInitRsaInfo <> nil);
@_fnCOLibGetState := GetProcAddress(_hCoLib, 'COLibGetState');
ASSERT(@_fnCOLibGetState <> nil);
@_fnCOLibGetVersion := GetProcAddress(_hCoLib, 'COLibGetVersion');
ASSERT(@_fnCOLibGetVersion <> nil);
@_fnCOLibSelfTestAll := GetProcAddress(_hCoLib, 'COLibSelfTestAll');
ASSERT(@_fnCOLibSelfTestAll <> nil);
@_fnCOLibEncrypt := GetProcAddress(_hCoLib, 'COLibEncrypt');
ASSERT(@_fnCOLibEncrypt <> nil);
@_fnCOLibDecrypt := GetProcAddress(_hCoLib, 'COLibDecrypt');
ASSERT(@_fnCOLibDecrypt <> nil);
@_fnCOLibGetKey := GetProcAddress(_hCoLib, 'COLibGetKey');
ASSERT(@_fnCOLibGetKey <> nil);
@_fnCOLibDrbg := GetProcAddress(_hCoLib, 'COLibDrbg');
ASSERT(@_fnCOLibDrbg <> nil);
@_fnCOLibEncryptRsa := GetProcAddress(_hCoLib, 'COLibEncryptRsa');
ASSERT(@_fnCOLibEncryptRsa <> nil);
@_fnCOLibDecryptRsa := GetProcAddress(_hCoLib, 'COLibDecryptRsa');
ASSERT(@_fnCOLibDecryptRsa <> nil);
@_fnCOLibGetRsaKey := GetProcAddress(_hCoLib, 'COLibGetRsaKey');
ASSERT(@_fnCOLibGetRsaKey <> nil);
@_fnCOLibRsaKeyInit := GetProcAddress(_hCoLib, 'COLibRsaKeyInit');
ASSERT(@_fnCOLibRsaKeyInit <> nil);
@_fnCOLibGetModeState := GetProcAddress(_hCoLib, 'COLibGetModeState');
ASSERT(@_fnCOLibGetModeState <> nil);
@_fnCOLibZeroCipherInfo := GetProcAddress(_hCoLib, 'COLibZeroCipherInfo');
ASSERT(@_fnCOLibZeroCipherInfo <> nil);
@_fnCOLibZeroRsaInfo := GetProcAddress(_hCoLib, 'COLibZeroRsaInfo');
ASSERT(@_fnCOLibZeroRsaInfo <> nil);
@_fnCOLibGetErrorStr := GetProcAddress(_hCoLib, 'COLibGetErrorStr');
ASSERT(@_fnCOLibGetErrorStr <> nil);
@_fnCOLibGetModeStr := GetProcAddress(_hCoLib, 'COLibGetModeStr');
ASSERT(@_fnCOLibGetModeStr <> nil);
@_fnCOLibGetStateStr := GetProcAddress(_hCoLib, 'COLibGetStateStr');
ASSERT(@_fnCOLibGetStateStr <> nil);
@_fnCOLibGetKatStateStr := GetProcAddress(_hCoLib, 'COLibGetKatStateStr');
ASSERT(@_fnCOLibGetKatStateStr <> nil);
end;
end;
Result := _hCoLib <> 0;
end;
procedure COLibSetCipherInfo(cipher_info: PCIPHER_INFO; colib_mode: TCOLIB_MODE; colib_block_crypto_mode: TCOLIB_BLOCK_CRYPTO_MODE;
colib_pad_type: TCOLIB_PAD_TYPE; user_key: PBYTE; user_key_len: UINT;
iv: PBYTE; iv_len: UINT; input: PBYTE; input_len: UINT;
output: PBYTE; output_len: PUINT);
begin
if InitCOLibProcedure and Assigned(_fnCOLibSetCipherInfo) then
_fnCOLibSetCipherInfo(cipher_info, Integer(colib_mode), Integer(colib_block_crypto_mode),
Integer(colib_pad_type), user_key, user_key_len,
iv, iv_len, input, input_len, output, output_len);
end;
procedure COLibSetRsaInfo(rsa_info: PRSA_INFO; cokey: PCOKEY; colib_mode: Integer;
rsa_hash_type: TCORSA_HASH_TYPE; input: PBYTE; input_len: UINT;
output: PBYTE; output_len: PUINT; salt: PBYTE; salt_len: UINT);
begin
if InitCOLibProcedure and Assigned(_fnCOLibSetRsaInfo) then
_fnCOLibSetRsaInfo(rsa_info, cokey, colib_mode, rsa_hash_type, input, input_len,
output, output_len, salt, salt_len);
end;
function COLibGetState: Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibGetState) then
Result := _fnCOLibGetState;
end;
function COLibGetVersion(colib_version: PCOLIB_VERSION): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibGetVersion) then
Result := _fnCOLibGetVersion(colib_version);
end;
function COLibSelfTestAll: Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibSelfTestAll) then
Result := _fnCOLibSelfTestAll;
end;
function COLibEncrypt(cipher_info: PCIPHER_INFO): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibEncrypt) then
Result := _fnCOLibEncrypt(cipher_info);
end;
function COLibDecrypt(cipher_info: PCIPHER_INFO): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibDecrypt) then
Result := _fnCOLibDecrypt(cipher_info);
end;
function COLibGetKey(key: PBYTE; key_len: UINT): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibGetKey) then
Result := _fnCOLibGetKey(key, key_len);
end;
function COLibDrbg(buf: PBYTE; buf_len: UINT; addtl: PBYTE; addtl_len: UINT;
pers: PBYTE; pers_len: UINT; pr: SINT): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibDrbg) then
Result := _fnCOLibDrbg(buf, buf_len, addtl, addtl_len, pers, pers_len, pr);
end;
function COLibEncryptRsa(rsa_info: PRSA_INFO): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibEncryptRsa) then
Result := _fnCOLibEncryptRsa(rsa_info);
end;
function COLibDecryptRsa(rsa_info: PRSA_INFO): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibDecryptRsa) then
Result := _fnCOLibDecryptRsa(rsa_info);
end;
function COLibGetRsaKey(bits: Integer; prk, puk: PCOKEY): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibGetRsaKey) then
Result := _fnCOLibGetRsaKey(bits, prk, puk);
end;
function COLibRsaKeyInit(cokey: PCOKEY; cokey_buf: PCOKEY_BUF): Integer;
begin
Result := -1;
if InitCOLibProcedure and Assigned(_fnCOLibRsaKeyInit) then
Result := _fnCOLibRsaKeyInit(cokey, cokey_buf);
end;
procedure COLibGetModeState(colib_mode_state: PInteger);
begin
if InitCOLibProcedure and Assigned(_fnCOLibGetModeState) then
_fnCOLibGetModeState(colib_mode_state);
end;
procedure COLibZeroCipherInfo(cipher_info: PCIPHER_INFO);
begin
if InitCOLibProcedure and Assigned(_fnCOLibZeroCipherInfo) then
_fnCOLibZeroCipherInfo(cipher_info);
end;
procedure COLibZeroRsaInfo(rsa_info: PRSA_INFO);
begin
if InitCOLibProcedure and Assigned(_fnCOLibZeroRsaInfo) then
_fnCOLibZeroRsaInfo(rsa_info);
end;
function COLibGetErrorStr(colib_error: Integer): PAnsiChar;
begin
Result := nil;
if InitCOLibProcedure and Assigned(_fnCOLibGetErrorStr) then
Result := _fnCOLibGetErrorStr(colib_error);
end;
function COLibGetModeStr(colib_mode: TCOLIB_MODE): PAnsiChar;
begin
Result := nil;
if InitCOLibProcedure and Assigned(_fnCOLibGetModeStr) then
Result := _fnCOLibGetModeStr(colib_mode);
end;
function COLibGetStateStr(colib_state: TCOLIB_STATE): PAnsiChar;
begin
Result := nil;
if InitCOLibProcedure and Assigned(_fnCOLibGetStateStr) then
Result := _fnCOLibGetStateStr(colib_state);
end;
function COLibGetKatStateStr(colib_kat_state: TCOLIB_KAT_STATE): PAnsiChar;
begin
Result := nil;
if InitCOLibProcedure and Assigned(_fnCOLibGetKatStateStr) then
Result := _fnCOLibGetKatStateStr(colib_kat_state);
end;
end.

View File

@ -13,7 +13,7 @@ interface
uses
Tocsg.Thread, System.SysUtils, System.Classes, Winapi.Windows,
Winapi.Messages, System.Generics.Collections, CttSchDefine, Tocsg.KvFilter,
ManagerPattern, Tocsg.Fasoo, Tocsg.Win32;
ManagerPattern, Tocsg.Fasoo, Tocsg.Win32, vcl.Dialogs;
const
LOG_FS_DEC_FAIL = 'FsDecFail.log';
@ -52,7 +52,7 @@ uses
Tocsg.Shell, superobject, ProcessSoftcampDRM, Tocsg.Hash, Tocsg.FileInfo,
Tocsg.Convert, Tocsg.Registry, Condition, Tocsg.AIP, GlobalDefine,
Winapi.ActiveX, Tocsg.Kess, Tocsg.Fasoo.Global.Define, Tocsg.Fasoo.Global,
Tocsg.Valid, Tocsg.Trace;
Tocsg.Valid, Tocsg.Trace, Tocsg.COLib.Encrypt;
{ TThdCttSch }
@ -291,13 +291,14 @@ var
end;
end;
// [yhkim]
function EncFile(sPath: String): Boolean;
var
enc: TTgDrmEnc;
sEncPath: String;
pKek, pDek: TBytes;
begin
Result := false;
try
if not ForceDirectories(sEncDir) then
exit;
@ -349,25 +350,70 @@ var
exit;
// if not MoveFile_wait(sPath, sEncPath, 3) then
if not CopyFile(PChar(sPath), PChar(sEncPath), false) then
exit;
DeleteFile(PChar(sPath));
SaveStrToFile(sEncPath + '.i', sPath, TEncoding.UTF8);
// if not CopyFile(PChar(sPath), PChar(sEncPath), false) then
// exit;
// DeleteFile(PChar(sPath));
// SaveStrToFile(sEncPath + '.i', sPath, TEncoding.UTF8);
//
// Guard(enc, TTgDrmEnc.Create(sPath));
//
// enc.SetHaed(PASS_DRM_HEAD, SIG_DRM, sEmpNo, sHost, sDept, sPoName, dwCsType);
// if enc.EncryptFromFile(sPass, sEncPath) then
// begin
// DeleteFile(PChar(sEncPath));
// DeleteFile(PChar(sEncPath + '.i'));
// Result := true;
// end else begin
//// MoveFile_wait(sEncPath, sPath, 3);
// if CopyFile(PChar(sEncPath), PChar(sPath), false) then
// DeleteFile(PChar(sEncPath));
// DeleteFile(PChar(sEncPath + '.i'));
// end;
Guard(enc, TTgDrmEnc.Create(sPath));
enc.SetHaed(PASS_DRM_HEAD, SIG_DRM, sEmpNo, sHost, sDept, sPoName, dwCsType);
if enc.EncryptFromFile(sPass, sEncPath) then
// [yhkim]
// 이미 암호화된 파일이면 중단
if TTgColibDrm.IsEncrypt(sPath) then
begin
DeleteFile(PChar(sEncPath));
DeleteFile(PChar(sEncPath + '.i'));
Result := true;
end else begin
// MoveFile_wait(sEncPath, sPath, 3);
if CopyFile(PChar(sEncPath), PChar(sPath), false) then
DeleteFile(PChar(sEncPath));
DeleteFile(PChar(sEncPath + '.i'));
//ShowMessage('이미 암호화된 파일입니다. 암호화를 중단합니다');
Exit;
end;
pKek := TTgColibDrm.GetKEK('kek.bin');
if pKek = nil then
exit;
pDek := TTgColibDrm.GetDEK('dek.bin', pKek);
if pDek = nil then
exit;
ShowMessage('암호화 대상: ' +sPath);
try
TTgColibDrm.DoEncrypt(sPath, pDek);
// 암호화 결과 파일이 정상적으로 생성되었는지 확인
if FileExists(sPath + '.enc') then
begin
// 성공 시 원본 파일을 삭제하고 암호화된 파일을 원본 이름으로 변경
if DeleteFile(PChar(sPath)) then
begin
if MoveFile_wait(sPath + '.enc', sPath, 3) then
Result := True;
end;
end;
except
on E: Exception do
begin
ETgException.TraceException(Self, E, '암호화 실패: ' + sPath);
// 실패 시 찌꺼기 파일 제거
if FileExists(sPath + '.enc') then
DeleteFile(PChar(sPath + '.enc'));
Result := False;
end;
end;
end;
except
on E: Exception do

View File

@ -0,0 +1,57 @@
object AuthForm: TAuthForm
Left = 0
Top = 0
BorderIcons = [biMinimize, biMaximize]
Caption = 'BSOne Login'
ClientHeight = 171
ClientWidth = 146
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -12
Font.Name = 'Segoe UI'
Font.Style = []
OnCreate = FormCreate
TextHeight = 15
object Label1: TLabel
Left = 8
Top = 8
Width = 11
Height = 15
Caption = 'ID'
end
object Label2: TLabel
Left = 8
Top = 58
Width = 18
Height = 15
Caption = 'PW'
end
object EditID: TEdit
Left = 8
Top = 29
Width = 129
Height = 23
TabOrder = 0
TextHint = 'ID'#47484' '#51077#47141#54616#49464#50836
end
object EditPW: TEdit
Left = 8
Top = 79
Width = 129
Height = 23
PasswordChar = '*'
TabOrder = 1
TextHint = #54056#49828#50892#46300#47484' '#51077#47141#54616#49464#50836
end
object ButtonLogin: TButton
Left = 8
Top = 120
Width = 129
Height = 33
Caption = 'Login'
Default = True
TabOrder = 2
OnClick = ButtonLoginClick
end
end

View File

@ -0,0 +1,246 @@
unit UserAuthentification;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,
superobject, IdHTTP, IdSSLOpenSSL, System.Math, System.IOUtils, System.RegularExpressions,
Tocsg.Safe, Tocsg.COLib, Tocsg.COLib.Encrypt;
const
CODE_AUTH_OK = 100;
type
// 로그인 성공 시 호출될 이벤트 타입 정의
TNotifyLoginSuccess = procedure(Sender: TObject; ResultCode: Integer) of object;
TAuthForm = class(TForm)
Label1, Label2: TLabel;
EditID, EditPW: TEdit;
ButtonLogin: TButton;
procedure FormCreate(Sender: TObject);
procedure ButtonLoginClick(Sender: TObject);
private
{ Private declarations }
iFailCount: Integer; // 로그인 실패 횟수
BlockStartTime: TDateTime; // 차단 시작 시간
FOnSuccess: TNotifyLoginSuccess; // 이벤트를 담을 변수
public
{ Public declarations }
sAgentId, sDestIPort: string;
property OnSuccess: TNotifyLoginSuccess read FOnSuccess write FOnSuccess;
end;
var
AuthForm: TAuthForm;
implementation
{$R *.dfm}
procedure TAuthForm.FormCreate(Sender: TObject);
begin
Self.Position := poScreenCenter;
Self.BorderStyle := bsSingle;
Self.FormStyle := fsStayOnTop;
end;
function IsValidInput(const AText: string): Boolean;
const
// 영문, 숫자, 특수문자만 허용
ALLOWED_PATTERN = '^[a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};'':"\\|,.<>\/?]+$';
begin
// 빈 값 체크 후 패턴 검사
Result := (AText <> '') and TRegEx.IsMatch(AText, ALLOWED_PATTERN);
end;
function GetPostData(sDestIPort, sUrl, sData: String; sReqType: String = ''): String;
var
HTTP: TIdHTTP;
SSL: TIdSSLIOHandlerSocketOpenSSL;
ss: TStringStream;
begin
Result := '';
try
if sUrl = '' then
exit;
if sUrl[1] = '/' then
Delete(sUrl, 1, 1);
Guard(SSL, TIdSSLIOHandlerSocketOpenSSL.Create(nil));
SSL.SSLOptions.Method := sslvSSLv23;
SSL.SSLOptions.SSLVersions := [sslvTLSv1_2, sslvTLSv1_1, sslvTLSv1];
Guard(HTTP, TIdHTTP.Create(nil));
HTTP.IOHandler := SSL;
with HTTP do
begin
HandleRedirects := true;
Request.Clear;
Request.UserAgent := 'Mozilla/5.0';
Request.ContentType := 'application/xml';
Request.AcceptCharSet := 'UTF-8';
// Request.Connection := 'Keep-Alive';
// Request.CustomHeaders.Values['Keep-Alive'] := 'timeout=300, max=100';
Request.Connection := 'close';
HTTPOptions := HTTPOptions - [hoKeepOrigProtocol];
if sReqType <> '' then
Request.CustomHeaders.Values['requestType'] := sReqType;
HTTPOptions := HTTP.HTTPOptions + [hoForceEncodeParams];
ConnectTimeout := 5000;
ReadTimeout := 5000;
end;
Guard(ss, TStringStream.Create(sData, TEncoding.UTF8));
Result := HTTP.Post(sDestIPort + sUrl, ss);
except
on E: Exception do
begin
//ShowMessage('HTTP 통신 내부 오류: ' + E.Message);
Result := '';
end;
end;
end;
procedure TAuthForm.ButtonLoginClick(Sender: TObject);
var
O: ISuperObject;
pSalt, pKek, pDek : TBytes;
sResult, sSalt: String;
nResult: integer;
CurrentTime: TDateTime;
begin
if iFailCount >= 5 then
begin
CurrentTime := Now;
// 차단 시작 시간으로부터 5분이 지났는지 확인
if (CurrentTime - BlockStartTime) < (5 / (24 * 60)) then
begin
MessageBox(0,'로그인 5회 실패로 인해 5분간 로그인이 차단됩니다', 'BSOne Login', MB_ICONINFORMATION);
Exit;
end
else
begin
// 5분이 지났으면 카운트 초기화
iFailCount := 0;
end;
end;
if EditID.Text = '' then
begin
MessageBox(0,'ID를 입력하세요', 'BSOne Login', MB_ICONINFORMATION);
EditID.SetFocus;
Exit;
end;
if not IsValidInput(EditID.Text) then
begin
MessageBox(0,'ID에는 영문, 숫자, 특수기호를 제외하고 들어갈 수 없습니다', 'BSOne Login', MB_ICONINFORMATION);
Exit;
end;
if EditPW.Text = '' then
begin
MessageBox(0,'패스워드를 입력하세요', 'BSOne Login', MB_ICONINFORMATION);
EditPW.SetFocus;
Exit;
end;
if not IsValidInput(EditPW.Text) then
begin
MessageBox(0,'패스워드에는 영문, 숫자, 특수기호를 제외하고 들어갈 수 없습니다', 'BSOne Login', MB_ICONINFORMATION);
Exit;
end;
try
O := SO;
// O.S['empId'] := '0505';
// O.S['pw'] := 'Q!w2e3r4t5';
// O.S['agentId'] := '25111809085600FF96644E47';
O.S['empId'] := EditID.Text;
O.S['pw'] := EditPW.Text;
O.S['agentId'] := sAgentId;
sResult := GetPostData(sDestIPort, 'aapi/auth/refresh-token/issue', O.AsJSon);
if sResult <> '' then
begin
if sResult.Contains('error') then
begin
//_Trace('Error .. GetRegPerInfoUrl() .. Msg="%s"', [Result]);
ShowMessage('에러 1: '+ sResult);
exit;
end
else
begin
O := SO(sResult);
//O.S['refreshToken']
iFailCount := 0;
//ShowMessage('인증 완료');
end;
end
else
begin
Inc(iFailCount);
if iFailCount >= 5 then
begin
BlockStartTime := Now; // 현재 시간 기록
ShowMessage('인증 실패 5회 연속으로 5분간 로그인이 차단됩니다.');
exit;
end
else
begin
ShowMessage(Format('아이디 또는 비밀번호가 일치하지 않습니다. (현재 %d회 실패 / 5회 연속실패 시 차단)', [iFailCount]));
end;
exit;
end;
except
on E: Exception do
begin
ShowMessage('오류 발생: Fail .. GetRegPerInfoUrl()' + sLineBreak + E.Message);
exit;
end;
end;
// salt 생성
pSalt := TTgColibDrm.CreateSalt(COLIB_128BIT_KEY_LEN);
if pSalt = nil then
begin
ShowMessage('CreateSalt is failed');
exit;
end;
for var i := 0 to COLIB_128BIT_KEY_LEN - 1 do
sSalt := sSalt + Format('%.2x', [pSalt[i]]);
//ShowMessage('Salt : ' + sSalt);
// KEK 생성 및 암호화(사용자 로그인 계정 암호)
pKek := TTgColibDrm.CreateKEK(EditPW.Text, sSalt, 1000, SHA256_DIGEST_SIZE);
if pKek = nil then
begin
ShowMessage('CreateKEK is failed');
exit;
end;
// KEK 복호화 디버그
// var pTemp := TTgColibDrm.GetKEK('kek.bin');
// if (Length(pKek) = Length(pTemp)) and
// CompareMem(@pKek[0], @pTemp[0], Length(pKek)) then
// begin
// ShowMessage('KEK 복호화 성공');
// end;
// DEK 생성 및 암호화(KEK)
TTgColibDrm.CreateDEK(SHA256_DIGEST_SIZE, pKek);
if Assigned(FOnSuccess) then
FOnSuccess(Self, CODE_AUTH_OK); // 메인 서비스에 알림 발송
Close; // 창 닫기
end;
end.

View File

@ -0,0 +1,15 @@
program login;
uses
Vcl.Forms,
authentification in 'authentification.pas' {Form1},
Tocsg.COLib.Encrypt in 'Tocsg.COLib.Encrypt.pas';
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,7 @@ uses
ThdUsbMon, ManagerHook, ThdSendFiles, ThdWinUpdateScan, ThdRouteMon,
Tocsg.Process, HandleSecurity, AppCtrlDefine, Tocsg.WndUtil,
ManagerCampaign, ManagerRule, superobject, Define, ThdReaction,
Vcl.Graphics, DSchPiNoti, Tocsg.Win32, Tocsg.Fasoo,
Vcl.Graphics, DSchPiNoti, Tocsg.Win32, Tocsg.Fasoo, UserAuthentification,
ThdPrintWork, xPrintLogService, ManagerPrint, ThdScreenRecord, ProcessRecentDoc, Bs1FltCtrl, DeviceGuard.Logic;
{$I Define.inc}
@ -438,6 +438,8 @@ type
bIgrPrtPause_: Boolean;
bIsManualSecurityMode_: Boolean; // 로그인 성공시 보안모드 진입 플
procedure Lock;
procedure Unlock;
procedure DevLock;
@ -657,6 +659,9 @@ type
procedure ProcessEndSession;
// [yhkim] 로그인 시 수동모드 -> 보안모드
procedure ChangeLoginMode(Sender: TObject; ResultCode: Integer);
property RcvHwnd: HWND read hRcvHwnd_;
property DestServerUrl: String read sDestSvrUrl_;
property Connected: Boolean read GetConnected;
@ -1005,6 +1010,42 @@ end;
{ TManagerService }
procedure TManagerService.ChangeLoginMode(Sender: TObject; ResultCode: Integer);
begin
if ResultCode = CODE_AUTH_OK then
begin
begin
// 서비스 가용 상태를 True로 변경 (GetModePolicy가 보안모드를 선택하도록 함)
bIsManualSecurityMode_ := True; // 수동 인증 성공
bIsServiceAvailable_ := True; // 서비스 가용 상태로 강제 전환
// GetModePolicy 로직 참조: 보안 모드 진입 시 필요한 설정 강제 적용
try
// 레지스트리 caller 값을 3으로 (보안모드 의미)
SetRegValueInteger(HKEY_LOCAL_MACHINE, 'SOFTWARE\eCrmHomeEdition', 'caller', 3, true);
// 보안 모드 시작 로그 전송
if Assigned(gMgSvc) then
gMgSvc.SendEventLog(URI_USER_ACTION, MODE_SECURITY_START, 'Security Mode');
_Trace('인증 성공으로 인한 수동 모드 변경 : 수면모드 > 보안모드', 1);
// 정책 엔진 다시 호출 (화면 로고 업데이트 및 팝업 처리를 위해)
GetModePolicy;
// 화면 로고 즉시 업데이트
if IsScreenLogo then
UpdateScreenLogo(true);
except
on E: Exception do
_Trace('ChangeLoginMode Error: ' + E.Message);
end;
end;
end;
end;
Constructor TManagerService.Create(hRcvHwnd: HWND);
procedure InitHttp;
@ -1085,6 +1126,18 @@ Constructor TManagerService.Create(hRcvHwnd: HWND);
{$ENDIF}
end;
procedure ExecuteLogin;
var
LoginForm: TAuthForm;
begin
LoginForm := TAuthForm.Create(nil);
LoginForm.OnSuccess := ChangeLoginMode; // 성공했을때 호출할 함수 등록
LoginForm.sAgentId := sAgentId_;
LoginForm.sDestIPort := sDestIPort_;
LoginForm.Show;
end;
procedure InitAgentInfo;
var
sPath: String;
@ -1151,6 +1204,9 @@ Constructor TManagerService.Create(hRcvHwnd: HWND);
// AgentModel_.Save; 아래에서 함 22_0721 15:24:12 kku
end;
//[yhkim]
ExecuteLogin();
if CUSTOMER_TYPE = CUSTOMER_LOTTEMART then
begin
// 실행마다 NAC에서 유저 ID값 가져오기
@ -5646,7 +5702,7 @@ begin
SetModeName(RS_VulMode);
end else
// if { PrefIdlModel_.Loaded and } not VulService_.IsVpnOn then // 수면 모드는 정책 안불러와도 빈 정책을 줘야함 22_0729 07:46:15 kku
if not bIsServiceAvailable_ then // VulService_.IsVpnOn 이걸로 체크 하면 모드별 팝업 옵션이 즉시 적용 되지 않아서 변경함 22_1222 17:08:48 kku
if not bIsServiceAvailable_ and not bIsManualSecurityMode_ then // VulService_.IsVpnOn 이걸로 체크 하면 모드별 팝업 옵션이 즉시 적용 되지 않아서 변경함 22_1222 17:08:48 kku
begin
Result := PrefIdlModel_;
SetModeKind(hmkSleep);

View File

@ -512,6 +512,7 @@ procedure TRecoverService.CheckAndRecover(sResPath, sPath: String);
sDir,
sFName: String;
begin
exit;
try
sFName := ExtractFileName(sPath);
Guard(zip, TAbUnzipper.Create(nil));

Some files were not shown because too many files have changed in this diff Show More