From a64166915078b4db6356bd64269f039f6a920dc3 Mon Sep 17 00:00:00 2001 From: r-zakarya <82443831+r-zakarya@users.noreply.github.com> Date: Sat, 15 Aug 2026 00:06:30 +0100 Subject: [PATCH] fix(android): keep the ETag only when the decryption that followed succeeded The harness stored the ETag on download, so a first attempt with no password left a valid tag behind: the next call answered 304 and there was nothing to decrypt, precisely when the right password had just been typed. Sending If-None-Match without holding the matching plaintext trades a download for having no data - the real client needs the same rule, the tag belonging to the cached vault. Also drops an em dash from an exception message: Delphi reads a BOM-less source as ANSI and it reached the device as mojibake. --- android-client/PMA.Crypto.pas | 4 +++- mainApk.pas | 15 +++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/android-client/PMA.Crypto.pas b/android-client/PMA.Crypto.pas index a952f6a..25320a2 100644 --- a/android-client/PMA.Crypto.pas +++ b/android-client/PMA.Crypto.pas @@ -330,7 +330,9 @@ begin // AEADBadTagException surfaces here: wrong password, or altered bytes. // Both are indistinguishable by design — that is what authentication means. on E: Exception do - raise EPMACrypto.Create('Decryption failed — wrong password or corrupt file'); + // Message en pur ASCII : un tiret cadratin dans une source lue en ANSI + // par Delphi ressort en mojibake sur l'appareil. + raise EPMACrypto.Create('Decryption failed - wrong password or corrupt file'); end; end; {$ELSE} diff --git a/mainApk.pas b/mainApk.pas index 06825ab..5967e6d 100644 --- a/mainApk.pas +++ b/mainApk.pas @@ -46,7 +46,11 @@ type FBtn: TButton; FBtnFetch: TButton; FUrl, FToken, FPwd: TEdit; - FETag: string; // conserve entre deux appuis : c'est ce qui permet le 304 + // L'ETag n'est conserve QUE si le dechiffrement qui a suivi a reussi : + // envoyer If-None-Match sans detenir le clair correspondant fait + // economiser un telechargement pour se retrouver sans donnees. Le vrai + // client aura la meme regle, l'ETag etant lie au coffre en cache. + FETag: string; procedure RunSelfTest(Sender: TObject); procedure RunFetch(Sender: TObject); procedure Log(const AMsg: string); @@ -190,17 +194,16 @@ begin end; Log(' recu ' + Length(LRes.Container).ToString + ' octets'); - if LRes.ETag <> '' then - begin - FETag := LRes.ETag; - Log(' ETag conserve : ' + FETag); - end; Log(''); Log('Dechiffrement...'); LSw := TStopwatch.StartNew; + // Volontairement AVANT de retenir l'ETag : un echec ici doit laisser + // FETag vide pour que le prochain essai retelecharge. LPlain := DecryptContainer(LRes.Container, LPwd); LSw.Stop; + FETag := LRes.ETag; + if FETag <> '' then Log(' ETag retenu : ' + FETag); Log(' ' + LSw.ElapsedMilliseconds.ToString + ' ms pour ' + Length(LPlain).ToString + ' caracteres');