If only the passwords (& not usernames or URLs or whatnot) are encrypted & no checksum or other verification is used, then entering the wrong master password could very well cause it to decrypt to completely useless but structurally valid passwords.
Of course, care would need to be taken to ensure the result is always valid...probably have a "password format" field that indicates what format the password is allowed to have (at least 1 of each of these types of character, at least 8 characters & no more than 16, that sort of thing), then do a "base conversion" of sorts so that valid passwords map to consecutive integers. The only remaining problem is if the format does not pack nicely into an integral number of bits, since then you might get out-of-range values with certain choices for the master password, but this can either be ignored (you rule some fraction of the master passwords out but still have to do a lot of searching) or handled by randomly (not necessarily uniformly...) choosing any value that is equivalent modulo the number of passwords allowed by the format.
I found that I can write much more efficient QBASIC code after learning & using Haskell. (^_^)
Now, if only graphics in Haskell were as easy as QBASIC. (Unless one of the million or so mutually-incompatible graphics-related packages on Hackage does everything I want but I missed it.)
Hmm. I suppose that can be true in an iterative setting (needing to store some data from every iteration), & that the only hope of avoiding that is rewriting the whole loop to be fully reversible so it does not consume space every iteration. (It cannot take more space than linear in the run time, at any rate.) I was imagining recursive functions with stack allocation for each, but I should know better since I use tail recursion all the time. So I guess I was only right about iteration- & tail-recursion-free code.
On the other hand, it should not require more than an exponential increase (hah, only exponential) in space for any terminating & non-interactive computation, since with that you could store every possible state of the original irreversible machine. For non-terminating computation, it is at worst linear in the runtime, as aforementioned.
B=A XOR B (leaving A unchanged) is a reversible operation & is what I meant. More generally, B=f(A) XOR B is reversible (in fact, self-inverse), where f can be any (even irreversible) function.
Sure, you need to save the input to otherwise-irreversible steps, but the point is that you can erase a known value, & since there was some method to compute the intermediate values in the first place, they can be removed from memory in reverse order. (This is a known method—I did not come up with it.) Then you only need enough memory to store the maximum intermediate storage size (which is not all intermediate results unless the computation is a single list of originally-irreversible steps with no subroutines & such), & you can eventually end up with just the answer (& any inputs) remaining in memory.