/*
* Copyright (c) 2000
* Traakan, Inc., Los Altos, CA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Project: NDMJOB
* Ident: $Id: $
*
* Description:
*
* MD5 authentication support
****************************************************************
* Both sides share a secret in the form of a clear-text
* password. One side generates a challenge (64-bytes)
* and conveys it to the other. The other side then
* uses the challenge, the clear-text password, and
* the NDMP rules for MD5, and generates a digest.
* The digest is returned as proof that both sides
* share the same secret clear-text password.
*
* The NDMP rules for MD5 are implemented in ndmmd5_digest().
* It amounts to positioning the clear-text password and challenge
* into a "message" buffer, then applying the MD5 algorithm.
*
* ndmmd5_generate_challenge() generates a challenge[]
* using conventional random number routines.
*
* ndmmd5_ok_digest() takes a locally known challenge[]
* and clear-text password, a remotely generated
* digest[], and determines if everything is correct.
*
* Using MD5 prevents clear-text passwords from being conveyed
* over the network. However, it compels both sides to maintain
* clear-text passwords in a secure fashion, which is difficult
* to say the least. Because the NDMP MD5 rules must be followed
* to digest() the password, it's impractical to consider
* an external authentication authority.
*
* Credits to Rajiv of NetApp for helping with MD5 stuff.
*/
#include "ndmlib.h"
#include "md5.h"
int
ndmmd5_generate_challenge (char challenge[NDMP_MD5_CHALLENGE_LENGTH])
{
int i;
NDMOS_MACRO_SRAND();
for (i = 0; i < NDMP_MD5_CHALLENGE_LENGTH; i++) {
challenge[i] = NDMOS_MACRO_RAND() >> (i&7);
}
return 0;
}
int
ndmmd5_ok_digest (char challenge[NDMP_MD5_CHALLENGE_LENGTH],
char *clear_text_password,
char digest[NDMP_MD5_DIGEST_LENGTH])
{
char my_digest[16];
int i;
ndmmd5_digest (challenge, clear_text_password, my_digest);
for (i = 0; i < NDMP_MD5_DIGEST_LENGTH; i++)
if (digest[i] != my_digest[i])
return 0; /* Invalid */
return 1; /* OK */
}
int
ndmmd5_digest (char challenge[NDMP_MD5_CHALLENGE_LENGTH],
char *clear_text_password,
char digest[NDMP_MD5_DIGEST_LENGTH])
{
int pwlength = strlen (clear_text_password);
MD5_CTX mdContext;
unsigned char message[128];
/*
* The spec describes the construction of the 128 byte
* "message" (probably MD5-speak). It is described as:
*
* PASSWORD PADDING CHALLENGE PADDING PASSWORD
*
* Each PADDING is defined as zeros of length 64 minus pwlen.
*
* A pwlen of over 32 would result in not all fields
* fitting. This begs a question of the order elements
* are inserted into the message[]. You get a different
* message[] if you insert the PASSWORD(s) before
* the CHALLENGE than you get the other way around.
*
* A pwlen of over 64 would result in PADDING of negative
* length, which could cause crash boom bang.
*
* The resolution of this vaguery implemented here is to
* only use the first 32 bytes of the password. All
* fields fit. Order dependencies are avoided.
*
* Final resolution is pending.
*/
if (pwlength > 32)
pwlength = 32;
/*
* Compose the 128-byte buffer according to NDMP rules
*/
NDMOS_API_BZERO (message, sizeof message);
NDMOS_API_BCOPY (clear_text_password, &message[0], pwlength);
NDMOS_API_BCOPY (clear_text_password,
&message[128 - pwlength], pwlength);
NDMOS_API_BCOPY (challenge, &message[64 - pwlength], 64);
/*
* Grind it up, ala MD5
*/
MD5Init(&mdContext);
MD5Update(&mdContext, message, 128);
MD5Final((unsigned char *)digest, &mdContext);
/*
* ding! done
*/
return 0;
}