Well, let's begin with the fact it's worse. You argue it's not "much" worse, but it is clearly worse not the same. Under 'pass' all passwords conforming to chosen rules are equally likely, under your approach some are twice as likely as others.
But then the other characteristic is simplicity. Using 'tr -cd' is, by my counting, five characters. How big is your best implementation of this supposedly "even simpler" but worse solution?
> Under 'pass' all passwords conforming to chosen rules are equally likely, under your approach some are twice as likely as others.
But they're passwords. At most half of the passwords will have different probability than the rest which means that you're still left with a staggering number of un-brute-forceable passwords. Two to the power of ninety nine is practically indistinguishable from two to the power of one hundred.
By the way, if you're still obsessed about completely equal probabilities here, you can just drop the whole sequence of bits if it's larger than the number of alternatives when interpreted as a binary number and fetch a new one. It seems to me that the expected value of number of bits consumed for such a process won't exceed twice the number of bits that are technically necessary (because the probabilities of individual numbers of attempts are a geometric sequence with a factor of at most 0.5 summing to exactly 1, which would have an expected value of 2), which is around 12.5 bits per character. With a filtration like tr -dc "0-z" mentioned below you'll consume roughly 27.3 bits per character on average. So "better" is a subjective term here; one solution may be simpler to write in a shell command line, another consumes much less entropy. If you're deciding what to do, you need to weigh your criteria properly if you have more of them. You may very well have different criteria than I do; that happens.
> Using 'tr -cd' is, by my counting, five characters
I probably wouldn't use this in the first place because it requires a subprocess and a binary that I might not have on some computers. So by my counting this could be hundreds of kilobytes of extra code. Division with a remainder is most likely something you already have in your standard library regardless of whether you use it or not.
To the extent that it could mean something to "consume" entropy from the random device they're both outputting the same size of password and so they're consuming roughly the same amount of entropy. Assuming the random device works as intended this would be a distinction that makes no difference anyway.
> a binary that I might not have on some computers
A binary that's included in the Linux Standard Base. Which computers don't you have it on?
> this could be hundreds of kilobytes of extra code
More like a few dozen kilobytes, although of course on tiny Linux systems it's bundled into something like busybox so much less.
> Division with a remainder is most likely something you already have in your standard library regardless of whether you use it or not.
The shell, which is what pass is written for, does have division with a remainder, but it cannot do this operation on 96-bit integers. So now you've added another constraint "rewrite this software in a language which has 96-bit integers, or more if longer passwords are allowed" [Hint: Longer passwords are very much allowed in pass]
So far what you've achieved is to show that this is trickier than you thought, yet produces worse results. Again, this is why I like what Jason did here.
> A binary that's included in the Linux Standard Base. Which computers don't you have it on?
I'm using some Windows computers. But for example I can use (and often do) a dumped SBCL binary on them just fine, even on those where I can't install anything.
Well, let's begin with the fact it's worse. You argue it's not "much" worse, but it is clearly worse not the same. Under 'pass' all passwords conforming to chosen rules are equally likely, under your approach some are twice as likely as others.
But then the other characteristic is simplicity. Using 'tr -cd' is, by my counting, five characters. How big is your best implementation of this supposedly "even simpler" but worse solution?