/*
* Copyright (c) 2000-2001, Boris Popov
* 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, 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
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Boris Popov.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* 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.
*
* $Id: smb_crypt.c,v 1.13 2005/01/26 23:50:50 lindak Exp $
*/
/*
*/
/*
* NTLM support functions
*
* Some code from the driver: smbfs_smb.c, smbfs_crypt.c
*/
#include <ctype.h>
#include <stdlib.h>
#include <strings.h>
#include "smbfs_lib.h"
#include "smbfs_private.h"
#include "smbfs_charsets.h"
#include "smbfs_crypt.h"
#include "smbfs_ntlm.h"
/*
* smbfs_ntlm_compute_lm_hash
*
* Compute an LM hash given a password
*
* Output:
* hash: 16-byte "LanMan" (LM) hash.
* Inputs:
* ucpw: User's password, upper-case UTF-8 string.
*
* Source: Implementing CIFS (Chris Hertel)
*
* P14 = UCPW padded to 14-bytes, or truncated (as needed)
* result = Encrypt(Key=P14, Data=MagicString)
*/
int
{
int err;
char *ucpw;
/* First, convert the p/w to upper case. */
return (ENOMEM);
/* Pad or truncate the upper-case P/W as needed. */
/* Compute the hash. */
return (err);
}
/*
* smbfs_ntlm_compute_nt_hash
*
* Compute an NT hash given a password in UTF-8.
*
* Output:
* hash: 16-byte "NT" hash.
* Inputs:
* upw: User's password, mixed-case UCS-2LE.
* pwlen: Size (in bytes) of upw
*/
int
{
int pwsz;
/* First, convert the password to unicode. */
return (ENOMEM);
/* Compute the hash. */
return (0);
}
/*
* ntlm_v1_response
*
* Create an LM response from the given LM hash and challenge,
* or an NTLM repsonse from a given NTLM hash and challenge.
* Both response types are 24 bytes (NTLM_V1_RESP_SZ)
*/
static int
{
int err;
/*
* 14-byte LM Hash should be padded with 5 nul bytes to create
* a 21-byte string to be used in producing LM response
*/
/* padded LM Hash -> LM Response */
return (err);
}
/*
* Calculate an NTLMv1 session key (16 bytes).
*/
static void
{
}
/*
* Compute both the LM(v1) response and the NTLM(v1) response,
* and put them in the mbdata chains passed. This allocates
* mbuf chains in the output args, which the caller frees.
*/
int
{
int err;
/* Get mbuf chain for the LM response. */
return (err);
/* Get mbuf chain for the NT response. */
return (err);
/*
* Compute the LM response, derived
* from the challenge and the ASCII
* password (if authflags allow).
*/
if (err)
return (err);
/* They asked to send the LM hash too. */
if (err)
return (err);
}
/*
* Compute the NTLM response, derived from
* the challenge and the NT hash.
*/
if (err)
return (err);
/*
* Compute the session key
*/
return (err);
}
/*
* Compute the LM and NTLM responses using NTLM2 session security
* This allocates mbuf chains in the output args, which the caller
* frees.
*/
int
{
int err;
/* Get mbuf chain for the LM response. */
return (err);
/* Get mbuf chain for the NT response. */
return (err);
/*
* Generate the random client nonce
*/
if (err)
return (err);
if (err)
return (err);
/*
* Calculate the NTLM2 NTResponse using the server challenge,
* the client nonce and the nt_hash
*/
if (err)
return (err);
if (err)
return (err);
/*
* Compute the session key
*/
ctx->ct_ssn_key);
return (err);
}
/*
* A variation on HMAC-MD5 known as HMACT64 is used by Windows systems.
* The HMACT64() function is the same as the HMAC-MD5() except that
* it truncates the input key to 64 bytes rather than hashing it down
* to 16 bytes using the MD5() function.
*
* Output: digest (16-bytes)
*/
static void
{
int i;
/* if key is longer than 64 bytes use only the first 64 bytes */
if (key_len > 64)
key_len = 64;
/*
* The HMAC-MD5 (and HMACT64) transform looks like:
*
* MD5(K XOR opad, MD5(K XOR ipad, data))
*
* where K is an n byte key
* ipad is the byte 0x36 repeated 64 times
* opad is the byte 0x5c repeated 64 times
* and data is the data being protected.
*/
/* start out by storing key in pads */
/* XOR key with ipad and opad values */
for (i = 0; i < 64; i++) {
k_ipad[i] ^= 0x36;
k_opad[i] ^= 0x5c;
}
/*
* perform inner MD5
*/
/*
* perform outer MD5
*/
}
/*
* Compute an NTLMv2 hash given the NTLMv1 hash, the user name,
* and the destination (machine or domain name).
*
* Output:
* v2hash: 16-byte NTLMv2 hash.
* Inputs:
* v1hash: 16-byte NTLMv1 hash.
* user: User name, UPPER-case UTF-8 string.
* destination: Domain or server, MIXED-case UTF-8 string.
*/
static int
const char *user, const char *destination)
{
/*
* v2hash = HMACT64(v1hash, 16, concat(upcase(user), dest))
* where "dest" is the domain or server name ("target name")
* Note: user name is converted to upper-case by the caller.
*/
/* utf8data = concat(user, dest) */
goto out;
/* Convert to UCS-2LE */
goto out;
err = 0;
out:
if (ucs2data)
if (utf8data)
return (err);
}
/*
* Compute a partial LMv2 or NTLMv2 response (first 16-bytes).
* The full response is composed by the caller by
* appending the client_data to the returned hash.
*
* Output:
* Inputs:
* v2hash: 16-byte NTLMv2 hash.
* C8: Challenge from server (8 bytes)
* client_data: client nonce (for LMv2) or the
* "blob" from ntlm_build_target_info (NTLMv2)
*/
static int
{
/* data = concat(C8, client_data) */
return (ENOMEM);
return (0);
}
/*
* Calculate an NTLMv2 session key (16 bytes).
*/
static void
{
/* session key uses only 1st 16 bytes of ntresp */
}
/*
* Compute both the LMv2 response and the NTLMv2 response,
* and put them in the mbdata chains passed. This allocates
* mbuf chains in the output args, which the caller frees.
* Also computes the session key.
*/
int
{
int err;
return (err);
return (err);
/*
* Convert the user name to upper-case, as
* that's what's used when computing LMv2
* and NTLMv2 responses. Note that the
* domain name is NOT upper-cased!
*/
goto out;
}
/*
* Compute the NTLMv2 hash
*/
if (err)
goto out;
/*
* Compute the LMv2 response, derived from
* the v2hash, the server challenge, and
* the client nonce (random bits).
*
* We compose it from two parts:
* 1: 16-byte response hash
* 2: Client nonce
*/
if (err)
goto out;
/*
* Compute the NTLMv2 response, derived
* from the server challenge and the
* "target info." blob passed in.
*
* Again composed from two parts:
* 1: 16-byte response hash
* 2: "target info." blob
*/
if (err)
goto out;
/*
* Compute the session key
*/
out:
if (err) {
}
return (err);
}
/*
* Helper for ntlm_build_target_info below.
* Put a name in the NTLMv2 "target info." blob.
*/
static void
{
int nlen;
if (name)
if (ucs)
else
nlen = 0;
if (ucs)
}
/*
* Build an NTLMv2 "target info." blob. When called from NTLMSSP,
* the list of names comes from the Type 2 message. Otherwise,
* we create the name list here.
*/
int
{
int err;
/* Get mbuf chain for the "target info". */
return (err);
/*
* Construct the client nonce by getting
*/
if (err)
goto out;
/*
* Get the "NT time" for the target info header.
*/
(void) gettimeofday(&now, 0);
/*
* Build the "target info." block.
*
* Based on information at:
* http://davenport.sourceforge.net/ntlm.html#theNtlmv2Response
*
* First the fixed-size part.
*/
/*
* Now put the list of names, either from the
* NTLMSSP Type 2 message or composed here.
*/
if (names) {
} else {
/* Get upper-case names. */
goto out;
}
/* OK, that's the whole "target info." blob! */
}
err = 0;
out:
return (err);
}