Since Naamari belongs to cryptographic software, it is a subject to attacks. Perhaps the adversary in need of such attacks is yourself. Here we list the ways you could break it, — in the past... and presumably (to our shame and your glory) at present.
To recover the key(s) and be able to decipher the files put on a cloud by Naamari is the «royal», though not unique at all, attack (or more precisely, goal of the attack). Partial (probable) decryption, forgery, metadata analysis, and so forth sometimes yield not less fun consequences. The means are quite multifarious too: known-ciphertext attacks, chosen-plaintext attacks, adaptive chosen-ciphertext attacks, side channel attacks, etc. Those we've considered interesting and instructive are presented on this page.
While we've attempted to list them in the «criticality» order, the resultant sequence is prejudiced. Maybe the most important ones come near the end of the list. Eventually, it is incomplete, and it'll never be.
Notice that in these descriptions, you are considered to be an adversary/attacker, rather than Naamari's user. See the game through the eyes of the other side... no, it is your side, as it ever was.
Each description is accompanied by its own «metadata»: the importance (from our point of view), the versions affected, the external links to thorough explanations of similar attacks on systems alike, the correction status, and the related tricks listed ad locum are among these.
You have to read Specs in order to apprehend the context.
Proceeding to the salt...
In the versions prior to 1.2.0, the encryption scheme didn't include the usage of KEY-H, and two 16-byte blocks with hash, appended to padded file data (n blocks), were encrypted with per-block-key calculated for k = n+1 and k = n+2.
The attack allows file forgery for this scheme. To perform it, you — the adversary — provides victim with the file of the following structure: A || P || h(A || P) || B, where A and B are some (non-zero) byte strings and P is a padding string, making A || P length a multiple of 16 — m 16-byte blocks for some m. You can calculate h(A || P) because you know A, and h() isn't keyed.
She encrypts that file with Naamari and puts on the remote storage. According to the scheme, it turns to A || P || h(A || P) || B || P' || h (A || P || h(A || P) || B || P'), and then each block of number k is AES-encrypted with per-block-key = h(KEY-B || salt || k). Notice that for two blocks containing h(A || P), k takes on the values m+1 and m+2.
Now you, who has a read/write access to the same storage (administrator, for instance) truncate the encrypted file, — by removing all blocks after the (m+2)th. When the victim pulls it from the storage to the drive and decrypts, Naamari doesn't reveal the truncation, since the remainder is «correct». She gets A || P || h(A || P) as the intermediate, and A as the resultant content. P || h(A || P) || B is lost. What's more important is that she doesn't detect the loss, especially if she cannot compare the decrypted data to the original file content.
Fix. What have we changed to prevent this kind of attacks, and does it really prevent them?
First, we made integrity hash keyed with KEY-H. This alone isn't sufficient; why? Try to realize on your own before reading further.
Even if you retrieve certain information from intermediate content of few en/decrypted file(s), this shouldn't enable you to decrypt or forge other files. So, even if integrity hash for A || P is h (KEY-H || A || P), we have to consider you know it. Perhaps you were able to intercept the victim's communications with other parties where she included exactly h(KEY-H || A || P). Or perhaps she willingly published it.
One way or another, you give her A || P || h(KEY-H || A || P) || B, Naamari turns it into encrypted A || P || h (KEY-H || A || P) || B || P' || h (KEY-H || A || P || h (KEY-H || A || P) || B || P'), uploads to the remote storage, where you truncate it to encrypted A || P || h (KEY-H || A || P), and she gets A once again — without any signal from Naamari.
To make it more realistic, consider her uploading two files: the original content of the first one is A, while the original content of the second one is A || P || h(KEY-H || A || P) || B. The second one is quite possible (in the materials concerning this attack, for example). Now, you only need to know what encrypted files correspond to these, and the length of A, to truncate the second one, — after that, though different in encrypted form, they'll be decrypted to the same byte string A. You don't need neither KEY-H, nor h(KEY-H || A || P).
In general, KEY-H in conjunction with h()'s anti-length-extension-attack structure, prevents you from calculating the integrity hash of new strings. However, truncation is still possible.
So there's another change: last two blocks are en/decrypted with k = –(n+1) and k = –(n+2) (to be more precise, 264–(n+i)). Any truncation/extension forces n to take on a different value n', and the last two blocks of truncated/extended file will be decrypted with k = –(n'+1) and k = –(n'+2).
Assuming the n' blocks prior to the hash pair contain, in decrypted form, some A || P, you have to append h(KEY-H || A || P) — encrypted with two per-block-keys for k = –(n'+1) and k = –(n'+2); where can you find these (with a considerable probability)?
Not in the other encrypted files, because different random salts were used in calculation of their per-block-keys.
What about this very file you're tampering with? All its blocks prior to the last two ones were encrypted with positive k, no one coincides with any of two you need (you hardly make victim to download file of more than 263 bytes these days, if you rely on signed int overflow). Looks like the last two blocks are the only material you have.
If n' = n, the decryption won't transform them into garbage (again, due to unique salt) only if they come in the same order as in the unmodified file. But then they have to be a hash of exactly the data from the unmodified file before encryption (until you defeat the preimage resistance combined with encryption).
If n' < n, the decryption procedure may restore something correctly only when n' = n - 1, implying –(n'+2) = –(n+1), — that will be a first half of the hash from the unmodified file, and you have to make it the very last block of the fake on the storage, which replaces the file uploaded by Naamari. However, since one block is gone, the encrypted hash will be different, and even if it happens to be the same, the order of the halves is reversed.
If n' > n, similarly, only when n' = n+1 implies –(n'+1) = –(n+2) the second half of the original hash is restored by decryption. But one block is inserted, data hash changes, and the order of the halves is reversed.
Copyright © 2014–2021 Sunkware
〈VisitIPs is 👁watching👁 you〉