Skip to content

Commit 922126d

Browse files
author
Christopher Zimmermann
committed
Add md5 digest
1 parent ba594d6 commit 922126d

File tree

6 files changed

+245
-4
lines changed

6 files changed

+245
-4
lines changed

jbuild

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,6 @@
55
(public_name sha)
66
(synopsis "SHA-1 and SHA-2 family implementations")
77
(wrapped false)
8-
(modules (hash sha1 sha256 sha512))
8+
(modules (hash md5 sha1 sha256 sha512))
99
(c_flags (-Wall -O3 -funroll-loops)) ; Needs adapting for Windows
10-
(c_names (sha1c sha1_stubs sha256c sha256_stubs sha512c sha512_stubs))))
10+
(c_names (md5_stubs sha1c sha1_stubs sha256c sha256_stubs sha512c sha512_stubs))))

md5.h

+42
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**************************************************************************/
2+
/* */
3+
/* OCaml */
4+
/* */
5+
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
6+
/* */
7+
/* Copyright 1999 Institut National de Recherche en Informatique et */
8+
/* en Automatique. */
9+
/* */
10+
/* All rights reserved. This file is distributed under the terms of */
11+
/* the GNU Lesser General Public License version 2.1, with the */
12+
/* special exception on linking described in the file LICENSE. */
13+
/* */
14+
/**************************************************************************/
15+
16+
/* MD5 message digest */
17+
18+
#include <caml/config.h>
19+
20+
#ifndef CAML_MD5_H
21+
#define CAML_MD5_H
22+
23+
24+
CAMLextern value caml_md5_string (value str, value ofs, value len);
25+
CAMLextern value caml_md5_chan (value vchan, value len);
26+
CAMLextern void caml_md5_block(unsigned char digest[16],
27+
void * data, uintnat len);
28+
29+
struct MD5Context {
30+
uint32_t buf[4];
31+
uint32_t bits[2];
32+
unsigned char in[64];
33+
};
34+
35+
CAMLextern void caml_MD5Init (struct MD5Context *context);
36+
CAMLextern void caml_MD5Update (struct MD5Context *context, unsigned char *buf,
37+
uintnat len);
38+
CAMLextern void caml_MD5Final (unsigned char *digest, struct MD5Context *ctx);
39+
CAMLextern void caml_MD5Transform (uint32_t *buf, uint32_t *in);
40+
41+
42+
#endif /* CAML_MD5_H */

md5.ml

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
include Hash.Make (struct
2+
type ctx
3+
type t = string
4+
let digest_length = 128
5+
6+
external to_bin: t -> string = "%identity"
7+
external init: unit -> ctx = "stub_md5_init"
8+
external unsafe_update_substring: ctx -> string -> int -> int -> unit = "stub_md5_update"
9+
external update_buffer: ctx -> Hash.buf -> unit = "stub_md5_update_bigarray"
10+
external finalize: ctx -> t = "stub_md5_finalize"
11+
end)

