1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1999-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20
21-module(crypto_SUITE).
22
23-include_lib("common_test/include/ct.hrl").
24
25-export([all/0, suite/0,
26         t_md5/1,t_md5_update/1,error/1,unaligned_context/1,random_lists/1,
27         misc_errors/1]).
28
29suite() ->
30    [{ct_hooks,[ts_install_cth]}].
31
32all() ->
33    [t_md5, t_md5_update, error, unaligned_context,
34     random_lists, misc_errors].
35
36%% Test crc32, adler32 and md5 error cases not covered by other tests"
37misc_errors(Config) when is_list(Config) ->
38    ct:timetrap({minutes, 2}),
39    1 = erlang:adler32([]),
40    L = lists:duplicate(600,3),
41    1135871753 = erlang:adler32(L),
42    L2 = lists:duplicate(22000,3),
43    1100939744 = erlang:adler32(L2),
44    {'EXIT', {badarg,_}} = (catch erlang:adler32(L++[a])),
45    {'EXIT', {badarg,_}} = (catch erlang:crc32(L++[a])),
46    {'EXIT', {badarg,_}} = (catch erlang:crc32([1,2,3|<<25:7>>])),
47    {'EXIT', {badarg,_}} = (catch erlang:crc32([1,2,3|4])),
48    Big = 111111111111111111111111111111,
49    {'EXIT', {badarg,_}} = (catch erlang:crc32(Big,<<"hej">>)),
50    {'EXIT', {badarg,_}} = (catch erlang:crc32(25,[1,2,3|4])),
51    {'EXIT', {badarg,_}} = (catch erlang:crc32_combine(Big,3,3)),
52    {'EXIT', {badarg,_}} = (catch erlang:crc32_combine(3,Big,3)),
53    {'EXIT', {badarg,_}} = (catch erlang:crc32_combine(3,3,Big)),
54    {'EXIT', {badarg,_}} = (catch erlang:adler32(Big,<<"hej">>)),
55    {'EXIT', {badarg,_}} = (catch erlang:adler32(25,[1,2,3|4])),
56    {'EXIT', {badarg,_}} = (catch erlang:adler32_combine(Big,3,3)),
57    {'EXIT', {badarg,_}} = (catch erlang:adler32_combine(3,Big,3)),
58    {'EXIT', {badarg,_}} = (catch erlang:adler32_combine(3,3,Big)),
59    {'EXIT', {badarg,_}} = (catch erlang:md5_update(<<"hej">>,<<"hej">>)),
60    {'EXIT', {badarg,_}} = (catch erlang:md5_final(<<"hej">>)),
61    ok.
62
63
64%%
65%% Most of the real code for these test cases are in
66%% the modules crypto_reference and random_iolist.
67%%
68-define(REF,crypto_reference).
69
70nicesplit(N,L) ->
71    nicesplit(N,L,[]).
72nicesplit(0,Tail,Acc) ->
73    {lists:reverse(Acc),Tail};
74nicesplit(_,[],Acc) ->
75    {lists:reverse(Acc),[]};
76nicesplit(N,[H|Tail],Acc) ->
77    nicesplit(N-1,Tail,[H|Acc]).
78
79run_in_para([],_) ->
80    true;
81run_in_para(FunList,Schedulers) ->
82    {ThisTime,NextTime} = nicesplit(Schedulers,FunList),
83    case length(ThisTime) of
84        1 ->
85            [{L,Fun}] = ThisTime,
86            try
87                Fun()
88            catch
89                _:Reason ->
90                    exit({error_at_line,L,Reason})
91            end;
92        _ ->
93            These = [ {L,erlang:spawn_monitor(F)} || {L,F} <- ThisTime ],
94            collect_workers(These)
95    end,
96    run_in_para(NextTime,Schedulers).
97
98collect_workers([]) ->
99    ok;
100collect_workers([{L,{Pid,Ref}}|T]) ->
101    receive
102        {'DOWN',Ref,process,Pid,normal} ->
103            collect_workers(T);
104        {'DOWN',Ref,process,Pid,Other} ->
105            exit({error_at_line,L,Other})
106    end.
107
108%% Test crc32, adler32 and md5 on a number of pseudo-randomly generated lists.
109random_lists(Config) when is_list(Config) ->
110    ct:timetrap({minutes, 5}),
111    Num = erlang:system_info(schedulers_online),
112    B = list_to_binary(
113          lists:duplicate(
114            (erlang:system_info(context_reductions)*10) - 50,$!)),
115    CRC32_1 = fun(L) -> erlang:crc32(L) end,
116    CRC32_2 = fun(L) -> ?REF:crc32(L) end,
117    ADLER32_1 = fun(L) -> erlang:adler32(L) end,
118    ADLER32_2 = fun(L) -> ?REF:adler32(L) end,
119    MD5_1 = fun(L) -> erlang:md5(L) end,
120    MD5_2 = fun(L) -> ?REF:md5_final(
121                         ?REF:md5_update(?REF:md5_init(),L)) end,
122    MD5_3 =  fun(L) -> erlang:md5_final(
123                         erlang:md5_update(erlang:md5_init(),L)) end,
124    CRC32_1_L = fun(L) -> erlang:crc32([B|L]) end,
125    CRC32_2_L = fun(L) -> ?REF:crc32([B|L]) end,
126    ADLER32_1_L = fun(L) -> erlang:adler32([B|L]) end,
127    ADLER32_2_L = fun(L) -> ?REF:adler32([B|L]) end,
128    MD5_1_L = fun(L) -> erlang:md5([B|L]) end,
129    MD5_2_L = fun(L) -> ?REF:md5_final(
130                           ?REF:md5_update(?REF:md5_init(),[B|L])) end,
131    MD5_3_L =  fun(L) -> erlang:md5_final(
132                           erlang:md5_update(
133                             erlang:md5_init(),[B|L])) end,
134    Wlist0 =
135    [{?LINE, fun() -> random_iolist:run(150, CRC32_1, CRC32_2) end},
136     {?LINE, fun() -> random_iolist:run(150, ADLER32_1, ADLER32_2) end},
137     {?LINE, fun() -> random_iolist:run(150,MD5_1,MD5_2) end},
138     {?LINE, fun() -> random_iolist:run(150,MD5_1,MD5_3) end},
139     {?LINE, fun() -> random_iolist:run(150, CRC32_1_L, CRC32_2_L) end},
140     {?LINE,
141      fun() -> random_iolist:run(150, ADLER32_1_L, ADLER32_2_L) end},
142     {?LINE, fun() -> random_iolist:run(150,MD5_1_L,MD5_2_L) end},
143     {?LINE, fun() -> random_iolist:run(150,MD5_1_L,MD5_3_L) end}],
144    run_in_para(Wlist0,Num),
145    CRC32_1_2 = fun(L1,L2) -> erlang:crc32([L1,L2]) end,
146    CRC32_2_2 = fun(L1,L2) -> erlang:crc32(erlang:crc32(L1),L2) end,
147    CRC32_3_2 = fun(L1,L2) -> erlang:crc32_combine(
148                                erlang:crc32(L1),
149                                erlang:crc32(L2),
150                                erlang:iolist_size(L2))
151                end,
152    ADLER32_1_2 = fun(L1,L2) -> erlang:adler32([L1,L2]) end,
153    ADLER32_2_2 = fun(L1,L2) -> erlang:adler32(
154                                  erlang:adler32(L1),L2) end,
155    ADLER32_3_2 = fun(L1,L2) -> erlang:adler32_combine(
156                                  erlang:adler32(L1),
157                                  erlang:adler32(L2),
158                                  erlang:iolist_size(L2))
159                  end,
160    MD5_1_2 = fun(L1,L2) -> erlang:md5([L1,L2]) end,
161    MD5_2_2 = fun(L1,L2) ->
162                      erlang:md5_final(
163                        erlang:md5_update(
164                          erlang:md5_update(
165                            erlang:md5_init(),
166                            L1),
167                          L2))
168              end,
169    CRC32_1_L_2 = fun(L1,L2) -> erlang:crc32([[B|L1],[B|L2]]) end,
170    CRC32_2_L_2 = fun(L1,L2) -> erlang:crc32(
171                                  erlang:crc32([B|L1]),[B|L2]) end,
172    CRC32_3_L_2 = fun(L1,L2) -> erlang:crc32_combine(
173                                  erlang:crc32([B|L1]),
174                                  erlang:crc32([B|L2]),
175                                  erlang:iolist_size([B|L2]))
176                  end,
177    ADLER32_1_L_2 = fun(L1,L2) -> erlang:adler32([[B|L1],[B|L2]]) end,
178    ADLER32_2_L_2 = fun(L1,L2) -> erlang:adler32(
179                                    erlang:adler32([B|L1]),
180                                    [B|L2])
181                    end,
182    ADLER32_3_L_2 = fun(L1,L2) -> erlang:adler32_combine(
183                                    erlang:adler32([B|L1]),
184                                    erlang:adler32([B|L2]),
185                                    erlang:iolist_size([B|L2]))
186                    end,
187    MD5_1_L_2 = fun(L1,L2) -> erlang:md5([[B|L1],[B|L2]]) end,
188    MD5_2_L_2 = fun(L1,L2) ->
189                        erlang:md5_final(
190                          erlang:md5_update(
191                            erlang:md5_update(
192                              erlang:md5_init(),
193                              [B|L1]),
194                            [B|L2]))
195                end,
196    Wlist1 =
197    [{?LINE, fun() -> random_iolist:run2(150,CRC32_1_2,CRC32_2_2) end},
198     {?LINE, fun() -> random_iolist:run2(150,CRC32_1_2,CRC32_3_2) end},
199     {?LINE, fun() -> random_iolist:run2(150,ADLER32_1_2,ADLER32_2_2) end},
200     {?LINE, fun() -> random_iolist:run2(150,ADLER32_1_2,ADLER32_3_2) end},
201     {?LINE, fun() -> random_iolist:run2(150,MD5_1_2,MD5_2_2) end},
202     {?LINE, fun() -> random_iolist:run2(150,CRC32_1_L_2,CRC32_2_L_2) end},
203     {?LINE, fun() -> random_iolist:run2(150,CRC32_1_L_2,CRC32_3_L_2) end},
204     {?LINE,
205      fun() -> random_iolist:run2(150,ADLER32_1_L_2,ADLER32_2_L_2) end},
206     {?LINE,
207      fun() -> random_iolist:run2(150,ADLER32_1_L_2,ADLER32_3_L_2) end},
208     {?LINE, fun() -> random_iolist:run2(150,MD5_1_L_2,MD5_2_L_2) end}],
209    run_in_para(Wlist1,Num),
210    ok.
211
212%% Generate MD5 message digests and check the result. Examples are from RFC-1321.
213t_md5(Config) when is_list(Config) ->
214    t_md5_test("", "d41d8cd98f00b204e9800998ecf8427e"),
215    t_md5_test("a", "0cc175b9c0f1b6a831c399e269772661"),
216    t_md5_test("abc", "900150983cd24fb0d6963f7d28e17f72"),
217    t_md5_test(["message ","digest"], "f96b697d7cb7938d525a2f31aaf161d0"),
218    t_md5_test(["message ",unaligned_sub_bin(<<"digest">>)],
219               "f96b697d7cb7938d525a2f31aaf161d0"),
220    t_md5_test("abcdefghijklmnopqrstuvwxyz",
221               "c3fcd3d76192e4007dfb496cca67e13b"),
222    t_md5_test("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
223               "0123456789",
224               "d174ab98d277d9f5a5611c2c9f419d9f"),
225    t_md5_test("12345678901234567890123456789012345678901234567890"
226               "123456789012345678901234567890",
227               "57edf4a22be3c955ac49da2e2107b67a"),
228    ok.
229
230%% Generate MD5 message using md5_init, md5_update, and md5_final, and
231%% check the result. Examples are from RFC-1321.
232t_md5_update(Config) when is_list(Config) ->
233    t_md5_update_1(fun(Str) -> Str end),
234    t_md5_update_1(fun(Str) -> list_to_binary(Str) end),
235    t_md5_update_1(fun(Str) -> unaligned_sub_bin(list_to_binary(Str)) end),
236    ok.
237
238t_md5_update_1(Tr) when is_function(Tr, 1) ->
239    Ctx = erlang:md5_init(),
240    Ctx1 = erlang:md5_update(Ctx, Tr("ABCDEFGHIJKLMNOPQRSTUVWXYZ")),
241    Ctx2 = erlang:md5_update(Ctx1, Tr("abcdefghijklmnopqrstuvwxyz"
242                                      "0123456789")),
243    m(erlang:md5_final(Ctx2),
244      hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")),
245    ok.
246
247%%
248%%
249error(Config) when is_list(Config) ->
250    {'EXIT',{badarg,_}} = (catch erlang:md5(bit_sized_binary(<<"abc">>))),
251    Ctx0 = erlang:md5_init(),
252    {'EXIT',{badarg,_}} =
253    (catch erlang:md5_update(Ctx0, bit_sized_binary(<<"abcfjldjd">>))),
254    {'EXIT',{badarg,_}} =
255    (catch erlang:md5_update(Ctx0, ["something",bit_sized_binary(<<"abcfjldjd">>)])),
256    {'EXIT',{badarg,_}} =
257    (catch erlang:md5_update(bit_sized_binary(Ctx0), "something")),
258    {'EXIT',{badarg,_}} = (catch erlang:md5_final(bit_sized_binary(Ctx0))),
259    m(erlang:md5_final(Ctx0), hexstr2bin("d41d8cd98f00b204e9800998ecf8427e")),
260    ok.
261
262
263%%
264%%
265unaligned_context(Config) when is_list(Config) ->
266    Ctx0 = erlang:md5_init(),
267    Ctx1 = erlang:md5_update(unaligned_sub_bin(Ctx0), "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
268    Ctx = erlang:md5_update(unaligned_sub_bin(Ctx1),
269                            "abcdefghijklmnopqrstuvwxyz0123456789"),
270    m(erlang:md5_final(unaligned_sub_bin(Ctx)),
271      hexstr2bin("d174ab98d277d9f5a5611c2c9f419d9f")),
272    ok.
273
274%%
275%% Help functions
276%%
277
278t_md5_test(Str, ResultStr) ->
279    ResultBin = hexstr2bin(ResultStr),
280    m(erlang:md5(Str), ResultBin),
281    Bin = list_to_binary(Str),
282    m(erlang:md5(Bin), ResultBin),
283    UnalignedSubBin = unaligned_sub_bin(Bin),
284    m(erlang:md5(UnalignedSubBin), ResultBin).
285
286m(X, X) -> true.
287
288hexstr2bin(S) ->
289    list_to_binary(hexstr2list(S)).
290
291hexstr2list([X,Y|T]) ->
292    [mkint(X)*16 + mkint(Y) | hexstr2list(T)];
293hexstr2list([]) ->
294    [].
295
296mkint(C) when $0 =< C, C =< $9 ->
297    C - $0;
298mkint(C) when $A =< C, C =< $F ->
299    C - $A + 10;
300mkint(C) when $a =< C, C =< $f ->
301    C - $a + 10.
302
303unaligned_sub_bin(Bin0) ->
304    Bin1 = <<0:3,Bin0/binary,31:5>>,
305    Sz = size(Bin0),
306    <<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
307    Bin.
308
309%% Add 1 bit to the size of the binary.
310bit_sized_binary(Bin0) ->
311    Bin = <<Bin0/binary,1:1>>,
312    BitSize = bit_size(Bin),
313    BitSize = 8*size(Bin) + 1,
314    Bin.
315
316id(I) -> I.
317