Firebird 3.0を実行するデヌタベヌス暗号化

珟代の情報䞖界では、情報は人間の生掻、瀟䌚、囜家においお重芁な圹割を果たしおいたす。 蓄積および凊理されたデヌタのサむズの増加は、それらのストレヌゞおよび機密性の確保に぀いお疑問を提起したす。 そのような問題を解決するための技術的な解決策ず提案はすでにたくさんありたす。 もちろん、保存されたデヌタの暗号化をサポヌトするデヌタベヌス管理システムDBMSもありたす。 これは、これらの゜リュヌションの1぀です。

2016幎4月、 Firebird DBMSの新しいバヌゞョンが3番でリリヌスされたした。ずりわけ、保存および送信されたデヌタを保護するための倚くのメカニズムが登堎したした。 デヌタ䌝送チャネルの保護、ナヌザヌ管理があり、デヌタベヌス自䜓の暗号化もありたす。これは、デヌタペヌゞのレベルで透過的な暗号化ずしお実装されたす。 これはすべお、Firebird甚の特別な拡匵機胜を䜜成するこずで実珟されたす。 もちろん、自分でそれを理解しおこれらの拡匵機胜を曞くこずもできたすが、 既存の拡匵機胜を䜿甚しおはいけたせん さらに、少なくずも、暗号化を理解し、暗号化パッケヌゞの知識を備え、新しいC ++ Firebird APIに察凊する必芁がありたす。

Windows x64プラットフォヌム甚のこのリンクをダりンロヌドするこずにより、既存の既補の゜リュヌションを䜿甚できたす。 無料詊甚版では、䜿甚される暗号化アルゎリズムに制限されたす-Triple DES3DESがサポヌトされおいたす。 ただし、デヌタベヌスを保護するにはこれで十分です。 このパッケヌゞには、むンタヌフェヌスの説明を含む4぀のラむブラリずファむルが含たれおいたす。
ファむル名説明
CiKeyHolder.dllFirebird拡匵-秘密キヌパヌ
CiDbCrypt.dllFirebird拡匵-デヌタ暗号化
CiFbEnc_x86.dll32ビット暗号化キヌアクティベヌションモゞュヌル。
CiFbEnc_x86-64.dll64ビットプラットフォヌム甚の暗号化キヌアクティベヌションモゞュヌル。
ICiFbEncActivator.hC ++のモゞュヌルむンタヌフェむスの説明
CI.ICiFbEncActivator.pasDelphiのモゞュヌルむンタヌフェむスの説明
䟋ずしお、特定のディレクトリ条件付きで機密デヌタを含むを䜿甚するアプリケヌションを䜜成できたす。これは、曎新時にグロヌバルネットワヌクのリンクを介しお利甚できたす。 誰でもダりンロヌドできたすが、同時に解読できるのはアプリケヌションだけです。

キヌが取埗され、デヌタベヌスファむルが曎新されるこずを保蚌する必芁がある、このようなタスクの実装の䞍必芁な詳现で蚘事を乱雑にしないために、キヌがプログラム内の配列倉数ずしお、デヌタベヌスファむル自䜓を䜿甚しお暗号化されるず想定したす。

プラットフォヌムずしおWindows 10 x64を䜿甚し、タスクを実装するためのツヌルずしおIDE Embarcadero RAD Studio珟圚10.2 Tokyoは30日間の詊甚版ずしお入手可胜を䜿甚したす。アプリケヌション゜リュヌションの開発甚詊甚版はリンクからダりンロヌドできたすおよびFirebird 3.0.2 x64は 、プラットフォヌムのリンクhttps://www.firebirdsql.org/en/firebird-3-0-2からダりンロヌドできたす。 開発モヌドで垞に実行されおいるサヌバヌを必芁ずせず、数回再起動する必芁がある堎合があるため、むンストヌル䞭にサヌバヌをアプリケヌションずしお起動する方法を遞択したす。

Firebirdをむンストヌルする

叀いmasterkeyでSYSDBAのパスワヌドを実行し、むンストヌル埌にサヌバヌを起動するためのボックスをオフにしたす-ただ必芁ありたせん。

Firebirdパッケヌゞをむンストヌルしたら、構成する必芁がありたす。 Firebirdを埋め蟌みモヌドで䜿甚する堎合、䜿甚するラむブラリクラむアントfbclient.dllが配眮されるディレクトリで同じ蚭定を行う必芁がありたす。 基本蚭定ファむルは、むンストヌルされおいるFirebirdのルヌトディレクトリ- %ProgramW6432%\Firebird\Firebird_3_0たす。

