Minn suġġett tar-rivista għall-prattika tal-proġett
Paġni ta' servizz u paġni tekniċi relevanti għall-artiklu
Fuq enkrizzjoni AES Delphi fil-prattika mhux dejjem ikun problema l‑„AES per se“, iżda l‑kundizzjonijiet tal‑kuntest: id‑dejta trid tiġi pproċessata bħala stream (fajls, BLOBs, backups), il‑formati antiki jridu jibqgħu jinreadu, u fil‑produzzjoni għandek bżonn debbuġjar (header, verżjoni) u defaults sigur (Salt/IV każwali, mingħajr ri‑użu). Din il‑biċċa kodiċi tidher mhux biss l‑“Encrypt/Decrypt”, iżda format żgħir u affidabbli b’header, verżjoni, Salt u IV – inkluż PBKDF2 għall‑derivazzjoni tal‑key u punt fejn l‑integrità tista’ tiġi miżjuda b’mod sensibbli.
Għaliex „enkrizzjoni ta‘ string b’AES“ kważi qatt ma tkun biżżejjed
Fi softwer aziendali individwalizzat, enkrizzjoni tipikament tidher f’tlett postijiet: (1) konfigurazzjoni/Secrets (eż. kredenzjali ta’ aċċess), (2) fajls ta’ skambju/esportazzjoni u (3) dejta statika (eż. arkivji, kontenituri ta’ dokumenti). L‑approċċ naiv „password → AES‑Key → string in/out“ jisfrutta malajr:
- Ri‑użu tal‑IV: F’modi bħal CBC jew GCM vettur ta’ inizjalizzazzjoni (IV) għandu jkun uniku għal kull enkrizzjoni. IV kostanti huwa twessigħa ta’ sigurtà, anke jekk il‑password ikun robust.
- Key minn password mingħajr KDF: L‑użu ta’ password direttament bħala key (jew hash wieħed biss) jinvita attakki offline. KDF (Key Derivation Function) bħal PBKDF2 jżid it‑tul tal‑ħin meħtieġ u jagħmilha ħafna iktar diffiċli għall‑attakkanti.
- L‑ebda verżjoni tal‑format: Mingħajr header/verżjoni mhux faċli tbiddel in‑numru ta’ iterazzjonijiet, l‑algoritmu jew il‑parametri aktar tard mingħajr ma tħalli d‑dejta l‑qadima inkompatibbli jew maqtugħa mill‑verżjonijiet ġodda.
- L‑ebda integrità: AES‑CBC jinkripta, imma ma jipprevjenix manipulazzjoni. Mingħajr awtentikazzjoni (eż. HMAC jew AEAD bħal GCM) tirċievi problemi ta’ bitflipping/padding u manifestazzjonijiet ta’ żball difficli biex jiġu d‑dijanjostikati.
Il‑pint ewlieni ta’ dan il‑test: format żgħir ta’ kontenitur li jappoġġja streaming, li jista’ jiġi verżjoni u li jevita l‑żbalji standard.
Enkrizzjoni AES Delphi b’Header, Salt, IV u PBKDF2
Niddedefinixxu format sempliċi ta’ kontenitur li jista’ jintuża wkoll f’BLOBs ta’ database jew bħala message‑payloads:
- Magic: 4 Bytes, eż.
NBAE(kontroll mgħaġġel „Hu dan il‑format tagħna?”) - Verżjoni: 1 Byte (jippermetti migrazzjoni)
- Parametri KDF: numru ta’ iterazzjonijiet (4 Bytes)
- Salt: 16 Bytes (każwali għal kull fajl)
- IV: 16 Bytes (każwali għal kull fajl għal AES‑CBC)
- Ciphertext: dejta utli enkritpata (appoġġjata għal streaming)
Importanti: Salt u IV mhumiex sigrieti. Għandhom biss ikunu ġodda għal kull enkrizzjoni. Il‑password jibqa’ sigriet; il‑key derivat minn dak m’għandux jiġi maħżun.
Enkrizzjoni AES Delphi fil‑Stream: tikteb/taqra l‑kontenitur
Il‑kodiċi huwa skritt intenzjonalment bħala «pjan ta’ kostruzzjoni»: funzjonijiet separati b’mod ċar, header li jistgħu jiġu vverifikati, l‑ebda globals moħbija. Għall‑AES u PBKDF2 ħafna timijiet jużaw libreriji kripto stabbiliti (eż. DEC). Il‑biċċa kodiċi turi l‑format u l‑mudell tas‑streaming; is‑sejħiet għall‑AES/PBKDF2 huma kapsulati b’tali mod li tista’ tbiddilhom skont il‑librerija li tuża.
unit Nb.AesContainer;
interface
uses
System.SysUtils, System.Classes, System.NetEncoding;
type
ENbCryptoError = class(Exception);
TNbAesContainer = class
public
class procedure EncryptStreamToStream(const AIn: TStream; const AOut: TStream;
const APassword: string; const AIterations: Cardinal = 200000);
class procedure DecryptStreamToStream(const AIn: TStream; const AOut: TStream;
const APassword: string);
class function EncryptBytesToBase64(const APlain: TBytes; const APassword: string): string;
class function DecryptBase64ToBytes(const ACipherB64: string; const APassword: string): TBytes;
end;
implementation
const
CMagic: array[0..3] of AnsiChar = ('N','B','A','E');
CVersion: Byte = 1;
CSaltLen = 16;
CIvLen = 16;
type
TNbHeaderV1 = packed record
Magic: array[0..3] of AnsiChar;
Version: Byte;
Iterations: Cardinal; // little endian
Salt: array[0..CSaltLen-1] of Byte;
IV: array[0..CIvLen-1] of Byte;
end;
// --- Abhängigkeiten, die Sie je nach Crypto-Stack implementieren ---
procedure FillRandomBytes(var B: TBytes);
begin
// Għall-istriming ta' ġenerazzjoni kriptografika: uża CSPRNG tal-OS
// (Windows BCryptGenRandom, Linux getrandom/urandom).
// Hawnhekk intenzjonalment bħala placeholder.
raise ENbCryptoError.Create('FillRandomBytes: CSPRNG mhux imqabbad');
end;
function PBKDF2_HMAC_SHA256(const APassword: string; const ASalt: TBytes;
const AIterations, AKeyLen: Cardinal): TBytes;
begin
// Implementazzjoni eż. bil-DEC (PBKDF2) jew librerija oħra.
// Riżultat: AKeyLen bytes.
raise ENbCryptoError.Create('PBKDF2_HMAC_SHA256: mhux imqabbad');
end;
procedure AES256_CBC_EncryptStream(const AKey, AIV: TBytes; const AIn, AOut: TStream);
begin
// Implementazzjoni permezz ta' librerija:
// - KeyLen = 32 Bytes
// - IVLen = 16 Bytes
// - PKCS#7 Padding
// Importanti: ipproman b'mod orjentat lejn il-stream, mhux kollox fil-memorja.
raise ENbCryptoError.Create('AES256_CBC_EncryptStream: mhux imqabbad');
end;
procedure AES256_CBC_DecryptStream(const AKey, AIV: TBytes; const AIn, AOut: TStream);
begin
raise ENbCryptoError.Create('AES256_CBC_DecryptStream: mhux imqabbad');
end;
// --- Helper ---
procedure WriteHeaderV1(const AOut: TStream; const H: TNbHeaderV1);
begin
if AOut.Write(H, SizeOf(H)) <> SizeOf(H) then
raise ENbCryptoError.Create('Ma setax jinkiteb il-header');
end;
function ReadHeaderV1(const AIn: TStream): TNbHeaderV1;
var
H: TNbHeaderV1;
begin
if AIn.Read(H, SizeOf(H)) <> SizeOf(H) then
raise ENbCryptoError.Create('Header mhux sħiħ');
if (H.Magic[0] <> CMagic[0]) or (H.Magic[1] <> CMagic[1]) or
(H.Magic[2] <> CMagic[2]) or (H.Magic[3] <> CMagic[3]) then
raise ENbCryptoError.Create('Mhuwiex container validu (Magic ma taqbilx)');
if H.Version <> CVersion then
raise ENbCryptoError.CreateFmt('Verżjoni tal-container mhux magħrufa: %d', [H.Version]);
if (H.Iterations < 10000) or (H.Iterations > 5000000) then
raise ENbCryptoError.Create('In-numru ta iterazzjonijiet huwa barra mill-limiti raġonevoli');
Result := H;
end;
class procedure TNbAesContainer.EncryptStreamToStream(const AIn, AOut: TStream;
const APassword: string; const AIterations: Cardinal);
var
H: TNbHeaderV1;
Salt, IV, Key: TBytes;
begin
if APassword = '' then
raise ENbCryptoError.Create('Il-password ma tistax tkun vojta');
// Salt/IV erzeugen
// Ġenerazzjoni ta' Salt u IV
SetLength(Salt, CSaltLen);
SetLength(IV, CIvLen);
FillRandomBytes(Salt);
FillRandomBytes(IV);
// Header befüllen
Move(CMagic[0], H.Magic[0], Length(CMagic));
H.Version := CVersion;
H.Iterations := AIterations;
Move(Salt[0], H.Salt[0], CSaltLen);
Move(IV[0], H.IV[0], CIvLen);
WriteHeaderV1(AOut, H);
// Key ableiten (32 Bytes für AES-256)
// Iddderiva l-key (32 bytes għal AES-256)
Key := PBKDF2_HMAC_SHA256(APassword, Salt, AIterations, 32);
// Nutzdaten verschlüsseln (Ciphertext folgt direkt nach Header)
// Il-madwar tad-dejta jiġu kriptati (il-ciphertext isegwi direttament wara l-header)
AES256_CBC_EncryptStream(Key, IV, AIn, AOut);
end;
class procedure TNbAesContainer.DecryptStreamToStream(const AIn, AOut: TStream;
const APassword: string);
var
H: TNbHeaderV1;
Salt, IV, Key: TBytes;
begin
if APassword = '' then
raise ENbCryptoError.Create('Il-password ma tistax tkun vojta');
H := ReadHeaderV1(AIn);
SetLength(Salt, CSaltLen);
SetLength(IV, CIvLen);
Move(H.Salt[0], Salt[0], CSaltLen);
Move(H.IV[0], IV[0], CIvLen);
Key := PBKDF2_HMAC_SHA256(APassword, Salt, H.Iterations, 32);
// Entschlüsseln ab aktueller Stream-Position (nach Header)
// Id-dekriptaġġ jibda mill-pożizzjoni attwali tas-stream (wara l-header)
AES256_CBC_DecryptStream(Key, IV, AIn, AOut);
end;
class function TNbAesContainer.EncryptBytesToBase64(const APlain: TBytes;
const APassword: string): string;
var
InS, OutS: TBytesStream;
begin
InS := TBytesStream.Create(APlain);
try
OutS := TBytesStream.Create;
try
EncryptStreamToStream(InS, OutS, APassword);
Result := TNetEncoding.Base64.EncodeBytesToString(OutS.Bytes, 0, OutS.Size);
finally
OutS.Free;
end;
finally
InS.Free;
end;
end;
class function TNbAesContainer.DecryptBase64ToBytes(const ACipherB64,
APassword: string): TBytes;
var
Cipher: TBytes;
InS, OutS: TBytesStream;
begin
Cipher := TNetEncoding.Base64.DecodeStringToBytes(ACipherB64);
InS := TBytesStream.Create(Cipher);
try
OutS := TBytesStream.Create;
try
DecryptStreamToStream(InS, OutS, APassword);
Result := OutS.Bytes;
SetLength(Result, OutS.Size);
finally
OutS.Free;
end;
finally
InS.Free;
end;
end;
end.Skop: Kontenitur minimali adattat għal fajls u BLOBs, inkluż verżjoni u parametri KDF. Kundizzjonijiet: Trid toħloq konnessjoni reali ma‘ CSPRNG (ġeneratur ta‘ numri pseudo każwali kryptografikament sigur mill-operating system) u twaħħal taħt implementazzjoni robusta ta‘ AES/PBKDF2. Perikli: Ma tużax „xi“ Random (ebda Random()), ebda IVs stabbiliti, u plana għal immaniġġjar ċar tal-iżbalji waqt id-decrypt (password ħażin vs. data maqduma). Varjanti: minflok CBC preferibbli AEAD (ara hawn taħt), jew iezzi header b’ID tal-algoritmu u HMAC.
Integrità: għaliex AES-CBC waħdu fil-operazzjoni huwa riskjuż
AES-CBC għadu preżenti f’ħafna kuntesti legacy u jista‘ jaħdem jekk tuża bħala komplement mekanizmu ta‘ assegurar l-integrità. Mingħajr integrità attakkant jista‘ jmaniġġja l-ciphertext; anke mingħajr attakkant attiv żbalji fil-ħruġ jew livelli tal-iskalata tal-ħażna jistgħu joħolqu żbalji tal-„Padding“ li huma diffiċli biex jiġu diagnostikati.
Għażliet pragmatiċi:
- Encrypt-then-HMAC: Wara l-ciphertext ikteb HMAC (per eż., HMAC-SHA-256) fuq Header+Ciphertext. Meta taqra, iċċekkja l-ewwel l-HMAC, imbagħad id-dekrijpja. Għal dan, ideali tkun taderiva żewġ keys minn PBKDF2 (eż., 64 Bytes: 32 għall-AES, 32 għall-HMAC), minflok tuża l-istess key darbtejn.
- AES-GCM: Modalità AEAD (Authenticated Encryption with Associated Data). Tipprovdi Ciphertext + Auth-Tag. Spiss din hi l-għażla l-iktar nadifa illum, jekk il-librerija Delphi tiegħek tappoġġja GCM b’mod stabbli. Il-kampijiet tal-header jistgħu jiġu awtentikati bħala „AAD“ mingħajr ma jkunu maħżuna b’kif encrypted.
Jekk trid tibqa‘ ma‘ CBC (pereżempju għal interoperabbiltà), Encrypt-then-HMAC hija l-komplement robust. Għall-format ġodda jiswa li tuża GCM, peress li tibgħat awtentikazzjoni mill-bidu u tagħti mudelli ta‘ żball aktar ċari.
Straordinarjament importanti: „Kryptografischer Zufall“ u għaliex System.Hash mhuwiex biżżejjed
Reflex legacy komuni f’proġetti Delphi: „Aħna sempliċement nieħdu SHA256 fuq timestamp + xi ħaġa u jkollna Random.“ Dan mhux bażi affidabbli. Għal salt u IV għandek bżonn CSPRNG (ġeneratur ta‘ numri pseudo każwali kryptografikament sigur) tal-system operattiv. Sotto Windows tipikament huwa l-API BCrypt (CNG), u sotto Linux ġeneratur tal-kernel bħall-getrandom() jew /dev/urandom. Id-differenza fil-prattika hi li CSPRNG huwa mfassal b’mod li minn valuri osservati ma jkun jista’ jsir previzjoni ta’ valuri futuri.
Trik tal-arkitettura: Kapsla dan f’unità żgħira „RandomProvider“ li tista‘ tmockja fit-tests. B’dan issolvi żewġ każijiet f’daqqa: testijiet riproduċibbli (bi seed fiss fil-mock) u sigurtà vera fil-produzzjoni (bi OS-CSPRNG). B’hekk tevita li f’hotfix wieħed jerġa‘ jidħol Random() sempliċement għax hu mgħaġġel.
Debugging u migrazzjoni legacy: ġestjoni tal-verżjonijiet mhix lussu
Il-header mhuwiex biss għal „estetika“ krittografika, iżda għall-manutenzjoni:
- Tuning tal-Iterazzjonijiet: In-numri ta‘ iterazzjonijiet tal-PBKDF2 jinbidlu maż-żmien. Bi qasam fil-header tista‘ iżżid il-kumplessità aktar tard mingħajr ma tagħmel id-dejta antika mhux aċċessibbli.
- Bidla tal-format: Eż., Verżjoni 2 tista‘ tivvjaġġa għal AES-GCM jew iżżid HMAC.
- Dijanjosi fil-post: Magic/Version jippermettu kontrolli malajr fil-logs u fl-għodod mingħajr ma jkollok bżonn tid-dekrijpja d-dejta.
Suggeriment prattiku: Implimenta „Inspector“ żgħir li jaqra biss il-header (Magic/Version/Iterations) u jikteb fil-log. B’dan tissolvu ħafna każijiet ta’ appoġġ („Liema verżjoni hawn?“) mingħajr maniġġjar ta’ passwords.
Sauber migrieren: „Read old, write new“ statt Big Bang
Jekk trid tbiddel format antik (eż. IV fiss, l-ebda KDF, Blowfish/3DES, jew XOR mibni personalment), f’proġetti Delphi irreġistra mudell prattiku: waqt il-qar tiskopri diversi formati (Magic/Version jew euristika ta’ fallback), waqt il-ktieb tinħoloq biss il-format il-ġdid. Barra minn hekk, jekk jixraq lill-proċess, tista’ fuq suċċess ta’ dekrizzjoni terġa’ t-inkripta fil-background („lazy migration“). B’hekk tnaqqas ir-riskju ta’ rollout u tevita l-obbligu ta’ „kollox jerġa’ jiżħar“ bħala fenestra ta’ manutenzjoni.
Threading und Streaming: typische Kanten in Delphi
Il-kriptar normalment jiffunzjona f’worker-threads (eż. waqt l-esportazzjoni, waqt l-upload f’portal tal-klijent, waqt il-kitba ta’ arkivji kbar). Żewġ punti li jidhru regolarment f’proġetti Delphi:
- Pożizzjonijiet tal-stream: Qabel tikkodifika/jiddeċodifika jkollok kuntratti ċari: l-input-stream jinqara mill-pożizzjoni kurrenti, l-output-stream jinkiteb mill-pożizzjoni kurrenti. Meta tirriutilizza streams kun żgur li tissettja
Position := 0b’mod konxju. - Spikes fil-memorja: Evita “kollox f’TBytes”. L-approċċ b’stream huwa kruċjali għal fajls kbar. Jekk il-librerija crypto tiegħek taċċetta biss byte-arrays, jiswa l-isforz addizzjonali biex tivverifika implimentazzjoni li tappoġġja streams jew biex toħloq adapter bufferjat.
Jekk tikkripta f’servizzi (Windows- jew Linux-Services), innota wkoll logging nadif tal-eċċezzjonijiet: „password żbaljat“, „header imkisser“, „tag/HMAC mhux validu“ huma każijiet operattivi differenti u għandhom ikunu distingwibbli. Importanti: il-messaġġi ta’ żball ma jridx ikun eċċessivament dettaljat lejn il-barra (ebda „padding żbaljat fil-block 7″ bħala żball API), imma internament fil-log jistgħu jkunu dettaljati.
Meta dan l-approċċ jiswa – u fejn jista’ jonqos
Jiswa, jekk inti: (a) taħżen b’mod lonġev dejta ta’ esportazzjoni/import imirkeb, (b) topera verżjonijiet differenti tal-programm parallelament, (c) tipproċessa dejta bħala streams, jew (d) għandek bżonn interfaċċa tal-crypto nadifa għal diversi moduli (Client/Server/Tooling).
Ma jkunx adattat, jekk tipprova b’dan issolvi “kollox”: Għall-Transport huwa responsabbli TLS, mhux wrapper AES mibni internament. Għall-Secrets (passwords, tokens) spiss ikun aktar sensat juża OS-Secret-Store jew Vault. U jekk għandek bżonn interoperabilità ma’ lingwi oħra, trid dokumentazzjoni eżatta tal-header, endianness u l-encoding (jew tuża format stabbilit).
Fazit: AES in Delphi ist weniger Algorithmus, mehr Engineering
Il-benefiċċju ewlieni ta’ dan il-framment mhuwiex biss “AES jaħdem”, imma format operattiv: salt każwali u IV, header versionjat, parametri PBKDF2 fil-payload u proċessar li jappoġġja streams. Għolli l-integrità għal formati ġodda fejn jista’ jkun (AES-GCM jew Encrypt-then-HMAC). B’hekk minn “aħna ninkriptaw xi ħaġa” isir komponent li f-soluzzjonijiet diġitali korporattivi jibqa’ manutenzjonabbli u migrabbli anke wara snin.
Jekk trid tintegra kontenitur bħal dan f’ambjent żviluppat ta‘ Delphi jew timmigra b’mod nadif minn format legacy, jiswa kontroll qasir tal-arkitettura (ġestjoni tal-muftieħ, verżjonijiet tal-format, operazzjoni/logging). Id-dettalji niddiskutuhom bi pjaċir f’laqgħa jekk meħtieġ:
Fil-kuntest tekniku jilgħabu wkoll Delphi Aes u Pbkdf2 Delphi rwol importanti, meta l-integrazzjonijiet, il-flussi tad-data u l-iżvilupp sussegwenti jridu jaħdmu b’mod koerenti u nadif.
Tiddiskuti proġett jew pjan ta‘ modernizzazzjoni ma‘ Net-Base.
Pass li jmiss
Meta suġġett jissarraf f’proġett reali, l-arkitettura, is-sistema eżistenti u l-operazzjoni għandhom jiġu kkunsidrati flimkien kmien.
Wir unterstuetzen nicht nur bei Einzelfragen, sondern auch dann, wenn aus Source-Schnipseln, Legacy-Themen oder Portalideen ein belastbares Unternehmensprojekt werden soll.
- L-istat attwali, l-istat tal-mira u r-riskji tekniċi jiġu vvalutati flimkien.
- REST, aċċess għad-dejta, portali u Rollout mhux se jiġu posposti bħala konsegwenzi tardivi.
- Tara kmieni liema triq hija sostenibbli kemm mill‑punt ta’ vista ekonomiku kif ukoll mill‑punt ta’ vista operattiv.