Reputation: 6399
I have a piece of code in C# that encodes string and returns URL safe string (that is decoded later on)
string stringToEncrypt = "Winter is coming";
byte[] bytes = new byte[stringToEncrypt.Length * sizeof(char)];
System.Buffer.BlockCopy(stringToEncrypt.ToCharArray(), 0, bytes, 0, bytes.Length);
System.Web.HttpServerUtility.UrlTokenEncode(bytes).Dump();
Dump
is from LinqPad. I use it to test bits and pieces of C# quickly
This Returns VwBpAG4AdABlAHIAIABpAHMAIABjAG8AbQBpAG4AZwA1
when Executed.
I am trying to do the same thing from a clojure service now. Using the encode
library and going by this answer When I have
(String. (b64/encode (.getBytes email)) "UTF-8")
I get V2ludGVyIGlzIGNvbWluZw==
, which is
Tried looking at the MSDN documentation for UrlTokenEncode()
but it doesn't have much detail on the implementation of it to see what's going on under the hood.
Can I generate the equivalent string in clojure?
Upvotes: 4
Views: 970
Reputation: 3527
If you are using Java 8, the new Base64
class, along with a little modular arithmetic for the pad count does it:
(defn url-token-encode [bytes]
(let [byte-count (count bytes)]
(if (pos? byte-count)
(str (.. (java.util.Base64/getUrlEncoder) (withoutPadding) (encodeToString bytes))
(mod (- byte-count) 3))
"")))
(defn encode [s]
(url-token-encode (.getBytes s "UTF-16LE")))
(encode "Winter is coming")
;=>"VwBpAG4AdABlAHIAIABpAHMAIABjAG8AbQBpAG4AZwA1"
Upvotes: 2
Reputation: 11154
Thanks to Robert for pointing out the source for UrlTokenEncode
. It does the following:
=
with the number of padding characters (1
or 2
)+
with -
and /
with _
The other essential detail is that the C# example encodes the UTF-16 representation of the string (2 bytes per character). To illustrate, here is an example from the Go playground: http://play.golang.org/p/UlKMa7_OwV
This code produces the expected output for your test input:
(ns blah.core
(:require [clojure.data.codec.base64 :as b64])
(:require [clojure.string :as string])
(:gen-class))
(defn encode [original]
(let [bytes_in (.getBytes original "UTF-16LE")
bytes_enc (b64/encode bytes_in)
bytes_len (alength bytes_enc)
pad_count (b64/pad-length bytes_enc 0 bytes_len)
enc_string (String. bytes_enc 0 (- bytes_len pad_count) "UTF-8")
enc_string (string/replace enc_string \+ \-)
enc_string (string/replace enc_string \/ \_)]
(str enc_string pad_count)))
(defn -main
[& args]
(let [message "Winter is coming"]
(println message)
(println (encode message))))
The decode function is left as an exercise for the reader.
Upvotes: 3