md5.mli

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
(*
2+
* Copyright (C) 2006-2009 Vincent Hanquez <[email protected]>
3+
*
4+
* Permission to use, copy, modify, and distribute this software for any
5+
* purpose with or without fee is hereby granted, provided that the above
6+
* copyright notice and this permission notice appear in all copies.
7+
*
8+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15+
*
16+
*)
17+
18+
(** MD5 OCaml binding *)
19+
20+
(** context type - opaque *)
21+
type ctx
22+
23+
(** digest type - opaque *)
24+
type t
25+
26+
(** The zero digest *)
27+
val zero : t
28+
29+
(** Create a new context *)
30+
val init: unit -> ctx
31+
32+
(** Md5.unsafe_update_substring ctx s ofs len updates the context
33+
with the substring of s starting at character number ofs and
34+
containing len characters. Unsafe: No range checking! *)
35+
val unsafe_update_substring: ctx -> string -> int -> int -> unit
36+
37+
(** Md5.update_substring ctx s ofs len updates the context with the
38+
substring of s starting at character number ofs and containing len
39+
characters. *)
40+
val update_substring: ctx -> string -> int -> int -> unit
41+
42+
(** Md5.update_string ctx s updates the context with s. *)
43+
val update_string: ctx -> string -> unit
44+
45+
(** Md5.update_buffer ctx a updates the context with a.
46+
Runs parallel to other threads if any exist. *)
47+
val update_buffer: ctx -> Hash.buf -> unit
48+
49+
(** Finalize the context and return digest *)
50+
val finalize: ctx -> t
51+
52+
(** Return an copy of the context *)
53+
val copy : ctx -> ctx
54+
55+
(** Return the digest of the given string. *)
56+
val string : string -> t
57+
58+
(** Md5.substring s ofs len returns the digest of the substring of s starting
59+
at character number ofs and containing len characters. *)
60+
val substring : string -> int -> int -> t
61+
62+
(** Return the digest of the given buffer. *)
63+
val buffer : Hash.buf -> t
64+
65+
(** If len is nonnegative, Md5.channel ic len reads len characters from
66+
channel ic and returns their digest, or raises End_of_file if end-of-file is
67+
reached before len characters are read. If len is negative, Md5.channel ic
68+
len reads all characters from ic until end-of-file is reached and return their
69+
digest. *)
70+
val channel : in_channel -> int -> t
71+
72+
(** Return the digest of the file whose name is given. *)
73+
val file : string -> t
74+
75+
(** Return the digest of the file whose name is given using fast C function *)
76+
val file_fast : string -> t
77+
78+
(** Write a digest on the given output channel. *)
79+
val output : out_channel -> t -> unit
80+
81+
(** Read a digest from the given input channel. *)
82+
val input : in_channel -> t
83+
84+
(** return a binary representation of the given digest *)
85+
val to_bin : t -> string
86+
87+
(** return a printable hexadecimal representation of the given digest *)
88+
val to_hex : t -> string

md5_stubs.c

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* Copyright (c) 2017 Christopher Zimmermann <[email protected]>
3+
*
4+
* Permission to use, copy, modify, and distribute this software for any
5+
* purpose with or without fee is hereby granted, provided that the above
6+
* copyright notice and this permission notice appear in all copies.
7+
*
8+
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9+
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10+
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11+
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13+
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14+
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15+
*
16+
*
17+
* md5 stub code linking to the md5 backend in the OCaml runtime.
18+
*/
19+
20+
#include <caml/mlvalues.h>
21+
#include <caml/memory.h>
22+
#include <caml/alloc.h>
23+
#include <caml/bigarray.h>
24+
#include <caml/threads.h>
25+
26+
#include "md5.h"
27+
28+
#define GET_CTX_STRUCT(a) ((struct MD5Context *) a)
29+
30+
CAMLprim value stub_md5_init(value unit)
31+
{
32+
value ctx;
33+
34+
ctx = caml_alloc_small(sizeof(struct MD5Context), Abstract_tag);
35+
caml_MD5Init(GET_CTX_STRUCT(ctx));
36+
37+
return(ctx);
38+
}
39+
40+
CAMLprim value stub_md5_update(value ctx, value data, value ofs, value len)
41+
{
42+
caml_MD5Update(GET_CTX_STRUCT(ctx),
43+
(unsigned char *) data + Int_val(ofs), Int_val(len));
44+
45+
return(Val_unit);
46+
}
47+
48+
CAMLprim value stub_md5_update_bigarray(value ctx, value buf)
49+
{
50+
CAMLparam2(ctx, buf);
51+
struct MD5Context ctx_dup = *GET_CTX_STRUCT(ctx);
52+
unsigned char *data = Data_bigarray_val(buf);
53+
size_t len = Bigarray_val(buf)->dim[0];
54+
55+
caml_release_runtime_system();
56+
caml_MD5Update(&ctx_dup, data, len);
57+
caml_acquire_runtime_system();
58+
59+
*GET_CTX_STRUCT(ctx) = ctx_dup;
60+
CAMLreturn(Val_unit);
61+
}
62+
63+
CAMLprim value stub_md5_finalize(value ctx)
64+
{
65+
CAMLparam1(ctx);
66+
value result;
67+
68+
result = caml_alloc_string(16);
69+
caml_MD5Final(
70+
(unsigned char *)Bp_val(result),
71+
GET_CTX_STRUCT(ctx));
72+
73+
CAMLreturn(result);
74+
}

