| I'll take a stab, but I'm keeping it fuzzy, not because I haven't worked the attack out at a low level but because I don't want you to know that I haven't worked the attack out at a low level. Some of this will be wrong. We're in the bizarre circumstance of being able to get our target to use a partially corrupted version of their own secret RSA key to decrypt a message of our choosing (this never happens! Only with Mega!). We're looking for q, one of two factors of our private key. We set m, the plaintext message we get to choose, to the middle of the range of possible q's. Remember, q is smaller than m; we've got a 2048 bit RSA key, and so q is 1024 bits; the client is effectively going to pad it out, and then blindly extract the 2nd though 45th bytes from it. What we're going to do resembles a fault attack (we're sort of simulating one by scrambling qInv). One of two things will happen: * If m < q, the message is going to miss our faulted qInv (it won't wrap the modulus for the q part of the CRT calculation, by definition, which cancels out the qInv part of the calculation) and thus decrypts properly. After padding and extraction, the client will pull 0's out of the decrypted message --- remember, q is much smaller than the whole message space of m, and remember, the client doesn't bother to check the padding! the number of things that went wrong here is bananas! --- and post it back. * If m >= q, our qInv fucks up the decryption; we decrypt (I assume) random gibberish, all the way through the space of m. We extract 43 bytes of the random gibberish, posting back a non-zero value. It's described in detail in III.B.2 of https://mega-awry.io/pdf/mega-malleable-encryption-goes-awry... |
> We're in the bizarre circumstance of being able to get our target to use a partially corrupted version of their own secret RSA key to decrypt a message of our choosing (this never happens! Only with Mega!).
We overwrite the ciphertext of q^{-1} so that is fully corrupted (or at least, because it is ECB mode, a block of it is corrupted), right? By partially corrupted, do you mean "p and q are fine, but q^{-1} is not what it is supposed to be"? Does it matter how we corrupt q^{-1}? Is it just a bit flip in a single block? Do we have to corrupt it the same every time to make a new guess for q?
> We set m, the plaintext message we get to choose, to the middle of the range of possible q's. Remember, q is smaller than m;
I'm not quite following this part. To clarify, are you saying (roughly, I know RSA has some checks that q is not outrageously small) q lies in the interval [0, 2^1024] and we, on our first guess, set m = (2^1024 - 0)/2 = 2^1023? Then the adversary encrypts this guess m using the public key N from the client. m, when decrypted by the client at this point, could clearly be either larger or smaller than q, right? Our choice for m is literally in the middle. But the client also pads the resulting m, so it will certainly be larger than q? But to clarify, q is only (almost certainly) smaller than m because of the padding that the client adds?
> * If m < q, the message is going to miss our faulted qInv
I'm confused again, sorry. Is this m without the padding, right? Why, if m < q, does the RSA calculation not wrap around the modulus? I'm a bit confused how it pulls out only 0s, but this is probably related to my confusion at the last paragraph. Is it that it's that only 0s, but rather a small number followed by a ton of padding of 0s?
> * If m >= q, our qInv fucks up the decryption; we decrypt (I assume) random gibberish
The whole reason we fault qInv is so this case screws up while the other doesn't, right? And so it doesn't really matter how we fault qInv each time? This case faults because the calculation wraps around the modulus? It would be good to see the actual calculation and why this is which I think is my main struggle right now.