If I hashed the password and sent that as an hpassword it worked fine, but taking that hash, adding it to the challenge, hashing _that_ and sending it wasn't working. Which was odd, because all of the sample code I was seeing did that without a problem.
And then I nicked some working code from ljArchive and compared my results with its results and discovered that LJ cares about the case of the hash when it's checking the auth_response. It _must_ be in lower case - which was why my code was failing, as I was using the .Net method FormsAuthentication.HashPasswordForStori
If someone could update http://www.livejournal.com/doc/server/ljp.csp.auth.challresp.html to mention that the hex digest has to be in lower case it will undoubtedly save someone else a few hours of hair-pulling...