As you note, there is not generally an issue with producing incorrect results that are specific to cryptography. Results will either be correct or not. Wrong results are bad for both cryptographic and non-cryptographic applications. Since they're used more, non-cryptographic libraries are probably more likely to produce correct result.
This answer already told you about side channel timing attacks. This is a serious concern, but I won't speak more to it. It also mentions but does not explore the possibility of data being left on the stack or heap.
If an attacker can make a program do a core dump and there are variables in it like $original_password
. Then obviously that can leak the original password. For this reason, cryptography often overwrites these values when it's done using them. So that a memory dump will just get garbage or null bytes.
Now, a math library is unlikely to have something called $original_password
in it. But it might have a function called hash
that takes a byte array as an input. And that byte array may live on the stack or heap. And a cryptography library that uses the math library might have a call hash(to_byte_array($original_password))
. From which you should be able to see that the $input
byte array to hash
would contain a deterministic transformation of the $original_password
. So an attacker who knows that the only time that the program calls hash
is to hash the original password just needs to reverse the transformation. Now the attacker has the original password.
If the attacker can cross reference the password with the username, then that pair is compromised.
Even if the hash
function is called multiple times, that just makes things harder, not impossible. Now there are (e.g.) fifteen instances of $input
on the stack. Transform all of them into strings. Now you have fifteen candidates for the password.
This kind of stuff is what people mean when they talk about writing specifically for cryptography. It's not that the mathematical calculations are better in any way. Actually, because of timing attacks, they are in some ways worse. Cryptography deliberately writes its algorithms to be constant time. And constant time in this application means that the algorithms always have to be as slow as the slowest possible path. So cryptographic math libraries are deliberately slower and more wasteful of memory than non-cryptographic libraries.
They also do things like pass in the original data without transforming it first. So the cryptographic hash function might take a string ($original_password
) rather than an array of integers.
Cryptographic libraries also tend not to be general purpose. First, because why would you use a slow cryptographic library when you could use a faster non-cryptographic library? Second, because their signatures are different. For a math library, you would often pass the input itself on the stack. Because that's easier. But for a cryptographic library, you would rather pass a reference. Because you don't want the password to appear more than once in memory.
In fact, as soon as possible, you want it to appear zero times. So overwrite the original password input with its hash. Rather than returning the hash from the function, modify the original variable. That might be counterproductive if you are taking the hash for serialization or comparison purposes (general purpose uses of a hashing function). But for the purpose of cryptography, it makes sense. You want both the original password and the hash to spend no time on the stack and as little time in memory as possible. So replace the original password with the hash. Eventually overwrite the hash with garbage. Never make copies.
Also consider the handling of randomness. Is the random generator's seed a security hole? In a non-cryptographic library, no. Because you don't particularly care if the crashed program reveals what the seed had been. It's crashed. You won't be continuing it. But for cryptographic purposes, you care what the historical choices were. An attacker who knows the seed, has a much more limited set of possibilities for what the random choices were. The attacker can try all the permutations of that set and still save time relative to trying all possibilities.