Packages

POP3 email client in pure Erlang, a.k.a. erlpop derived from the original epop package. Retrieve/stream mail. Implements the following commands in accordance with RFC-1939: APOP, DELE, LIST, NOOP, PASS, RETR, RSET, STAT, TOP, UIDL, USER, QUIT. Optionally check if an email address is RFC 5322 comp...

Current section

Files

Jump to
pop3client src epop_md5.erl
Raw

src/epop_md5.erl

-module(epop_md5).
-author('tony@erix.ericsson.se').
%%% --------------------------------------------------------------------
%%% File : md5.erl
%%% Author : Tony Rogvall <tony@erix.ericsson.se>
%%% Purpose : Implementation of MD5 in erlang
%%% Created : 30 Oct 1997 by Tony Rogvall <tony@erix.ericsson.se>
%%% ====================================================================
%%% License to copy and use this software is granted provided that it
%%% is identified as the "RSA Data Security, Inc. MD5 Message-Digest
%%% Algorithm" in all material mentioning or referencing this software
%%% or this function.
%%%
%%% License is also granted to make and use derivative works provided
%%% that such works are identified as "derived from the RSA Data
%%% Security, Inc. MD5 Message-Digest Algorithm" in all material
%%% mentioning or referencing the derived work.
%%% ====================================================================
%%% Adopted : 17 Aug 1998 by tobbe@serc.rmit.edu.au
%%% Made it into an epop module and cleaned it up a bit.
%%% --------------------------------------------------------------------
-export([string/1]).
-import(lists, [reverse/1]).
-record(md5_ctx,
{
state = { 16#67452301, 16#efcdab89, 16#98badcfe, 16#10325476 },
count = 0, %% number of bits (64 bit)
buffer = [] %% input buffer (16 bytes)
}).
-define(S11, 7).
-define(S12, 12).
-define(S13, 17).
-define(S14, 22).
-define(S21, 5).
-define(S22, 9).
-define(S23, 14).
-define(S24, 20).
-define(S31, 4).
-define(S32, 11).
-define(S33, 16).
-define(S34, 23).
-define(S41, 6).
-define(S42, 10).
-define(S43, 15).
-define(S44, 21).
%% F, G, H and I are basic MD5 functions.
-define(F(X, Y, Z), (((X) band (Y)) bor ((bnot (X)) band (Z)))).
-define(G(X, Y, Z), (((X) band (Z)) bor ((Y) band (bnot (Z))))).
-define(H(X, Y, Z), ((X) bxor (Y) bxor (Z))).
-define(I(X, Y, Z), ((Y) bxor ((X) bor (bnot (Z))))).
-define(U32(X), ((X) band 16#ffffffff)).
-define(ROTATE_LEFT(X,N), rotate_left(X,N)).
%% FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
%% Rotation is separate from addition to prevent recomputation.
%%
-define(FF(A, B, C, D, X, S, AC),
?ROTATE_LEFT(A + ?F((B), (C), (D)) + (X) + (AC),(S)) + (B)).
-define(GG(A, B, C, D, X, S, AC),
?ROTATE_LEFT(A + ?G((B), (C), (D)) + (X) + (AC),(S)) + (B)).
-define( HH(A, B, C, D, X, S, AC),
?ROTATE_LEFT(A + ?H((B), (C), (D)) + (X) + (AC),(S)) + (B)).
-define(II(A, B, C, D, X, S, AC),
?ROTATE_LEFT(A + ?I((B), (C), (D)) + (X) + (AC),(S)) + (B)).
%% ---------------------------------
%% Exported function: string/1
%% Do a message digest on a string
%% ---------------------------------
string(Str) ->
format(final(update(init(), Str))).
format([X | Xs]) ->
[hex(X bsr 4), hex(X) | format(Xs)];
format([]) -> [].
hex(X) ->
X4 = (X band 16#f),
if X4 < 10 -> X4 + $0;
true -> (X4-10) + $a
end.
init() ->
#md5_ctx {}.
update(CTX, Input) ->
Buffer = CTX#md5_ctx.buffer,
LenI = length(Input),
Len = LenI + length(Buffer),
update(Buffer ++ Input, Len,CTX#md5_ctx.state,
CTX#md5_ctx.count+(LenI bsl 3)).
%%
%% update state, count reflects number of bytes
%% including bytes in buffer
%%
update(Buf0, Len0, State0, Count) when Len0 >= 64 ->
{Xs,Buf1} = decode(Buf0, 64),
State1 = transform(State0, Xs),
update(Buf1, Len0 - 64, State1, Count);
update(Buf0, _, State0, Count) ->
#md5_ctx { state = State0, count = Count, buffer = Buf0 }.
%% produce a digest
final(CTX) ->
%% pad out to a length 56 (we later add a count that makes 64)
Count = CTX#md5_ctx.count, %% number of bits
Index = (Count bsr 3) rem 64, %% number of bytes
PadLen = if Index < 56 ->
56 - Index;
true -> 120 - Index
end,
CTX1 = update(CTX, padding(PadLen,[])),
CTX2 = update(CTX1, encode([?U32(Count), ?U32(Count bsr 32)])),
encode(tuple_to_list(CTX2#md5_ctx.state)).
%% generate padding info to final
padding(0,Acc) -> Acc;
padding(1,Acc) -> [16#80 | Acc];
padding(N,Acc) -> padding(N-1, [0 | Acc]).
%% rotate X as 32-bit unsigned left N bits
rotate_left(X, N) ->
?U32(X bsl N) bor (?U32(X) bsr (32 - N)).
%%
%% decodes Len number of bytes into 32 bit integers
%% returns {Xs, Tail}
%%
decode(Buf, Len) ->
decode(Buf, Len, []).
decode(Buf, 0, Acc) ->
{reverse(Acc), Buf};
decode([A0,A1,A2,A3 | Buf], N, Acc) ->
decode(Buf, N-4, [ A0 + (A1 bsl 8) + (A2 bsl 16) + (A3 bsl 24) | Acc]).
%%
%% Encodes input 32-bit ints into byte buffer output.
%%
encode(Xs) -> encode(Xs, []).
encode([X | Xs], Acc) ->
encode(Xs, [(X bsr 24) band 16#ff,
(X bsr 16) band 16#ff,
(X bsr 8) band 16#ff,
X band 16#ff | Acc]);
encode([], Acc) -> reverse(Acc).
transform({A0,B0,C0,D0}, Xs) ->
[X0,X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15] = Xs,
%% Round 1
A1 = ?FF (A0, B0, C0, D0, X0, ?S11, 16#d76aa478),
D1 = ?FF (D0, A1, B0, C0, X1, ?S12, 16#e8c7b756),
C1 = ?FF (C0, D1, A1, B0, X2, ?S13, 16#242070db),
B1 = ?FF (B0, C1, D1, A1, X3, ?S14, 16#c1bdceee),
A2 = ?FF (A1, B1, C1, D1, X4, ?S11, 16#f57c0faf),
D2 = ?FF (D1, A2, B1, C1, X5, ?S12, 16#4787c62a),
C2 = ?FF (C1, D2, A2, B1, X6, ?S13, 16#a8304613),
B2 = ?FF (B1, C2, D2, A2, X7, ?S14, 16#fd469501),
A3 = ?FF (A2, B2, C2, D2, X8, ?S11, 16#698098d8),
D3 = ?FF (D2, A3, B2, C2, X9, ?S12, 16#8b44f7af),
C3 = ?FF (C2, D3, A3, B2, X10, ?S13, 16#ffff5bb1),
B3 = ?FF (B2, C3, D3, A3, X11, ?S14, 16#895cd7be),
A4 = ?FF (A3, B3, C3, D3, X12, ?S11, 16#6b901122),
D4 = ?FF (D3, A4, B3, C3, X13, ?S12, 16#fd987193),
C4 = ?FF (C3, D4, A4, B3, X14, ?S13, 16#a679438e),
B4 = ?FF (B3, C4, D4, A4, X15, ?S14, 16#49b40821),
%% Round 2
A5 = ?GG (A4, B4, C4, D4, X1, ?S21, 16#f61e2562),
D5 = ?GG (D4, A5, B4, C4, X6, ?S22, 16#c040b340),
C5 = ?GG (C4, D5, A5, B4, X11, ?S23, 16#265e5a51),
B5 = ?GG (B4, C5, D5, A5, X0, ?S24, 16#e9b6c7aa),
A6 = ?GG (A5, B5, C5, D5, X5, ?S21, 16#d62f105d),
D6 = ?GG (D5, A6, B5, C5, X10, ?S22, 16#2441453),
C6 = ?GG (C5, D6, A6, B5, X15, ?S23, 16#d8a1e681),
B6 = ?GG (B5, C6, D6, A6, X4, ?S24, 16#e7d3fbc8),
A7 = ?GG (A6, B6, C6, D6, X9, ?S21, 16#21e1cde6),
D7 = ?GG (D6, A7, B6, C6, X14, ?S22, 16#c33707d6),
C7 = ?GG (C6, D7, A7, B6, X3, ?S23, 16#f4d50d87),
B7 = ?GG (B6, C7, D7, A7, X8, ?S24, 16#455a14ed),
A8 = ?GG (A7, B7, C7, D7, X13, ?S21, 16#a9e3e905),
D8 = ?GG (D7, A8, B7, C7, X2, ?S22, 16#fcefa3f8),
C8 = ?GG (C7, D8, A8, B7, X7, ?S23, 16#676f02d9),
B8 = ?GG (B7, C8, D8, A8, X12, ?S24, 16#8d2a4c8a),
%% Round 3
A9 = ?HH (A8, B8, C8, D8, X5, ?S31, 16#fffa3942),
D9 = ?HH (D8, A9, B8, C8, X8, ?S32, 16#8771f681),
C9 = ?HH (C8, D9, A9, B8, X11, ?S33, 16#6d9d6122),
B9 = ?HH (B8, C9, D9, A9, X14, ?S34, 16#fde5380c),
A10 = ?HH (A9, B9, C9, D9, X1, ?S31, 16#a4beea44),
D10 = ?HH (D9, A10, B9, C9, X4, ?S32, 16#4bdecfa9),
C10 = ?HH (C9, D10, A10, B9, X7, ?S33, 16#f6bb4b60),
B10 = ?HH (B9, C10, D10, A10, X10, ?S34, 16#bebfbc70),
A11 = ?HH (A10, B10, C10, D10, X13, ?S31, 16#289b7ec6),
D11 = ?HH (D10, A11, B10, C10, X0, ?S32, 16#eaa127fa),
C11 = ?HH (C10, D11, A11, B10, X3, ?S33, 16#d4ef3085),
B11 = ?HH (B10, C11, D11, A11, X6, ?S34, 16#4881d05),
A12 = ?HH (A11, B11, C11, D11, X9, ?S31, 16#d9d4d039),
D12 = ?HH (D11, A12, B11, C11, X12, ?S32, 16#e6db99e5),
C12 = ?HH (C11, D12, A12, B11, X15, ?S33, 16#1fa27cf8),
B12 = ?HH (B11, C12, D12, A12, X2, ?S34, 16#c4ac5665),
%% Round 4
A13 = ?II (A12, B12, C12, D12, X0, ?S41, 16#f4292244),
D13 = ?II (D12, A13, B12, C12, X7, ?S42, 16#432aff97),
C13 = ?II (C12, D13, A13, B12, X14, ?S43, 16#ab9423a7),
B13 = ?II (B12, C13, D13, A13, X5, ?S44, 16#fc93a039),
A14 = ?II (A13, B13, C13, D13, X12, ?S41, 16#655b59c3),
D14 = ?II (D13, A14, B13, C13, X3, ?S42, 16#8f0ccc92),
C14 = ?II (C13, D14, A14, B13, X10, ?S43, 16#ffeff47d),
B14 = ?II (B13, C14, D14, A14, X1, ?S44, 16#85845dd1),
A15 = ?II (A14, B14, C14, D14, X8, ?S41, 16#6fa87e4f),
D15 = ?II (D14, A15, B14, C14, X15, ?S42, 16#fe2ce6e0),
C15 = ?II (C14, D15, A15, B14, X6, ?S43, 16#a3014314),
B15 = ?II (B14, C15, D15, A15, X13, ?S44, 16#4e0811a1),
A16 = ?II (A15, B15, C15, D15, X4, ?S41, 16#f7537e82),
D16 = ?II (D15, A16, B15, C15, X11, ?S42, 16#bd3af235),
C16 = ?II (C15, D16, A16, B15, X2, ?S43, 16#2ad7d2bb),
B16 = ?II (B15, C16, D16, A16, X9, ?S44, 16#eb86d391),
{?U32(A0+A16), ?U32(B0+B16), ?U32(C0+C16), ?U32(D0+D16)}.