Imported Upstream version 3.1.0
[debian/amanda] / ndmp-src / ndml_md5.c
1 /*
2  * Copyright (c) 2000
3  *      Traakan, Inc., Los Altos, CA
4  *      All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 /*
30  * Project:  NDMJOB
31  * Ident:    $Id: $
32  *
33  * Description:
34  *
35  * MD5 authentication support
36  ****************************************************************
37  * Both sides share a secret in the form of a clear-text
38  * password. One side generates a challenge (64-bytes)
39  * and conveys it to the other. The other side then
40  * uses the challenge, the clear-text password, and
41  * the NDMP rules for MD5, and generates a digest.
42  * The digest is returned as proof that both sides
43  * share the same secret clear-text password.
44  *
45  * The NDMP rules for MD5 are implemented in ndmmd5_digest().
46  * It amounts to positioning the clear-text password and challenge
47  * into a "message" buffer, then applying the MD5 algorithm.
48  *
49  * ndmmd5_generate_challenge() generates a challenge[]
50  * using conventional random number routines.
51  *
52  * ndmmd5_ok_digest() takes a locally known challenge[]
53  * and clear-text password, a remotely generated
54  * digest[], and determines if everything is correct.
55  *
56  * Using MD5 prevents clear-text passwords from being conveyed
57  * over the network. However, it compels both sides to maintain
58  * clear-text passwords in a secure fashion, which is difficult
59  * to say the least. Because the NDMP MD5 rules must be followed
60  * to digest() the password, it's impractical to consider
61  * an external authentication authority.
62  *
63  * Credits to Rajiv of NetApp for helping with MD5 stuff.
64  */
65
66
67 #include "ndmlib.h"
68 #include "md5.h"
69
70
71 int
72 ndmmd5_generate_challenge (char challenge[NDMP_MD5_CHALLENGE_LENGTH])
73 {
74         int                     i;
75
76         NDMOS_MACRO_SRAND();
77
78         for (i = 0; i < NDMP_MD5_CHALLENGE_LENGTH; i++) {
79                 challenge[i] = NDMOS_MACRO_RAND() >> (i&7);
80         }
81
82         return 0;
83 }
84
85
86 int
87 ndmmd5_ok_digest (char challenge[NDMP_MD5_CHALLENGE_LENGTH],
88   char *clear_text_password,
89   char digest[NDMP_MD5_DIGEST_LENGTH])
90 {
91         char            my_digest[16];
92         int             i;
93
94         ndmmd5_digest (challenge, clear_text_password, my_digest);
95
96         for (i = 0; i < NDMP_MD5_DIGEST_LENGTH; i++)
97                 if (digest[i] != my_digest[i])
98                         return 0;       /* Invalid */
99
100         return 1;       /* OK */
101 }
102
103
104 int
105 ndmmd5_digest (char challenge[NDMP_MD5_CHALLENGE_LENGTH],
106   char *clear_text_password,
107   char digest[NDMP_MD5_DIGEST_LENGTH])
108 {
109         int             pwlength = strlen (clear_text_password);
110         MD5_CTX         mdContext;
111         unsigned char   message[128];
112
113         /*
114          * The spec describes the construction of the 128 byte
115          * "message" (probably MD5-speak). It is described as:
116          *
117          *      PASSWORD PADDING CHALLENGE PADDING PASSWORD
118          *
119          * Each PADDING is defined as zeros of length 64 minus pwlen.
120          *
121          * A pwlen of over 32 would result in not all fields
122          * fitting. This begs a question of the order elements
123          * are inserted into the message[]. You get a different
124          * message[] if you insert the PASSWORD(s) before
125          * the CHALLENGE than you get the other way around.
126          *
127          * A pwlen of over 64 would result in PADDING of negative
128          * length, which could cause crash boom bang.
129          *
130          * The resolution of this vaguery implemented here is to
131          * only use the first 32 bytes of the password. All
132          * fields fit. Order dependencies are avoided.
133          *
134          * Final resolution is pending.
135          */
136         if (pwlength > 32)
137                 pwlength = 32;
138
139         /*
140          * Compose the 128-byte buffer according to NDMP rules
141          */
142         NDMOS_API_BZERO (message, sizeof message);
143         NDMOS_API_BCOPY (clear_text_password, &message[0], pwlength);
144         NDMOS_API_BCOPY (clear_text_password,
145                                 &message[128 - pwlength], pwlength);
146         NDMOS_API_BCOPY (challenge, &message[64 - pwlength], 64);
147
148         /*
149          * Grind it up, ala MD5
150          */
151         MD5Init(&mdContext);
152         MD5Update(&mdContext, message, 128);
153         MD5Final((unsigned char *)digest, &mdContext);
154
155         /*
156          * ding! done
157          */
158         return 0;
159 }