Hashing with ironclad and flexi-streams
Asked Answered
F

1

10

I'm trying to hash some strings in a Common Lisp app I'm working on. The sd-sha1 package seems to be unsupported, and has been for some time judging by the CLiki page, which suggests using Ironclad instead. Fair enough,

=> (require 'ironclad)
NIL

Ironclad doesn't do string digests though; this is stated on its project page as an intentional design choice, what I'm supposed to do is convert my string to a byte-string and hash that. In other words

=> (ironclad:digest-sequence
      :sha1 (flexi-streams:string-to-octets "Hello there"))
#(114 108 118 85 62 26 63 222 162 145 52 243 110 106 242 234 5 236 92 206)

Ok, now the thing is that the point of this entire excercise is to get out a sha1-hashed string of the original string input, which means that I really want to convert the above back into string format. But,

=> (flexi-streams:octets-to-string 
     (ironclad:digest-sequence
        :sha1 (flexi-streams:string-to-octets "Hello there"))
     :external-format :utf-8)

This sequence can't be decoded using UTF-8 as it is too short.  
1 octet missing at then end.
     [Condition of type FLEXI-STREAMS:EXTERNAL-FORMAT-ENCODING-ERROR]

Restarts:
     0: [ABORT] Exit debugger, returning to top level.

The other option is to let flexi-streams infer the correct encoding.

=> (flexi-streams:octets-to-string
      (ironclad:digest-sequence
        :sha1 (flexi-streams:string-to-octets "Hello there")))
"rlvU>?Þ¢4ónjòêì\\Î"

Which sort of works, but I get the feeling that the result isn't supposed to contain control characters. According to flexi-streams, the default encoding is :latin, so I'm really not sure what to do at this stage.

What am I doing wrong? How do I get a string-representation of a SHA1-digested string in Common Lisp?

In case it matters, I'm running SBCL (the version out of apt-get, which is 1.0.29 I believe) through Emacs+SLIME.

Farther answered 10/10, 2010 at 14:19 Comment(0)
T
10

The octets you get from ironclad:digest-sequence are the SHA1 digest. You want a string representing a hexadecimal encoding of those bytes. Ironclad has a function to do that built-in: ironclad:byte-array-to-hex-string.

Terreverte answered 10/10, 2010 at 15:11 Comment(2)
Man, I've got to learn to read the complete docs before I ask about stuff. The Ironclad page lists the utility functions above. In other words, what I should have done was (ironclad:byte-array-to-hex-string (ironclad:digest-sequence :sha1 (ironclad:ascii-string-to-byte-array "Hello there"))) instead of bringing flexi-streams into this (though it would probably still be useful if I wasn't dealing with plain ascii strings). Thanks for pointing me in the right direction.Farther
Babel is also helpful for encoding non-ASCII strings to octet vectors.Terreverte

© 2022 - 2024 — McMap. All rights reserved.