mirleft / ocaml-nocrypto

OCaml cryptographic library
ISC License
111 stars 53 forks source link

base64: \n #78

Open qlai opened 9 years ago

qlai commented 9 years ago

I am trying to match encoding and decoding responses to that of openssl on this matter and it seems to throw Invalid_Argument when decoding. The openssl cmd tool returns a new line after every 64 characters and I am just wondering if there is a way to get around this? (or maybe I missed something?)

Thank you!

cfcs commented 7 years ago

Unable to reproduce the Invalid_argument exception. Perhaps the interface has been changed to return a Cstruct.t option since?

The Nocrypto implementation is equivalent to the encoding described in RFC 3548 (NOTE: not the "URL and Filename Safe Alphabet" flavor).

RFC 3548 specifically forbids extraneous characters (such as newlines) and provides arguments against ignoring them.

I agree that better documentation of these features in the interface would be nice to have - the current interface leaves a lot to speculation:

(** Base64 conversion.

    It is here only temporary, until we find it a proper home. *)
module Base64 : sig
  val encode : Cstruct.t -> Cstruct.t
  val decode : Cstruct.t -> Cstruct.t option
  val is_base64_char : char -> bool
end

It does however provide the is_base64_char function, which makes it easy to filter illegal characters (such as newlines) from your input data. An example of how to do this with a Cstruct (although converting to Astring and back again would probably be easier):

let src = Cstruct.of_string "a bcd\ne";;
(* val src : Cstruct.t = {Cstruct.buffer = <abstr>; off = 0; len = 7} *)

let i = Cstruct.iter
    (*chunks of 1:*)
    (fun _ -> Some 1)
    (* convert the first char of each 1-byte cstruct to char and check if it's allowed: *)
    (fun cstr -> cstr, Cstruct.get_char cstr 0 |> Nocrypto.Base64.is_base64_char) src;;
(* val i : (Cstruct.t * bool) Cstruct.iter = <fun> *)

let filtered = Cstruct.fold
    (fun acc ->
     function (c,true) -> Cstruct.append acc c | _ -> acc)
    i Cstruct.(create 0);;
(* val filtered : Cstruct.t = {Cstruct.buffer = <abstr>; off = 0; len = 5} *)

let final = Cstruct.to_string filtered;;
(* val final : string = "abcde" *)