For another cut at a hashing interface, you may want to look at one I made specifically for passwords. You make a password hasher by passing in algorithm, salt length, and iterations, and you get back a map containing a pair of complementary functions: one that digests, the other that verifies. https://gist.github.com/mchampine/868342
Example: Digester/verifier pair using SHA-256 with 16 bytes salt and 10k iterations (def strongPWHasher (pwfuncs "SHA-256" 16 10000)) ; make the digester/verifier pair (def hashed-pw ((strongPWHasher :digest) "mysecret")) ; hash the password ((strongPWHasher :verify) "mysecret" hashed-pw) ; verify it M. On Monday, March 4, 2013 6:46:07 PM UTC-5, FrankS wrote: > > Larry, > > What I can advise though, is to look at my library code and it may give > you different perspectives. > > Furthermore, copy, borrow, and steal what you like and make it your own. > > -FS. > > > On Mar 4, 2013, at 3:17 PM, Frank Siebenlist > <frank.si...@gmail.com<javascript:>> > wrote: > > > If your code is for production… do not use my code! > > > > It's pretty much written over the weekend and it's "security code", > meaning that it deserves much more scrutiny than "ordinary" code. > > > > As mentioned in the readme, it's more an "educational exercise", > although it was good to see you struggling as it validated my concerns > about the java library's approach ;-) > > > > Don't even know if I'm willing to maintain it either… > > > > Sorry for the bad news - I was just trying to sollicit feedback about > alternative interfaces for the secure hashing. > > > > Regards, FrankS. > > > > > > On Mar 4, 2013, at 3:09 PM, larry google groups > > <lawrenc...@gmail.com<javascript:>> > wrote: > > > >> Frank, > >> > >> Any idea when you might release your code in a stable form? I am using > >> this code at work so I am nervous about using code that is still > >> marked SNAPSHOT. Lein reminds me not to use a SNAPSHOT: > >> > >> Could not find metadata org.clojars.franks42:clj.security.message- > >> digest:0.1.0-SNAPSHOT/maven-metadata.xml in central (http:// > >> repo1.maven.org/maven2) > >> Could not find metadata org.clojars.franks42:clj.security.message- > >> digest:0.1.0-SNAPSHOT/maven-metadata.xml in central-proxy (https:// > >> repository.sonatype.org/content/repositories/centralm1/) > >> Retrieving org/clojars/franks42/clj.security.message-digest/0.1.0- > >> SNAPSHOT/maven-metadata.xml (1k) > >> from https://clojars.org/repo/ > >> Could not find artifact org.clojars.franks42:clj.security.message- > >> digest:pom:0.1.0-20130304.220822-1 in central (http://repo1.maven.org/ > >> maven2) > >> Retrieving org/clojars/franks42/clj.security.message-digest/0.1.0- > >> SNAPSHOT/clj.security.message-digest-0.1.0-20130304.220822-1.pom (3k) > >> from https://clojars.org/repo/ > >> Retrieving org/clojure/clojure/1.5.0/clojure-1.5.0.pom (6k) > >> from http://repo1.maven.org/maven2/ > >> Retrieving org/clojars/franks42/clj.security.message-digest/0.1.0- > >> SNAPSHOT/clj.security.message-digest-0.1.0-20130304.220822-1.jar (6k) > >> from https://clojars.org/repo/ > >> Compiling 1 source files to /Users/lkrubner/projects/multi-platform- > >> data-visualization/mpdv-clojure/target/classes > >> Release versions may not depend upon snapshots. > >> Freeze snapshots to dated versions or set the > >> LEIN_SNAPSHOTS_IN_RELEASE environment variable to override. > >> > >> > >> > >> > >> > >> > >> On Mar 4, 4:55 pm, Frank Siebenlist <frank.siebenl...@gmail.com> > >> wrote: > >>> Glad Larry has working code now... > >>> > >>> As I mentioned before in this thread, I'm working on this functional > interface for the message-digesting/secure-hashing, and this whole > discussion reads like a use case for the "why?" ;-) > >>> > >>> It "proofs" to me that there may be real value in a more user-friendly > approach than the one offered by java.security.MessageDigest. > >>> > >>> So instead of writing: > >>> > >>> (let [... > >>> nonce-as-bytes (.getBytes nonce) > >>> created-as-bytes (.getBytes created) > >>> secret-as-bytes (.getBytes secret) > >>> digest (.digest > >>> (doto (java.security.MessageDigest/getInstance > "sha1") > >>> .reset > >>> (.update nonce-as-bytes) > >>> (.update created-as-bytes) > >>> (.update secret-as-bytes))) > >>> …] > >>> > >>> my library lets you write: > >>> > >>> (let [… > >>> digest (md/digest :sha-1 :utf-8 nonce created secret) > >>> …] > >>> > >>> and the advantages of the more functional approach is much more than > just saving a few lines of code! > >>> > >>> Although it still needs some more work, any feedback on > >>> "https://github.com/franks42/clj.security.message-digest" > >>> is much appreciated. > >>> > >>> Regards, FrankS. > >>> > >>> On Mar 4, 2013, at 1:31 PM, larry google groups < > lawrencecloj...@gmail.com> wrote: > >>> > >>> > >>> > >>> > >>> > >>> > >>> > >>>> I finally got this to work. Many thanks for all of the help that I > was > >>>> given here. > >>> > >>>> The final, winning combination was: > >>> > >>>> (let [username (get-in @um/interactions [:omniture-api- > >>>> credentials :username]) > >>>> secret (get-in @um/interactions [:omniture-api-credentials :shared- > >>>> secret]) > >>>> random-number (math/round (* (rand 1 ) 1000000)) > >>>> nonce (DigestUtils/md5Hex (str random-number)) > >>>> nonce-encoded-base64 (base64-encode (.getBytes nonce)) > >>>> date-formatter (new SimpleDateFormat "yyyy-MM-dd'T'HH:mm:ss") > >>>> created (.format date-formatter (new Date)) > >>>> nonce-as-bytes (.getBytes nonce) > >>>> created-as-bytes (.getBytes created) > >>>> secret-as-bytes (.getBytes secret) > >>>> digest (.digest > >>>> (doto (java.security.MessageDigest/getInstance > >>>> "sha1") > >>>> .reset > >>>> (.update nonce-as-bytes) > >>>> (.update created-as-bytes) > >>>> (.update secret-as-bytes))) > >>>> digest-base64 (base64-encode digest) > >>>> header (apply str " UsernameToken Username=\"" username "\" > >>>> PasswordDigest=\"" digest-base64 "\" Nonce=\"" nonce-encoded-base64 > >>>> "\" Created=\"" created "\"")] > >>>> header) > >>> > >>>> On Mar 4, 10:47 am, larry google groups <lawrencecloj...@gmail.com> > >>>> wrote: > >>>>> I have been having problems making an API call to Omniture. I have > >>>>> exchanged a dozen emails with a developer at Omniture, and he gave > me > >>>>> the impression that I was constructing my security codes > incorrectly. > >>>>> So now I am confronting my ignorance over how Java handles certain > >>>>> conversions. > >>> > >>>>> The developer at Omniture sent me this explanation in an email: > >>> > >>>>> " The security digest is formed from a sha1 hash of the following > >>>>> string concatenation: > >>>>> digest = sha1( Binary Nonce + Created Time String + API Secret Hex > >>>>> String (32 bytes) ) " > >>> > >>>>> I have been struggling with this for several days and I have tried > at > >>>>> least (literally) 200 variations on this bit of code: > >>> > >>>>> (let [username (get-in @um/interactions [:omniture-api- > >>>>> credentials :username]) > >>>>> secret (get-in @um/interactions [:omniture-api- > >>>>> credentials :shared-secret]) > >>>>> nonce (DigestUtils/md5Hex (random-string 32)) > >>>>> nonce-encoded-base64 (Base64/encodeBase64 (.getBytes nonce)) > >>>>> date-formatter (new SimpleDateFormat "yyyy-MM- > >>>>> dd'T'HH:mm:ss'Z'") > >>>>> created (.format date-formatter (new Date)) > >>>>> digest-as-string (apply str (.getBytes nonce) created secret) > >>>>> digest (.digest (java.security.MessageDigest/getInstance > "sha1") > >>>>> digest-as-string) > >>>>> header (apply str " UsernameToken Username=\"" username "\" > >>>>> PasswordDigest=\"" digest "\" Nonce=\"" nonce-encoded-base64 "\" > >>>>> Created=\"" created "\"")] > >>>>> header) > >>> > >>>>> This version gives me: > >>> > >>>>> "Exception in the main function: " #<ClassCastException > >>>>> java.lang.ClassCastException: java.lang.String cannot be cast to [B> > >>> > >>>>> For a long time I was using this for the last 3 lines: > >>> > >>>>> digest-as-string (apply str nonce created secret) > >>>>> digest (.digest (java.security.MessageDigest/getInstance > "sha1") > >>>>> (.getByes digest-as-string)) > >>>>> header (apply str " UsernameToken Username=\"" username "\" > >>>>> PasswordDigest=\"" digest "\" Nonce=\"" nonce-encoded-base64 "\" > >>>>> Created=\"" created "\"") > >>> > >>>>> Here I wrapped the whole digest-as-string in (.getBytes) so there > was > >>>>> no Java error, but this simply did not work when I pinged Omniture. > >>> > >>>>> In his email, he seems to suggest that the nonce should be binary > but > >>>>> that the date and the secret should be strings: > >>> > >>>>> digest = sha1( Binary Nonce + Created Time String + API Secret Hex > >>>>> String (32 bytes) ) " > >>> > >>>>> But, as I said, when I tried this I got the ClassCastException. > >>> > >>>>> No doubt some of my confusion is due to my ignorance of Java. > >>> > >>>>> I was able to take their sample PHP code and get that to > successfully > >>>>> ping their API, however, my company has an official policy of moving > >>>>> to the JVM, and of course I have a personal preference to work with > >>>>> Clojure. So I'd like to figure out how to get this to work in > Clojure. > >>>>> (Needless to say that Omniture doesn't offer sample code in > Clojure.) > >>> > >>>>> I have been using clj-http to make the actual POST calls to > Omniture. > >>>>> Since I am on a Mac, I have been using the excellent Charles network > >>>>> debugger (http://www.charlesproxy.com/) to watch the actual posts > >>>>> being made. Everything looks correct, except that in the end the > >>>>> requests fails, apparently because the digest is malformed. > >>> > >>>>> Any suggestions? > >>> > >>>> -- > >>>> -- > >>>> You received this message because you are subscribed to the Google > >>>> Groups "Clojure" group. > >>>> To post to this group, send email to > >>>> clo...@googlegroups.com<javascript:> > >>>> Note that posts from new members are moderated - please be patient > with your first post. > >>>> To unsubscribe from this group, send email to > >>>> clojure+u...@googlegroups.com <javascript:> > >>>> For more options, visit this group at > >>>> http://groups.google.com/group/clojure?hl=en > >>>> --- > >>>> You received this message because you are subscribed to the Google > Groups "Clojure" group. > >>>> To unsubscribe from this group and stop receiving emails from it, > send an email to clojure+u...@googlegroups.com <javascript:>. > >>>> For more options, visithttps://groups.google.com/groups/opt_out. > >> > >> -- > >> -- > >> You received this message because you are subscribed to the Google > >> Groups "Clojure" group. > >> To post to this group, send email to clo...@googlegroups.com<javascript:> > >> Note that posts from new members are moderated - please be patient with > your first post. > >> To unsubscribe from this group, send email to > >> clojure+u...@googlegroups.com <javascript:> > >> For more options, visit this group at > >> http://groups.google.com/group/clojure?hl=en > >> --- > >> You received this message because you are subscribed to the Google > Groups "Clojure" group. > >> To unsubscribe from this group and stop receiving emails from it, send > an email to clojure+u...@googlegroups.com <javascript:>. > >> For more options, visit https://groups.google.com/groups/opt_out. > >> > >> > > > > -- -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.