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