Except generating a random salt and the proper hash format to provide as input to crypt() is surprisingly difficult, especially in a cross-platform way. I recently replaced my custom crypt wrapper with the userland implementation of these functions, and in the process I discovered my custom wrapper had some rather non-obvious bugs.