BSOne.SFC/Tocsg.Module/COCrypto/DCoCryptoMain.pas

617 lines
17 KiB
Plaintext

unit DCoCryptoMain;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;
const
(**
* key 길이에 따라 블럭암호화 알고리즘 구분
* 16 : 128
* 24 : 192
* 32 : 256
*)
COLIB_USER_KEY_LEN = 32;
type
TDlgCoCryptoMain = class(TForm)
mmInfo: TMemo;
pnTop: TPanel;
btnHashTest: TButton;
btnBlcokEncTest: TButton;
btnHeadEncTest: TButton;
Button1: TButton;
Button2: TButton;
btnPbkdf2: TButton;
Button3: TButton;
procedure btnHashTestClick(Sender: TObject);
procedure btnBlcokEncTestClick(Sender: TObject);
procedure btnHeadEncTestClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure btnPbkdf2Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
private
{ Private declarations }
arrKey_: array [0..COLIB_USER_KEY_LEN-1] of Byte;
procedure Log(sLog: String); inline;
public
{ Public declarations }
Constructor Create(aOwner: TComponent); override;
end;
var
DlgCoCryptoMain: TDlgCoCryptoMain;
implementation
uses
Tocsg.COLib, Tocsg.COLib.Encrypt, Tocsg.DateTime, Tocsg.Safe,
System.Math, Winapi.AclAPI, Winapi.AccCtrl;
{$R *.dfm}
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;
// indy HMAC 사용
// uses IdHMACSHA1, IdGlobal, IdSSLOpenSSL;
//function PBKDF2_HMAC_SHA256(const pPass, pSalt: TBytes; Iterations, nKeyLen: Integer): TBytes;
//var
// i, n, nBlockCnt: Integer;
// pSaltAndBlkIdx, T, U, U2: TBytes;
// HMAC: TIdHMACSHA256;
// pBlockIdx: TBytes;
//begin
// SetLength(Result, nKeyLen);
// nBlockCnt := (nKeyLen + 31) div 32; // SHA256 = 32 bytes
//
// SetLength(pBlockIdx, 4);
// SetLength(U, 32);
// SetLength(U2, 32);
// SetLength(T, 32);
// HMAC := TIdHMACSHA256.Create;
// try
// HMAC.Key := TIdBytes(pPass);
// for i := 1 to nBlockCnt do
// begin
// // BlockIndex = i (Big Endian)
// 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);
//
// // U1 = HMAC(Password, Salt || BlockIndex)
// pSaltAndBlkIdx := ConcatBytes(pSalt, pBlockIdx);
// U := TBytes(HMAC.HashValue(TIdBytes(pSaltAndBlkIdx)));
//
// CopyMemory(T, U, Length(U));
//
// for n := 2 to Iterations do
// begin
// U := TBytes(HMAC.HashValue(TIdBytes(U)));
// XORBytes(T, U);
// end;
//
// Move(T[0], Result[(i - 1) * 32], Min(32, nKeyLen - (i - 1) * 32));
// end;
// finally
// HMAC.Free;
// end;
//end;
function PBKDF2_HMAC_SHA256(const sPass, sSalt: AnsiString; Iterations, nKeyLen: Integer): TBytes;
var
i, n, nBlockCnt: Integer;
pSaltAndBlkIdx, pTemp,
U_prev, U_current,
pPass, pSalt: TBytes;
pBlockIdx: TBytes;
ci: TCIPHER_INFO;
nOut, nResult: Integer;
begin
SetLength(Result, nKeyLen);
ZeroMemory(Result, nKeyLen);
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, 32);
SetLength(U_prev, 32);
SetLength(U_current, 32);
nBlockCnt := (nKeyLen + 31) div 32; // SHA256 = 32 bytes
for i := 1 to nBlockCnt do
begin
// BlockIndex = i (Big Endian)
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);
pSaltAndBlkIdx := ConcatBytes(pSalt, pBlockIdx);
nOut := 0;
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;
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;
XORBytes(pTemp, U_current);
CopyMemory(U_prev, U_current, Length(U_current));
end;
Move(pTemp[0], Result[(i - 1) * 32], Min(32, nKeyLen - (i - 1) * 32));
end;
end;
procedure TDlgCoCryptoMain.btnPbkdf2Click(Sender: TObject);
var
sOut: AnsiString;
pBuf: TBytes;
i: Integer;
begin
pBuf := PBKDF2_HMAC_SHA256('kku250507', '1234567890', 1001, 16);
sOut := '';
for i := 0 to Length(pBuf) - 1 do
sOut := sOut + Format('%.2x', [pBuf[i]]);
Log('PBKDF2 Text : ' + sOut);
end;
Constructor TDlgCoCryptoMain.Create(aOwner: TComponent);
var
cv: TCOLIB_VERSION;
begin
Inherited Create(aOwner);
COLibGetVersion(@cv);
Log('COLib 정보 : ' + cv.version_str);
mmInfo.Lines.Add('');
ZeroMemory(@arrKey_, SizeOf(arrKey_));
COLibGetKey(@arrKey_, COLIB_USER_KEY_LEN);
end;
procedure TDlgCoCryptoMain.Log(sLog: String);
begin
mmInfo.Lines.Add('[' + DateTimeToStr(Now) + '] ' + sLog);
end;
procedure TDlgCoCryptoMain.btnHashTestClick(Sender: TObject);
var
ci: TCIPHER_INFO;
sIn,
sOut: AnsiString;
nOut, nResult: Integer;
arrBuf: array [0..SHA256_DIGEST_SIZE-1] of Byte;
i: Integer;
begin
Log('해시 테스트 (SHA256)');
ZeroMemory(@ci, SizeOf(ci));
ZeroMemory(@arrBuf, SHA256_DIGEST_SIZE);
sIn := 'abcd';
sOut := '';
nOut := 0;
COLibSetCipherInfo(@ci, COLIB_MODE_SHA256, BLOCK_CRYPTO_MODE_UNUSED, COLIB_PAD_TYPE_UNUSED,
nil, 0, nil, 0, @sIn[1], Length(sIn), @arrBuf, @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibEncrypt() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
for i := 0 to nOut - 1 do
sOut := sOut + Format('%.2x', [arrBuf[i]]);
Log('입력 : ' + sIn);
Log('출력 : ' + sOut);
end;
procedure TDlgCoCryptoMain.btnHeadEncTestClick(Sender: TObject);
var
hd: TTgCoDrmHead;
nResult, nHdLen, i, nOut: Integer;
ci: TCIPHER_INFO;
sOut: AnsiString;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
pEnc, pDec: TBytes;
begin
Log('헤더 암호화 테스트');
nHdLen := SizeOf(hd);
ZeroMemory(@hd, nHdLen);
nResult := COLibGetKey(@hd.pDEK, SizeOf(hd.pDEK));
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibGetKey() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
hd.wVer := DRM_CO_VER;
hd.dwCustomerCode := 13001;
StrCopy(hd.sSig, PUTF8Char(SIG_CO_DRM));
StrCopy(hd.sFName, PUTF8Char(SIG_CO_DRM));
StrCopy(hd.sEmpNo, PUTF8Char(SIG_CO_DRM));
StrCopy(hd.sDeptName, PUTF8Char(SIG_CO_DRM));
StrCopy(hd.sHostName, PUTF8Char(SIG_CO_DRM));
hd.llEncDT := DelphiDtToJavaDt(Now);
// sOut := '';
// for i := 0 to nHdLen - 1 do
// sOut := sOut + Format('%.2x', [TBytes(@hd)[i]]);
// Log('원본 데이터 (Hex) : ' + sOut);
SetLength(pEnc, nHdLen + 500);
ZeroMemory(pEnc, nHdLen + 500);
SetLength(pDec, nHdLen + 500);
ZeroMemory(pDec, nHdLen + 500);
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_PKCS,
@hd.pDEK, COLIB_USER_KEY_LEN, @arrIV, 0,
@hd, nHdLen, @pEnc[0], @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibEncrypt() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
sOut := '';
for i := 0 to nOut - 1 do
sOut := sOut + Format('%.2x', [pEnc[i]]);
Log('암호화 데이터 (Hex) : ' + sOut);
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_PKCS,
@hd.pDEK, COLIB_USER_KEY_LEN, @arrIV, 0,
@pEnc[0], nOut, @pDec[0], @nOut);
nResult := COLibDecrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibDecrypt() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
// sOut := '';
// for i := 0 to nOut - 1 do
// sOut := sOut + Format('%.2x', [pDec[i]]);
// Log('복호화 데이터 (Hex) : ' + sOut);
Log('복호화 데이터 문자열 출력 : ' + PTgCoDrmHead(@pDec[0]).sSig);
end;
procedure TDlgCoCryptoMain.Button1Click(Sender: TObject);
const
BUF_LEN_64K = 1024 * 64;
var
sPath: String;
fsSrc, fsDst: TFileStream;
arrBuf, arrEnc: array [0..BUF_LEN_64K-1] of Byte;
dwRead: DWORD;
nOut, nResult: Integer;
pt: TCOLIB_PAD_TYPE;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
begin
sPath := 'C:\Users\kku\Desktop\TEST\123.mp4';
if not FileExists(sPath) then
exit;
ZeroMemory(@ci, SizeOf(ci));
ZeroMemory(@arrIV, SizeOf(arrIV));
Guard(fsSrc, TFileStream.Create(sPath, fmOpenRead));
Guard(fsDst, TFileStream.Create(sPath + '.1', fmCreate));
while fsSrc.Position < fsSrc.Size do
begin
dwRead := fsSrc.Read(arrBuf, BUF_LEN_64K);
if (dwRead mod COLIB_BLOCK_LEN) = 0 then
pt := COLIB_PAD_TYPE_NO
else
pt := COLIB_PAD_TYPE_PKCS;
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, pt,
@arrKey_, COLIB_USER_KEY_LEN, @arrIV, 0,
@arrBuf, dwRead, @arrEnc, @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibEncrypt() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
fsDst.Write(arrEnc, nOut);
end;
end;
procedure TDlgCoCryptoMain.Button2Click(Sender: TObject);
const
BUF_LEN_64K = 1024 * 64;
var
sPath: String;
fsSrc, fsDst: TFileStream;
arrBuf, arrEnc: array [0..BUF_LEN_64K-1] of Byte;
dwRead: DWORD;
nOut, nResult: Integer;
pt: TCOLIB_PAD_TYPE;
ci: TCIPHER_INFO;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
begin
sPath := 'C:\Users\kku\Desktop\TEST\123.mp4.1';
if not FileExists(sPath) then
exit;
ZeroMemory(@ci, SizeOf(ci));
ZeroMemory(@arrIV, SizeOf(arrIV));
Guard(fsSrc, TFileStream.Create(sPath, fmOpenRead));
Guard(fsDst, TFileStream.Create(sPath + '.mp4', fmCreate));
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;
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, pt,
@arrKey_, COLIB_USER_KEY_LEN, @arrIV, 0,
@arrBuf, dwRead, @arrEnc, @nOut);
nResult := COLibDecrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibDecrypt() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
fsDst.Write(arrEnc, nOut);
end;
end;
function ProtectProcessHandle: Boolean;
var
hProcess: THandle;
pSD: PSECURITY_DESCRIPTOR;
pA: PACL;
ea: EXPLICIT_ACCESS;
dwRes: DWORD;
begin
Result := false;
hProcess := GetCurrentProcess;
// 모든 사용자에 대한 접근 권한 제거용 ACE 설정
ZeroMemory(@ea, SizeOf(EXPLICIT_ACCESS));
ea.grfAccessPermissions := PROCESS_ALL_ACCESS;
ea.grfAccessMode := DENY_ACCESS;
ea.grfInheritance := NO_INHERITANCE;
ea.Trustee.TrusteeForm := TRUSTEE_IS_NAME;
ea.Trustee.TrusteeType := TRUSTEE_IS_WELL_KNOWN_GROUP;
ea.Trustee.ptstrName := 'Everyone';
// DACL 생성
dwRes := SetEntriesInAcl(1, @ea, nil, pA);
if dwRes <> ERROR_SUCCESS then
begin
Writeln('SetEntriesInAcl failed: ', dwRes);
Exit;
end;
// 보안 정보 설정
dwRes := SetSecurityInfo(hProcess, SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
nil, nil, pA, nil);
Result := dwRes = ERROR_SUCCESS;
// if dwRes <> ERROR_SUCCESS then
// Writeln('SetSecurityInfo failed: ', dwRes)
// else
// Writeln('Process handle protection applied successfully.');
// 정리
if pA <> nil then
LocalFree(HLOCAL(pA));
end;
procedure ProtectProcessFromTerminate;
const
ACL_REVISION = 2;
var
hProcess: THandle;
res: DWORD;
acl: TACL;
begin
ZeroMemory(@acl, SizeOf(acl));
if InitializeAcl(acl, SizeOf(acl), ACL_REVISION) then
begin
hProcess := GetCurrentProcess;
// DACL을 비워서 (NULL이 아님) 다른 사용자 접근 차단
res := SetSecurityInfo(
hProcess,
SE_KERNEL_OBJECT,
DACL_SECURITY_INFORMATION,
nil, nil, @acl, nil
);
if res <> ERROR_SUCCESS then
RaiseLastOSError(res);
end;
end;
procedure RemoveDebugPrivilege;
var
hToken: THandle;
tkp: TOKEN_PRIVILEGES;
dwLen: DWORD;
begin
OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES, hToken);
LookupPrivilegeValue(nil, 'SeDebugPrivilege', tkp.Privileges[0].Luid);
tkp.PrivilegeCount := 1;
tkp.Privileges[0].Attributes := SE_PRIVILEGE_REMOVED;
AdjustTokenPrivileges(hToken, FALSE, tkp, 0, nil, dwLen);
CloseHandle(hToken);
end;
function SetProcessAsProtected: Boolean;
const
ProcessProtectionLevelInfo = 34;
PROTECTION_LEVEL_WINTCB_LIGHT = 2;
PROTECTION_LEVEL_WINTCB = 1;
PROTECTION_LEVEL_ANTIMALWARE = 3;
type
PROCESS_PROTECTION_LEVEL_INFORMATION = record
ProtectionLevel: DWORD;
end;
var
hProcess: THandle;
ppli: PROCESS_PROTECTION_LEVEL_INFORMATION;
begin
Result := False;
hProcess := GetCurrentProcess;
// Protected Process Light (PPL)로 설정
ZeroMemory(@ppli, SizeOf(ppli));
ppli.ProtectionLevel := PROTECTION_LEVEL_WINTCB_LIGHT;
if SetProcessInformation(hProcess, TProcessInformationClass(ProcessProtectionLevelInfo), @ppli, SizeOf(ppli)) then
Result := True
else
OutputDebugString(PChar('보호 설정 실패: ' + SysErrorMessage(GetLastError)));
CloseHandle(hProcess);
end;
procedure TDlgCoCryptoMain.Button3Click(Sender: TObject);
begin
ProtectProcessHandle;
// ProtectProcessFromTerminate;
// SetProcessShutdownParameters($3FF, SHUTDOWN_NORETRY);
// RemoveDebugPrivilege;
// if SetProcessAsProtected then
// ShowMessage('프로세스가 Protected Process Light로 보호되었습니다!')
// else
// ShowMessage('보호 설정 실패. 관리자 권한으로 실행하세요.');
end;
procedure TDlgCoCryptoMain.btnBlcokEncTestClick(Sender: TObject);
var
sIn, sOut: AnsiString;
nResult, nOut, i: Integer;
ci: TCIPHER_INFO;
pBuf: TBytes;
arrIV: array [0..COLIB_BLOCK_LEN-1] of Byte;
{arrKey, }arrEnc, arrDec: array [0..COLIB_USER_KEY_LEN-1] of Byte;
begin
Log('블록 암호화 (ARIA)');
sIn := 'abcdefg97';
// sIn := '123456789012345';
Log('입력 : ' + sIn);
ZeroMemory(@ci, SizeOf(ci));
// ZeroMemory(@arrKey, SizeOf(arrKey));
ZeroMemory(@arrIV, SizeOf(arrIV));
ZeroMemory(@arrEnc, SizeOf(arrEnc));
ZeroMemory(@arrDec, SizeOf(arrDec));
// nResult := COLibGetKey(@arrKey, COLIB_USER_KEY_LEN);
// if nResult <> COLIB_SUCCESS then
// begin
// Log('Fail .. COLibGetKey() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
// exit;
// end;
nResult := COLibDrbg(@arrIV, SizeOf(arrIV), nil, 0, nil, 0, 0);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibDrbg() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_PKCS,
@arrKey_, COLIB_USER_KEY_LEN, @arrIV, SizeOf(arrIV),
@sIn[1], Length(sIn), @arrEnc, @nOut);
nResult := COLibEncrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibEncrypt() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
sOut := '';
for i := 0 to nOut - 1 do
sOut := sOut + Format('%.2x', [arrEnc[i]]);
Log('암호화 데이터 (Hex) : ' + sOut);
COLibSetCipherInfo(@ci, COLIB_MODE_ARIA, BLOCK_CRYPTO_MODE_CBC, COLIB_PAD_TYPE_PKCS,
@arrKey_, COLIB_USER_KEY_LEN, @arrIV, SizeOf(arrIV),
@arrEnc, nOut, @arrDec, @nOut);
nResult := COLibDecrypt(@ci);
if nResult <> COLIB_SUCCESS then
begin
Log('Fail .. COLibDecrypt() .. Error=' + IntToStr(nResult) + ', ' + COLibGetErrorStr(nResult));
exit;
end;
sOut := '';
for i := 0 to nOut - 1 do
sOut := sOut + Format('%.2x', [arrDec[i]]);
Log('복호화 데이터 (Hex) : ' + sOut);
Log('복호화 데이터 문자열 출력 : ' + PAnsiChar(@arrDec));
// COLibZeroCipherInfo(@ci);
end;
end.