Merge branch 'pu'
[jungerl.git] / lib / epop / src / epop_md5.erl
blob6ab1ab5ca28c38bf4d05d6df83fc4880bfb7ab88
1 -module(epop_md5).
2 -author('tony@erix.ericsson.se').
3 %%% --------------------------------------------------------------------
4 %%% File : md5.erl
5 %%% Author : Tony Rogvall <tony@erix.ericsson.se>
6 %%% Purpose : Implementation of MD5 in erlang
7 %%% Created : 30 Oct 1997 by Tony Rogvall <tony@erix.ericsson.se>
8 %%% ====================================================================
9 %%% License to copy and use this software is granted provided that it
10 %%% is identified as the "RSA Data Security, Inc. MD5 Message-Digest
11 %%% Algorithm" in all material mentioning or referencing this software
12 %%% or this function.
13 %%%
14 %%% License is also granted to make and use derivative works provided
15 %%% that such works are identified as "derived from the RSA Data
16 %%% Security, Inc. MD5 Message-Digest Algorithm" in all material
17 %%% mentioning or referencing the derived work.
18 %%% ====================================================================
19 %%% Adopted : 17 Aug 1998 by tobbe@serc.rmit.edu.au
20 %%% Made it into an epop module and cleaned it up a bit.
21 %%% --------------------------------------------------------------------
22 -export([string/1]).
24 -import(lists, [reverse/1]).
26 -record(md5_ctx,
28 state = { 16#67452301, 16#efcdab89, 16#98badcfe, 16#10325476 },
29 count = 0, %% number of bits (64 bit)
30 buffer = [] %% input buffer (16 bytes)
31 }).
33 -define(S11, 7).
34 -define(S12, 12).
35 -define(S13, 17).
36 -define(S14, 22).
37 -define(S21, 5).
38 -define(S22, 9).
39 -define(S23, 14).
40 -define(S24, 20).
41 -define(S31, 4).
42 -define(S32, 11).
43 -define(S33, 16).
44 -define(S34, 23).
45 -define(S41, 6).
46 -define(S42, 10).
47 -define(S43, 15).
48 -define(S44, 21).
50 %% F, G, H and I are basic MD5 functions.
52 -define(F(X, Y, Z), (((X) band (Y)) bor ((bnot (X)) band (Z)))).
53 -define(G(X, Y, Z), (((X) band (Z)) bor ((Y) band (bnot (Z))))).
54 -define(H(X, Y, Z), ((X) bxor (Y) bxor (Z))).
55 -define(I(X, Y, Z), ((Y) bxor ((X) bor (bnot (Z))))).
57 -define(U32(X), ((X) band 16#ffffffff)).
59 -define(ROTATE_LEFT(X,N), rotate_left(X,N)).
61 %% FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
62 %% Rotation is separate from addition to prevent recomputation.
64 -define(FF(A, B, C, D, X, S, AC),
65 ?ROTATE_LEFT(A + ?F((B), (C), (D)) + (X) + (AC),(S)) + (B)).
67 -define(GG(A, B, C, D, X, S, AC),
68 ?ROTATE_LEFT(A + ?G((B), (C), (D)) + (X) + (AC),(S)) + (B)).
70 -define( HH(A, B, C, D, X, S, AC),
71 ?ROTATE_LEFT(A + ?H((B), (C), (D)) + (X) + (AC),(S)) + (B)).
73 -define(II(A, B, C, D, X, S, AC),
74 ?ROTATE_LEFT(A + ?I((B), (C), (D)) + (X) + (AC),(S)) + (B)).
76 %% ---------------------------------
77 %% Exported function: string/1
78 %% Do a message digest on a string
79 %% ---------------------------------
81 string(Str) ->
82 format(final(update(init(), Str))).
84 format([X | Xs]) ->
85 [hex(X bsr 4), hex(X) | format(Xs)];
86 format([]) -> [].
88 hex(X) ->
89 X4 = (X band 16#f),
90 if X4 < 10 -> X4 + $0;
91 true -> (X4-10) + $a
92 end.
94 init() ->
95 #md5_ctx {}.
97 update(CTX, Input) ->
98 Buffer = CTX#md5_ctx.buffer,
99 LenI = length(Input),
100 Len = LenI + length(Buffer),
101 update(Buffer ++ Input, Len,CTX#md5_ctx.state,
102 CTX#md5_ctx.count+(LenI bsl 3)).
105 %% update state, count reflects number of bytes
106 %% including bytes in buffer
108 update(Buf0, Len0, State0, Count) when Len0 >= 64 ->
109 {Xs,Buf1} = decode(Buf0, 64),
110 State1 = transform(State0, Xs),
111 update(Buf1, Len0 - 64, State1, Count);
112 update(Buf0, Len0, State0, Count) ->
113 #md5_ctx { state = State0, count = Count, buffer = Buf0 }.
115 %% produce a digest
116 final(CTX) ->
117 %% pad out to a length 56 (we later add a count that makes 64)
118 Count = CTX#md5_ctx.count, %% number of bits
119 Index = (Count bsr 3) rem 64, %% number of bytes
120 PadLen = if Index < 56 ->
121 56 - Index;
122 true -> 120 - Index
123 end,
124 CTX1 = update(CTX, padding(PadLen,[])),
125 CTX2 = update(CTX1, encode([?U32(Count), ?U32(Count bsr 32)])),
126 encode(tuple_to_list(CTX2#md5_ctx.state)).
128 %% generate padding info to final
129 padding(0,Acc) -> Acc;
130 padding(1,Acc) -> [16#80 | Acc];
131 padding(N,Acc) -> padding(N-1, [0 | Acc]).
133 %% rotate X as 32-bit unsigned left N bits
134 rotate_left(X, N) ->
135 ?U32(X bsl N) bor (?U32(X) bsr (32 - N)).
138 %% decodes Len number of bytes into 32 bit integers
139 %% returns {Xs, Tail}
141 decode(Buf, Len) ->
142 decode(Buf, Len, []).
144 decode(Buf, 0, Acc) ->
145 {reverse(Acc), Buf};
146 decode([A0,A1,A2,A3 | Buf], N, Acc) ->
147 decode(Buf, N-4, [ A0 + (A1 bsl 8) + (A2 bsl 16) + (A3 bsl 24) | Acc]).
150 %% Encodes input 32-bit ints into byte buffer output.
152 encode(Xs) -> encode(Xs, []).
154 encode([X | Xs], Acc) ->
155 encode(Xs, [(X bsr 24) band 16#ff,
156 (X bsr 16) band 16#ff,
157 (X bsr 8) band 16#ff,
158 X band 16#ff | Acc]);
159 encode([], Acc) -> reverse(Acc).
162 transform({A0,B0,C0,D0}, Xs) ->
163 [X0,X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15] = Xs,
165 %% Round 1
166 A1 = ?FF (A0, B0, C0, D0, X0, ?S11, 16#d76aa478),
167 D1 = ?FF (D0, A1, B0, C0, X1, ?S12, 16#e8c7b756),
168 C1 = ?FF (C0, D1, A1, B0, X2, ?S13, 16#242070db),
169 B1 = ?FF (B0, C1, D1, A1, X3, ?S14, 16#c1bdceee),
171 A2 = ?FF (A1, B1, C1, D1, X4, ?S11, 16#f57c0faf),
172 D2 = ?FF (D1, A2, B1, C1, X5, ?S12, 16#4787c62a),
173 C2 = ?FF (C1, D2, A2, B1, X6, ?S13, 16#a8304613),
174 B2 = ?FF (B1, C2, D2, A2, X7, ?S14, 16#fd469501),
176 A3 = ?FF (A2, B2, C2, D2, X8, ?S11, 16#698098d8),
177 D3 = ?FF (D2, A3, B2, C2, X9, ?S12, 16#8b44f7af),
178 C3 = ?FF (C2, D3, A3, B2, X10, ?S13, 16#ffff5bb1),
179 B3 = ?FF (B2, C3, D3, A3, X11, ?S14, 16#895cd7be),
181 A4 = ?FF (A3, B3, C3, D3, X12, ?S11, 16#6b901122),
182 D4 = ?FF (D3, A4, B3, C3, X13, ?S12, 16#fd987193),
183 C4 = ?FF (C3, D4, A4, B3, X14, ?S13, 16#a679438e),
184 B4 = ?FF (B3, C4, D4, A4, X15, ?S14, 16#49b40821),
186 %% Round 2
187 A5 = ?GG (A4, B4, C4, D4, X1, ?S21, 16#f61e2562),
188 D5 = ?GG (D4, A5, B4, C4, X6, ?S22, 16#c040b340),
189 C5 = ?GG (C4, D5, A5, B4, X11, ?S23, 16#265e5a51),
190 B5 = ?GG (B4, C5, D5, A5, X0, ?S24, 16#e9b6c7aa),
192 A6 = ?GG (A5, B5, C5, D5, X5, ?S21, 16#d62f105d),
193 D6 = ?GG (D5, A6, B5, C5, X10, ?S22, 16#2441453),
194 C6 = ?GG (C5, D6, A6, B5, X15, ?S23, 16#d8a1e681),
195 B6 = ?GG (B5, C6, D6, A6, X4, ?S24, 16#e7d3fbc8),
197 A7 = ?GG (A6, B6, C6, D6, X9, ?S21, 16#21e1cde6),
198 D7 = ?GG (D6, A7, B6, C6, X14, ?S22, 16#c33707d6),
199 C7 = ?GG (C6, D7, A7, B6, X3, ?S23, 16#f4d50d87),
200 B7 = ?GG (B6, C7, D7, A7, X8, ?S24, 16#455a14ed),
202 A8 = ?GG (A7, B7, C7, D7, X13, ?S21, 16#a9e3e905),
203 D8 = ?GG (D7, A8, B7, C7, X2, ?S22, 16#fcefa3f8),
204 C8 = ?GG (C7, D8, A8, B7, X7, ?S23, 16#676f02d9),
205 B8 = ?GG (B7, C8, D8, A8, X12, ?S24, 16#8d2a4c8a),
207 %% Round 3
208 A9 = ?HH (A8, B8, C8, D8, X5, ?S31, 16#fffa3942),
209 D9 = ?HH (D8, A9, B8, C8, X8, ?S32, 16#8771f681),
210 C9 = ?HH (C8, D9, A9, B8, X11, ?S33, 16#6d9d6122),
211 B9 = ?HH (B8, C9, D9, A9, X14, ?S34, 16#fde5380c),
213 A10 = ?HH (A9, B9, C9, D9, X1, ?S31, 16#a4beea44),
214 D10 = ?HH (D9, A10, B9, C9, X4, ?S32, 16#4bdecfa9),
215 C10 = ?HH (C9, D10, A10, B9, X7, ?S33, 16#f6bb4b60),
216 B10 = ?HH (B9, C10, D10, A10, X10, ?S34, 16#bebfbc70),
218 A11 = ?HH (A10, B10, C10, D10, X13, ?S31, 16#289b7ec6),
219 D11 = ?HH (D10, A11, B10, C10, X0, ?S32, 16#eaa127fa),
220 C11 = ?HH (C10, D11, A11, B10, X3, ?S33, 16#d4ef3085),
221 B11 = ?HH (B10, C11, D11, A11, X6, ?S34, 16#4881d05),
223 A12 = ?HH (A11, B11, C11, D11, X9, ?S31, 16#d9d4d039),
224 D12 = ?HH (D11, A12, B11, C11, X12, ?S32, 16#e6db99e5),
225 C12 = ?HH (C11, D12, A12, B11, X15, ?S33, 16#1fa27cf8),
226 B12 = ?HH (B11, C12, D12, A12, X2, ?S34, 16#c4ac5665),
228 %% Round 4
229 A13 = ?II (A12, B12, C12, D12, X0, ?S41, 16#f4292244),
230 D13 = ?II (D12, A13, B12, C12, X7, ?S42, 16#432aff97),
231 C13 = ?II (C12, D13, A13, B12, X14, ?S43, 16#ab9423a7),
232 B13 = ?II (B12, C13, D13, A13, X5, ?S44, 16#fc93a039),
234 A14 = ?II (A13, B13, C13, D13, X12, ?S41, 16#655b59c3),
235 D14 = ?II (D13, A14, B13, C13, X3, ?S42, 16#8f0ccc92),
236 C14 = ?II (C13, D14, A14, B13, X10, ?S43, 16#ffeff47d),
237 B14 = ?II (B13, C14, D14, A14, X1, ?S44, 16#85845dd1),
239 A15 = ?II (A14, B14, C14, D14, X8, ?S41, 16#6fa87e4f),
240 D15 = ?II (D14, A15, B14, C14, X15, ?S42, 16#fe2ce6e0),
241 C15 = ?II (C14, D15, A15, B14, X6, ?S43, 16#a3014314),
242 B15 = ?II (B14, C15, D15, A15, X13, ?S44, 16#4e0811a1),
244 A16 = ?II (A15, B15, C15, D15, X4, ?S41, 16#f7537e82),
245 D16 = ?II (D15, A16, B15, C15, X11, ?S42, 16#bd3af235),
246 C16 = ?II (C15, D16, A16, B15, X2, ?S43, 16#2ad7d2bb),
247 B16 = ?II (B15, C16, D16, A16, X9, ?S44, 16#eb86d391),
249 {?U32(A0+A16), ?U32(B0+B16), ?U32(C0+C16), ?U32(D0+D16)}.