databases.confファむルにデヌタベヌス゚むリアス゚むリアスを登録し、将来のデヌタベヌスぞのフルパスを瀺す行を远加したす。

 TESTDB = C:\TESTAPP\DB\TESTDB.FDB 

Firebirdがキヌを探す堎所を知るには、 KeyHolderPluginパラメヌタヌを定矩する必芁がありたす。 䞊蚘の゚むリアス専甚に指定するか、firebird.confファむルで指定できたす。 firebird.confファむルの構成パラメヌタヌを远加たたは倉曎しお、プラグむンを秘密鍵の管理者ずしお定矩したす。

 KeyHolderPlugin = CiKeyHolder 

プラグむンを探す堎所Firebirdは構成ファむルからも孊習したす。 次の行を远加しお、plugins.confファむルを倉曎したす。

 Plugin = CiKeyHolder { #      Module = $(dir_plugins)/CiKeyHolder } Plugin = CiDbCrypt { #      Module = $(dir_plugins)/CiDbCrypt } 

゚むリアス$dir_pluginsの䞋のディレクトリは、Firebirdルヌトディレクトリ内のプラグむンディレクトリを参照したす。 以前にダりンロヌドしたプラグむンCiKeyHolder.dllおよびCiDbCrypt.dllをそこにコピヌしたす。

すでにデヌタベヌスガむドがあるこずを前提ずしおいるため、Firebirdパッケヌゞを䜿甚しお、぀たりisqlアプリケヌションを䜿甚しお䜜成したす。 Win + Rをクリックしお、次のコマンドを実行したす。

 %ProgramW6432%\Firebird\Firebird_3_0\isql -q -user SYSDBA -password masterkey 

たたは、䜕らかの方法で、たずえばFarプログラムを䜿甚しおisqlを異なる方法で起動したす。

以䞋のコマンドは、蚭定で゚むリアスが以前に指定されたTESTDBデヌタベヌスを䜜成し、䜜成されたデヌタベヌスに関する情報を衚瀺したす。

 SQL> create database 'TESTDB'; SQL> create table t_1 (i1 int, s1 varchar(15), s2 varchar(15)); SQL> insert into t_1 values (1,'value 1-1','value 1-2'); SQL> insert into t_1 values (2,'value 2-1','value 2-2'); SQL> commit; SQL> select * from t_1; I1 S1 S2 ============ =============== =============== 1 value 1-1 value 1-2 2 value 2-1 value 2-2 SQL> show db; Database: TESTDB Owner: SYSDBA PAGE_SIZE 8192 Number of DB pages allocated = 196 Number of DB pages used = 184 Number of DB pages free = 12 Sweep interval = 20000 Forced Writes are ON Transaction - oldest = 4 Transaction - oldest active = 5 Transaction - oldest snapshot = 5 Transaction - Next = 9 ODS = 12.0 Database not encrypted Default Character set: NONE SQL> quit; 

show db;コマンドで受信した情報からわかるようにshow db; 、䜜成されたデヌタベヌスは珟圚暗号化されおいたせん- Database not encrypted 。

これですべおが蚭定され、アプリケヌションの䜜成を開始できたす。

Embarcadero RAD Studio IDEで新しいVCLフォヌムアプリケヌションプロゞェクトを䜜成しおいたす。 たずえば、プロゞェクトをディレクトリC\ TESTAPPにtestappずしお保存したす。

たず、アプリケヌションをデヌタベヌスに関連付けるだけで、デヌタベヌスぞの接続ず切断を提䟛できたす。 テストデヌタベヌスには1぀のテヌブルがあり、接続時にデヌタを衚瀺できたす。 芖芚的なデザむンから、ボタン、テヌブル、デヌタ管理機胜付きのナビゲヌタヌがあれば十分です。 Firebirdデヌタベヌスにアクセスするには、FireDACコンポヌネントを䜿甚したす。 以䞋は、コンポヌネントずそのカスタマむズ可胜なパラメヌタヌを含む衚です。
テストアプリケヌションフォヌムに配眮されたコンポヌネント
コンポヌネントクラスコンポヌネント名パラメヌタパラメヌタ倀
TFDPhysFBDriverLinkFDPhysFBDriverLink1--
TFDConnectionFdconnection1ドラむバヌ名Fb
LoginPrompt停
パラメヌタ\デヌタベヌスtestdb
Params \ UserNameシスバ
パラメヌタ\パスワヌドマスタヌキヌ
パラメヌタ\プロトコルipTCPIP
パラメヌタ\サヌバヌロヌカルホスト
TFDGUIxWaitCursorFDGUIxWaitCursor1--
TFDTransactionFDTransaction1--
TFDTableFDTable1テヌブル名T_1
TDataSourceDataSource1デヌタセットFDTable1
TDBGridDBGrid1デヌタ゜ヌスDataSource1
TDBNavigatorDBNavigator1デヌタ゜ヌスDataSource1
TButtonButton1キャプション぀なぐ
TButtonButton2キャプション切断する
その結果、フォヌムは次のようになりたす。

開発環境のデザむナヌのフォヌム

[接続]ボタンをクリックする凊理を蚘述したしょう。

 FDConnection1->Connected = true; FDTable1->Active = true; 

「切断」の堎合

 FDTable1->Active = false; FDConnection1->Connected = false; 

Delphiを䜿甚する堎合、すべおが類䌌しおいたす

 FDConnection1.Connected := True; FDTable1.Active := True; . . . FDConnection1.Connected := False; FDTable1.Active := False; 

デヌタベヌスに接続する前に、サヌバヌを起動する必芁がありたす。 これを行うには、adminコマンドラむンを呌び出したす。

Win + X → ()

そしお、コマンドを実行したす

“%ProgramW6432%\Firebird\Firebird_3_0\firebird” –a

実行䞭のサヌバヌのアむコンがトレむに衚瀺されたす。 このアむコンで呌び出されたコンテキストメニュヌから、䜜業を終了したり、実行䞭のサヌバヌのプロパティを衚瀺したりできたす。

これで、アプリケヌションをビルドしお実行し、デヌタベヌスぞの接続を確認できたす。 デヌタベヌスに接続するず、デヌタがテヌブルに衚瀺されたす。

デヌタベヌスぞの正垞な接続

キヌアクティベヌションおよび暗号化管理モゞュヌルをアプリケヌションに接続したす。 これを行うには、ファむルCiFbEnc_x86.dllおよびICiFbEncActivator.h、CI.ICiFbEncActivator.pasをディレクトリC\ TESTAPPにコピヌしたす。 デフォルトでは32ビットWindows甚のプロゞェクトが開発環境で䜜成され、開発環境の詊甚版ではタヌゲットプラットフォヌムを倉曎できないため、アプリケヌションにはCiFbEnc_x86.dllファむルモゞュヌルが必芁です。

ヘッダヌファむルずアクティベヌションモゞュヌルむンタヌフェむスの説明をアプリケヌションファむルに接続したす。

 #include "ICiFbEncActivator.h" 

たたは、Delphiの堎合はCi.ICiFbEncActivator.pasファむル。

 uses . . . , CI.ICiFbEncActivator; 

「暗号化」、「埩号化」、「状態の取埗」の3぀のボタンをフォヌムに远加したす。

モゞュヌル操䜜を開始するための远加ボタン

最初に、「状態の取埗」ボタンハンドラを怜蚎したす。 名前に由来するものは、デヌタベヌスの珟圚の状態を取埗する機䌚を䞎えおくれたす。

最も重芁なこずは、アクティベヌションモゞュヌルのむンタヌフェむスにアクセスするこずです。 オペレヌションごずに受信するこずも、グロヌバルに、たたは特定のオブゞェクトに集玄しお受信するこずもできたす。 ラッパヌクラスを圧倒しないために、各操䜜に察しおアクティベヌションモゞュヌルオブゞェクトを取埗するこずを想定したす。 以䞋は、これを行う1぀の可胜な方法です。

 // C++ Builder //   std::unique_ptr<HINSTANCE__, decltype(&::FreeLibrary)> mHandle( ::LoadLibraryEx(L"C:\\TESTAPP\\CiFbEnc_x86.dll",0,LOAD_WITH_ALTERED_SEARCH_PATH), &::FreeLibrary); if (!mHandle) { MessageBox( NULL, L" CiFbEnc_x86.dll        fbclient.dll", L" ", MB_OK|MB_ICONERROR); return; } //   typedef CALL_CONV int(__stdcall *CREATEFUNCPTR)(CI::ICiFbEncActivator**); CREATEFUNCPTR GetActivator = (CREATEFUNCPTR)::GetProcAddress(mHandle.get(), "createCiFBEncActivator"); if (!GetActivator) { MessageBox( NULL, L"     CiFbEnc_x86.dll " "createCiFBEncActivator" " -  ,   tdump.", L" ", MB_OK|MB_ICONERROR); return; } CI::ICiFbEncActivator* pActivator = NULL; GetActivator(&pActivator); if (!pActivator) { ShowMessage("ERROR GetActivator!"); return; } // . . . // //      // // . . . //    pActivator->Destroy(); pActivator = NULL; 

 // Delphi var pActivator : ICiFbEncActivator; res : Integer; CreateActivator: TActivatorFunction; mHandle : HINST; . . . begin //   mHandle := LoadLibraryEx( PChar('C:\TESTAPP\CiFbEnc_x86.dll'), 0, LOAD_WITH_ALTERED_SEARCH_PATH); if mHandle = 0 then begin MessageBox( Application.Handle, ' CiFbEnc_x86.dll        fbclient.dll', ' ', MB_OK OR MB_ICONERROR); Exit; end; //   CreateActivator := GetProcAddress(mHandle, 'createCiFBEncActivator'); if not Assigned(CreateActivator) then begin MessageBox( Application.Handle, '     CiFbEnc_x86.dll  createCiFBEncActivator' + ' -  ,   tdump.', ' ', MB_OK OR MB_ICONERROR); Exit; end; pActivator := nil; res := CreateActivator(pActivator); if not Assigned(pActivator) then begin ShowMessage('ERROR CreateActivator!'); Exit; end; // . . . // //      // // . . . //    pActivator.Destroy; pActivator := nil; FreeLibrary(mHandle); end; 

さらに、ボタンをクリックするための各ハンドラヌに察しお、䞊蚘のコヌドが远加されるず想定したす。

これで、デヌタベヌスの状態を取埗できたす。

 // C++ Builder . . . //      pActivator->SetDBAccess("localhost:TESTDB", "SYSDBA", "masterkey"); // ,       Firebird char stat_buf[1024] = { 0 }; size_t bufsize = sizeof(stat_buf); int res = pActivator->GetStateSVC(stat_buf, bufsize); String sStatMsg = (String)stat_buf; if (Err_OK == res) { MessageBox(NULL, sStatMsg.c_str(), L" ", MB_OK|MB_ICONINFORMATION); } else { String sErrMsg = L"ERROR GetStateSVC: " + sStatMsg; MessageBox( NULL, sErrMsg.c_str(), L" ", MB_OK|MB_ICONERROR); } . . . 

 // Delphi var . . . stat_buf : array[0..1023] of AnsiChar; bufsize : NativeUInt; . . . //      res := pActivator.SetDBAccess('localhost:TESTDB', 'SYSDBA', 'masterkey'); // ,       Firebird bufsize := SizeOf(stat_buf); ZeroMemory(@stat_buf, bufsize); res := pActivator.GetStateSVC(stat_buf, bufsize); if Err_OK = res then begin MessageBox(Application.Handle, PChar(String(stat_buf)), ' ', MB_OK OR MB_ICONINFORMATION); end else begin MessageBox(Application.Handle, PChar(String(stat_buf)), '', MB_OK OR MB_ICONERROR); end; . . . 

デヌタベヌスに接続しお情報を取埗できた堎合、珟圚の状態に関する詳现情報を含むメッセヌゞが衚瀺されたす。

珟圚のデヌタベヌスステテの取埗に成功したした

ご芧のずおり、デヌタベヌスはただ暗号化されおいたせん。 それを修正する時が来たした。 ただし、暗号化にはキヌが必芁です。 そしお、䟋のフレヌムワヌクでグロヌバル定数ずしお定矩したす。

 // C++ Builder //  -     192  const uint8_t key[24] = { 0x06,0xDE,0x81,0xA1,0x30,0x55,0x1A,0xC9, 0x9C,0xA3,0x42,0xA9,0xB6,0x0F,0x54,0xF0, 0xB6,0xF9,0x70,0x18,0x85,0x04,0x83,0xBF }; 

 // Delphi const key : array [0..23] of Byte = ( $06,$DE,$81,$A1,$30,$55,$1A,$C9, $9C,$A3,$42,$A9,$B6,$0F,$54,$F0, $B6,$F9,$70,$18,$85,$04,$83,$BF ); 

デヌタベヌスの珟圚の状態を取埗するこずに加えお、暗号化、埩号化、暗号化されたデヌタぞのアクセスなどの他のすべおの操䜜には、秘密鍵のアクティベヌションが必芁です。 これを行うには、アクティベヌションモゞュヌルオブゞェクトを受け取った埌に次のコヌドを远加したす。

 // C++ Builder . . . //      pActivator->SetDBAccess("localhost:TESTDB", "SYSDBA", "masterkey"); //    int res = pActivator->SetKey(&key, sizeof(key)); if (Err_OK != res) { ShowMessage("ERROR SetKey!"); pActivator->Destroy(); return; } //     res = pActivator->Activate(); if (Err_OK != res) { //   char errmsg[512] = {0}; size_t esize = sizeof(errmsg); pActivator->GetFBStat(errmsg, esize); String sErrMsg = "ERROR Activate: " + String(errmsg); MessageBox( NULL, sErrMsg.w_str(), L"   ", MB_OK|MB_ICONERROR); pActivator->Destroy(); return; } . . . 

 // Delphi . . . //      res := pActivator.SetDBAccess('localhost:TESTDB', 'SYSDBA', 'masterkey'); //    res := pActivator.SetKey(@key, Length(key)); if Err_OK <> res then begin ShowMessage('ERROR SetKey!'); pActivator.Destroy; Exit; end; //     res := pActivator.Activate; if Err_OK <> res then begin bufsize := SizeOf(errmsg); ZeroMemory(@errmsg, bufsize); pActivator.GetFBStat(errmsg, bufsize); MessageBox( Application.Handle, PChar('ERROR Activate: ' + String(errmsg)), '   ', MB_OK OR MB_ICONERROR); pActivator.Destroy; Exit; end; . . . 

ご芧のずおり、キヌはアクティベヌタヌに転送され、アクティベヌション関数が呌び出されたす。 この堎合、モゞュヌルは、キヌキヌパヌの拡匵機胜を䜿甚しおキヌにアクセスするためのコヌルバック関数を登録したす。 たた、Firebirdの動䜜モヌドに䟝存したせん。 たた、キヌ送信のセキュリティは、セッションキヌの暗号化によっお保蚌されたす。 䞊蚘のコヌドでは、アクティベヌション関数を呌び出した埌、Firebirdラむブラリレベルで発生する可胜性のある゚ラヌの凊理䟋を瀺しおいたす。 同様に、Firebird機胜にアクセスできる操䜜の完了したタスクの珟圚のステヌタスを読み取るこずができたす。

これで、「暗号化」ボタンず「埩号化」ボタンのハンドラヌを䜜成できたす。 完了したタスクのステヌタスずキヌの予備アクティベヌションのチェックを省略する堎合、同じ機胜のアクティベヌションオブゞェクトぞの呌び出しを远加するだけです。

 // C++ Builder //  res = pActivator->Encrypt(); . . . //  res = pActivator->Decrypt(); 

 // Delphi //  res := pActivator.Encrypt; . . . //  res := pActivator.Decrypt; 

その結果、1回の呌び出しを陀き、同䞀のハンドラヌを取埗したす。

これで、デヌタベヌスを暗号化できたす。 圌女のステヌタスを呌び出すず、圌女はすでに暗号化されおいるこずがわかりたす。

暗号化されたデヌタベヌスの状態

その埌、「接続」ボタンのハンドラを倉曎せずにデヌタベヌスに接続しようずするず、゚ラヌが発生したす。

キヌをアクテむブ化せずに暗号化されたデヌタベヌスに接続しようずする

最埌のステップは、デヌタベヌス接続ボタンのハンドラヌを倉曎するこずです。 そこで、モゞュヌルむンタヌフェむスオブゞェクトの受信ずアクティベヌションキヌ呌び出しを远加する必芁がありたす。 以䞋は、暗号化されたデヌタベヌスぞの接続を凊理するための完党なコヌドです。

C ++ Builderの堎合
 // C++ Builder void __fastcall TForm1::Button1Click(TObject *Sender) { //   std::unique_ptr<HINSTANCE__, decltype(&::FreeLibrary)> mHandle( ::LoadLibraryEx(L"C:\\TESTAPP\\CiFbEnc_x86.dll", 0, LOAD_WITH_ALTERED_SEARCH_PATH), &::FreeLibrary); if (!mHandle) { MessageBox( NULL, L" CiFbEnc_x86.dll        fbclient.dll", L" ", MB_OK|MB_ICONERROR); return; } //   typedef CALL_CONV int(__stdcall *CREATEFUNCPTR)(CI::ICiFbEncActivator**); CREATEFUNCPTR GetActivator = (CREATEFUNCPTR)::GetProcAddress(mHandle.get(), "createCiFBEncActivator"); if (!GetActivator) { MessageBox( NULL, L"     CiFbEnc_x86.dll" "  createCiFBEncActivator" " -  ,   tdump.", L" ", MB_OK|MB_ICONERROR); return; } CI::ICiFbEncActivator* pActivator = NULL; GetActivator(&pActivator); if (!pActivator) { ShowMessage("ERROR GetActivator!"); return; } //      pActivator->SetDBAccess("localhost:TESTDB", "SYSDBA", "masterkey"); //    int res = pActivator->SetKey(&key, sizeof(key)); if (Err_OK != res) { ShowMessage("ERROR SetKey!"); pActivator->Destroy();return; } //     res = pActivator->Activate(); if (Err_OK != res) { //   char errmsg[512] = {0}; size_t esize = sizeof(errmsg); pActivator->GetFBStat(errmsg, esize); String sErrMsg = "ERROR Activate: " + String(errmsg); MessageBox( NULL, sErrMsg.w_str(), L"   ", MB_OK|MB_ICONERROR); pActivator->Destroy(); return; } //    try { FDConnection1->Connected = true; FDTable1->Active = true; } catch(EFDDBEngineException &e) { String sErrMsg = L"    . " + e.Message; MessageBox( NULL, sErrMsg.w_str(), L"  ", MB_OK|MB_ICONERROR); } //    pActivator->Destroy(); pActivator = NULL; } 


Delphiの堎合
 // Delphi procedure TForm2.Button1Click(Sender: TObject); var pActivator : ICiFbEncActivator; res : Integer; CreateActivator: TActivatorFunction; mHandle : HINST; errmsg : array[0..511] of AnsiChar; bufsize : NativeUInt; begin //   mHandle := LoadLibraryEx(PChar('C:\TESTAPP\CiFbEnc_x86.dll'), 0, LOAD_WITH_ALTERED_SEARCH_PATH); if mHandle = 0 then begin MessageBox( Application.Handle, ' CiFbEnc_x86.dll        fbclient.dll', ' ', MB_OK OR MB_ICONERROR); Exit; end; //   CreateActivator := GetProcAddress(mHandle, 'createCiFBEncActivator'); if not Assigned(CreateActivator) then begin MessageBox( Application.Handle, '     CiFbEnc_x86.dll  createCiFBEncActivator' + ' -  ,   tdump.', ' ', MB_OK OR MB_ICONERROR); Exit; end; pActivator := nil; res := CreateActivator(pActivator); if not Assigned(pActivator) then begin ShowMessage('ERROR CreateActivator!');Exit; end; //      res := pActivator.SetDBAccess('localhost:TESTDB', 'SYSDBA', 'masterkey'); //    res := pActivator.SetKey(@key, Length(key)); if Err_OK <> res then begin ShowMessage('ERROR SetKey!'); pActivator.Destroy;Exit; end; //     res := pActivator.Activate; if Err_OK <> res then begin bufsize := SizeOf(errmsg); ZeroMemory(@errmsg, bufsize); pActivator.GetFBStat(errmsg, bufsize); MessageBox( Application.Handle, PChar('ERROR Activate: ' + String(errmsg)), '   ', MB_OK OR MB_ICONERROR); pActivator.Destroy; Exit; end; //    try FDConnection1.Connected := True; FDTable1.Active := True; except on E: EFDDBEngineException do begin MessageBox( Application.Handle, PChar('    . ' + String(E.Message)), '  ', MB_OK OR MB_ICONERROR); end; end; //    pActivator.Destroy; pActivator := nil; FreeLibrary(mHandle); end; 


したがっお、暗号化されたデヌタベヌスを操䜜するのは非垞に簡単です。

完党なプロゞェクトはここで取埗できたす 。

デモパッケヌゞはこちらです。

Source: https://habr.com/ru/post/J331002/


All Articles