Signing bug

Simple explanation

The signing (also known as Trucha) bug was a bug present in earlier IOS versions that allowed the digital signatures (which show that Nintendo had approved the content in question) of software to be easily faked, which allowed the installation of software that Nintendo hadn't approved. Shortly after its widespread use appeared, it was patched; first in IOS37. This exploit was used in the original version of the Homebrew Channel installer, and is still used in many applications.

Detailed explanation

Here is a simplified pseudocode implementation that shows the hash-comparison bug present in some versions of IOS:

The bug here is that payload_hash is a binary SHA1 hash (not an ASCII string), and therefore may contain a NULL byte ('\0').
To quote from the first google hit for strncmp:

Compares up to num characters of the C string str1 to those of the C string str2.
This function starts comparing the first character of each string. If they are equal to each other, it continues with the following pairs until the characters differ, until a terminating null-character is reached, or until num characters match in both strings, whichever happens first.

This last part means that when strncmp finds a NULL byte it stops comparing, even if there is more data after the NULL.

This reduces the effective length of the hash to the number of bytes before the NULL byte, and the difficulty of finding a hash collision is reduced from 28*SHA1_LENGTH to 28*(bytes up to the NULL). That is a big change if the NULL is early in the hash. If the NULL byte is at 4th byte, that means that there is a one in 28*4 chance that the hash matches (three data bytes and the final NULL, which must also match). This is an average of 4 294 967 296 attempts to produce a valid partial collision, which can be computed in under 30 minutes on a modern computer that can compute a few million hashes per second. Nintendo signatures that have these properties certainly exist.

Furthermore, since we can brute force both the SHA-1 hash of the content (by changing unused bytes) and the SHA-1 that results after decrypting (by changing the signature randomly, which is possible because Nintendo doesn't check the fixed padding in the decrypted RSA signature), all we have to do is brute force both until the first byte of the hash is zero. This only requires about 256 RSA decryptions and 256 SHA-1 sums, both of which can be computed in a fraction of a second.

The process can be simplified further by taking advantage of the mathematical properties of RSA. Given the signature m, and the public key (e, n), the decrypted signature is calculated as me mod n. A zero signature (m = 0) always results in a zero result, regardless of the values of e and n (that is, regardless of the certificate that is used to check the signature). All we have to do is zero out the signature and get a guaranteed result of all zeroes. This reduces the time needed to build a fake signature to an average of 256 short SHA-1 sums, which can be done in mere milliseconds. The actual number of attempts required can vary (and could theoretically be infinite), since SHA-1 behaves like a random number generator. This is why having to try a couple thousand times isn't uncommon, and why changing a single byte when bruteforcing is not sufficient.