test/shatest.ml

+28-2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,15 @@ open OUnit
2121
let cog = "The quick brown fox jumps over the lazy cog"
2222
let dog = "The quick brown fox jumps over the lazy dog"
2323

24+
let ex_strings_md5 = [
25+
("",
26+
"d41d8cd98f00b204e9800998ecf8427e");
27+
("The quick brown fox jumps over the lazy cog",
28+
"1055d3e698d289f2af8663725127bd4b");
29+
("The quick brown fox jumps over the lazy dog",
30+
"9e107d9d372bb6826bd81d3542a419d6");
31+
]
32+
2433
let ex_strings_sha1 = [
2534
("",
2635
"da39a3ee5e6b4b0d3255bfef95601890afd80709");
@@ -46,6 +55,10 @@ let ex_strings_sha512 = [
4655
"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6"); ]
4756

4857

58+
let ex_files_md5 =
59+
[ ("sample.txt",
60+
"9e107d9d372bb6826bd81d3542a419d6") ]
61+
4962
let ex_files_sha1 =
5063
[ ("sample.txt",
5164
"2fd4e1c67a2d28fced849ee1bb76e7391b93eb12") ]
@@ -58,6 +71,10 @@ let ex_files_sha512 =
5871
[ ("sample.txt",
5972
"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6") ]
6073

74+
75+
let ex_channels_md5 =
76+
[ ("sample.txt", "9e107d9d372bb6826bd81d3542a419d6") ]
77+
6178
let ex_channels_sha1 =
6279
[ ("sample.txt", "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12") ]
6380

@@ -69,14 +86,17 @@ let ex_channels_sha512 =
6986
[ ("sample.txt",
7087
"07e547d9586f6a73f73fbac0435ed76951218fb7d0c8d788a309d785436bbb642e93a252a954f23912547d1e8a3b5ed6e1bfd7097821233fa0538f3db854fee6") ]
7188

89+
let stringfct_md5 s = Md5.to_hex (Md5.string s)
7290
let stringfct_sha1 s = Sha1.to_hex (Sha1.string s)
7391
let stringfct_sha256 s = Sha256.to_hex (Sha256.string s)
7492
let stringfct_sha512 s = Sha512.to_hex (Sha512.string s)
7593

94+
let filefct_md5 s = Md5.to_hex (Md5.file s)
7695
let filefct_sha1 s = Sha1.to_hex (Sha1.file s)
7796
let filefct_sha256 s = Sha256.to_hex (Sha256.file s)
7897
let filefct_sha512 s = Sha512.to_hex (Sha512.file s)
7998

99+
let channelfct_md5 s i = Md5.to_hex (Md5.channel s i)
80100
let channelfct_sha1 s i = Sha1.to_hex (Sha1.channel s i)
81101
let channelfct_sha256 s i = Sha256.to_hex (Sha256.channel s i)
82102
let channelfct_sha512 s i = Sha512.to_hex (Sha512.channel s i)
@@ -94,8 +114,14 @@ let test_channel channelfct arr _ =
94114
close_in chan;
95115
assert_equal r digest) arr
96116

97-
let suite = "SHA binding test" >:::
98-
[ "SHA1 example strings" >::
117+
let suite = "hash bindings test" >:::
118+
[ "MD5 example strings" >::
119+
test_strings stringfct_md5 ex_strings_md5;
120+
"MD5 reading a file" >::
121+
test_file filefct_md5 ex_files_md5;
122+
"MD5 reading few byte from channel" >::
123+
test_channel channelfct_md5 ex_channels_md5;
124+
"SHA1 example strings" >::
99125
test_strings stringfct_sha1 ex_strings_sha1;
100126
"SHA1 reading a file" >::
101127
test_file filefct_sha1 ex_files_sha1;

0 commit comments

Comments
 (0)