[dovecot-cvs]
dovecot/src/lib-ntlm .cvsignore, NONE, 1.1 Makefile.am,
NONE, 1.1 hmac-md5.c, NONE, 1.1 hmac-md5.h, NONE,
1.1 ntlm-byteorder.h, NONE, 1.1 ntlm-des.c, NONE,
1.1 ntlm-des.h, NONE, 1.1 ntlm-encrypt.c, NONE,
1.1 ntlm-encrypt.h, NONE, 1.1 ntlm-flags.h, NONE,
1.1 ntlm-message.c, NONE, 1.1 ntlm-message.h, NONE,
1.1 ntlm-types.h, NONE, 1.1 ntlm.h, NONE, 1.1
cras at dovecot.org
cras at dovecot.org
Wed Jul 28 18:39:32 EEST 2004
- Previous message: [dovecot-cvs] dovecot/src/lib Makefile.am, 1.37, 1.38 md4.c, NONE,
1.1 md4.h, NONE, 1.1
- Next message: [dovecot-cvs] dovecot/src/auth Makefile.am, 1.29, 1.30 mech-ntlm.c,
NONE, 1.1 mech.c, 1.28, 1.29 passdb.c, 1.19, 1.20 passdb.h,
1.10, 1.11 password-scheme-ntlm.c, NONE, 1.1 password-scheme.c,
1.10, 1.11 password-scheme.h, 1.4, 1.5
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /home/cvs/dovecot/src/lib-ntlm
In directory talvi:/tmp/cvs-serv28916/src/lib-ntlm
Added Files:
.cvsignore Makefile.am hmac-md5.c hmac-md5.h ntlm-byteorder.h
ntlm-des.c ntlm-des.h ntlm-encrypt.c ntlm-encrypt.h
ntlm-flags.h ntlm-message.c ntlm-message.h ntlm-types.h ntlm.h
Log Message:
NTLM authentication. Patch by Andrey Panin
--- NEW FILE: .cvsignore ---
*.la
*.lo
*.o
.deps
.libs
Makefile
Makefile.in
so_locations
--- NEW FILE: Makefile.am ---
noinst_LIBRARIES = libntlm.a
INCLUDES = \
-I$(top_srcdir)/src/lib
libntlm_a_SOURCES = \
hmac-md5.c \
ntlm-des.c \
ntlm-encrypt.c \
ntlm-message.c
noinst_HEADERS = \
hmac-md5.h \
ntlm.h \
ntlm-types.h \
ntlm-flags.h \
ntlm-byteorder.h \
ntlm-des.h \
ntlm-encrypt.h \
ntlm-message.h
--- NEW FILE: hmac-md5.c ---
/*
* HMAC-MD5 (RFC-2104) implementation.
*
* Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include "lib.h"
#include "hmac-md5.h"
void hmac_md5_init(struct hmac_md5_context *ctx,
const unsigned char * key, size_t key_len)
{
int i;
unsigned char md5key[16];
if (key_len > 64) {
md5_get_digest(key, key_len, md5key);
key = md5key;
key_len = 16;
}
memcpy(ctx->k_ipad, key, key_len);
memset(ctx->k_ipad + key_len, 0, 64 - key_len);
memcpy(ctx->k_opad, ctx->k_ipad, 64);
for (i = 0; i < 64; i++) {
ctx->k_ipad[i] ^= 0x36;
ctx->k_opad[i] ^= 0x5c;
}
md5_init(&ctx->ctx);
md5_update(&ctx->ctx, ctx->k_ipad, 64);
}
void hmac_md5_final(struct hmac_md5_context *ctx, unsigned char *digest)
{
md5_final(&ctx->ctx, digest);
md5_init(&ctx->ctx);
md5_update(&ctx->ctx, ctx->k_opad, 64);
md5_update(&ctx->ctx, digest, 16);
md5_final(&ctx->ctx, digest);
}
--- NEW FILE: hmac-md5.h ---
#ifndef __HMAC_MD5_H__
#define __HMAC_MD5_H__
#include "md5.h"
struct hmac_md5_context {
struct md5_context ctx;
unsigned char k_ipad[64];
unsigned char k_opad[64];
};
void hmac_md5_init(struct hmac_md5_context *ctx, const unsigned char* key, size_t key_len);
void hmac_md5_final(struct hmac_md5_context *ctx, unsigned char *digest);
static inline void
hmac_md5_update(struct hmac_md5_context *ctx, const void * data, size_t size)
{
md5_update(&ctx->ctx, data, size);
}
#endif /* __HMAC_MD5_H__ */
--- NEW FILE: ntlm-byteorder.h ---
/*
* Little-endian data access functions.
*
* Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __NTLM_BYTEORDER_H__
#define __NTLM_BYTEORDER_H__
#if defined(__i386__) || defined(__vax__)
static inline uint16_t read_le16(const void *addr)
{
return *((uint16_t *) addr);
}
static inline uint32_t read_le32(const void *addr)
{
return *((uint32_t *) addr);
}
static inline uint64_t read_le64(const void *addr)
{
return *((uint64_t *) addr);
}
static inline void write_le16(void *addr, const uint16_t value)
{
*((uint16_t *) addr) = value;
}
static inline void write_le32(void *addr, const uint32_t value)
{
*((uint32_t *) addr) = value;
}
static inline void write_le64(void *addr, const uint64_t value)
{
*((uint64_t *) addr) = value;
}
#else
/*
* Dumb and slow, but byteorder and alignment independent code.
*/
#define readb(addr, pos, type) ((type)(*(((uint8_t *) (addr)) + (pos))))
static inline uint16_t read_le16(const void *addr)
{
return readb(addr, 0, uint16_t) | (readb(addr, 1, uint16_t) << 8);
}
static inline uint32_t read_le32(const void *addr)
{
return readb(addr, 0, uint32_t) |
(readb(addr, 1, uint32_t) << 8) |
(readb(addr, 2, uint32_t) << 16) |
(readb(addr, 3, uint32_t) << 24);
}
static inline uint64_t read_le64(const void *addr)
{
return readb(addr, 0, uint64_t) |
(readb(addr, 1, uint64_t) << 8) |
(readb(addr, 2, uint64_t) << 16) |
(readb(addr, 3, uint64_t) << 24) |
(readb(addr, 4, uint64_t) << 32) |
(readb(addr, 5, uint64_t) << 40) |
(readb(addr, 6, uint64_t) << 48) |
(readb(addr, 7, uint64_t) << 56);
}
#define writeb(addr, pos, value) \
*(((uint8_t *)(addr)) + (pos)) = (uint8_t) (value)
static inline void write_le16(void *addr, const uint16_t value)
{
writeb(addr, 0, value & 0xff);
writeb(addr, 1, (value >> 8) & 0xff);
}
static inline void write_le32(void *addr, const uint32_t value)
{
writeb(addr, 0, value & 0xff);
writeb(addr, 1, (value >> 8) & 0xff);
writeb(addr, 2, (value >> 16) & 0xff);
writeb(addr, 3, (value >> 24) & 0xff);
}
static inline void write_le64(void *addr, const uint64_t value)
{
writeb(addr, 0, value & 0xff);
writeb(addr, 1, (value >> 8) & 0xff);
writeb(addr, 2, (value >> 16) & 0xff);
writeb(addr, 3, (value >> 24) & 0xff);
writeb(addr, 4, (value >> 32) & 0xff);
writeb(addr, 5, (value >> 40) & 0xff);
writeb(addr, 6, (value >> 48) & 0xff);
writeb(addr, 7, (value >> 56) & 0xff);
}
#endif
#endif /* __NTLM_BYTEORDER_H__ */
--- NEW FILE: ntlm-des.c ---
/*
* Implements DES encryption, but not decryption.
* DES is used to create LM password hashes and both LM and NTLM Responses.
*
* Copyright (C) 2003, 2004 by Christopher R. Hertel <crh at ubiqx.mn.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*
* Notes:
*
* This implementation was created by studying many existing examples
* found in Open Source, in the public domain, and in various documentation.
* The SMB protocol makes minimal use of the DES function, so this is a
* minimal implementation. That which is not required has been removed.
*
* The SMB protocol uses the DES algorithm as a hash function, not an
* encryption function. The auth_DEShash() implemented here is a one-way
* function. The reverse is not implemented in this module. Also, there
* is no attempt at making this either fast or efficient. There is no
* need, as the auth_DEShash() function is used for generating the LM
* Response from a 7-byte key and an 8-byte challenge. It is not intended
* for use in encrypting large blocks of data or data streams.
*
* As stated above, this implementation is based on studying existing work
* in the public domain or under Open Source (specifically LGPL) license.
* The code, however, is written from scratch. Obviously, I make no claim
* with regard to those earlier works (except to claim that I am grateful
* to the previous implementors whose work I studied). See the list of
* references below for resources I used.
*
* References:
* I read through the libmcrypt code to see how they put the pieces
* together. See: http://mcrypt.hellug.gr/
* Libmcrypt is available under the terms of the LGPL.
*
* The libmcrypt implementation includes the following credits:
* written 12 Dec 1986 by Phil Karn, KA9Q; large sections adapted
* from the 1977 public-domain program by Jim Gillogly
* Modified for additional speed - 6 December 1988 Phil Karn
* Modified for parameterized key schedules - Jan 1991 Phil Karn
* modified in order to use the libmcrypt API by Nikos Mavroyanopoulos
* All modifications are placed under the license of libmcrypt.
*
* See also Phil Karn's privacy and security page:
* http://www.ka9q.net/privacy.html
*
* I relied heavily upon:
* Applied Cryptography, Second Edition:
* Protocols, Algorithms, and Source Code in C
* by Bruce Schneier. ISBN 0-471-11709-9, John Wiley & Sons, Inc., 1996
* Particularly Chapter 12.
*
* Here's one more DES resource, which I found quite helpful (aside from
* the Clinton jokes):
* http://www.aci.net/kalliste/des.htm
*
* Finally, the use of DES in SMB is covered in:
* Implementing CIFS - the Common Internet File System
* by your truly. ISBN 0-13-047116-X, Prentice Hall PTR., August 2003
* Section 15.3, in particular.
* (Online at: http://ubiqx.org/cifs/SMB.html#SMB.8.3)
*/
#include "ntlm-des.h"
/*
* Initial permutation map.
* In the first step of DES, the bits of the initial plaintext are rearranged
* according to the map given below. This map and those like it are read by
* the permute() function (below) which uses the maps as a guide when moving
* bits from one place to another.
*
* Note that the values here are all one less than those shown in Schneier.
* That's because C likes to start counting from 0, not 1.
*
* According to Schneier (Ch12, pg 271), the purpose of the initial
* permutation was to make it easier to load plaintext and ciphertext into
* a DES ecryption chip. I have no idea why that would be the case.
*/
static const unsigned char InitialPermuteMap[64] = {
57, 49, 41, 33, 25, 17, 9, 1,
59, 51, 43, 35, 27, 19, 11, 3,
61, 53, 45, 37, 29, 21, 13, 5,
63, 55, 47, 39, 31, 23, 15, 7,
56, 48, 40, 32, 24, 16, 8, 0,
58, 50, 42, 34, 26, 18, 10, 2,
60, 52, 44, 36, 28, 20, 12, 4,
62, 54, 46, 38, 30, 22, 14, 6
};
/*
* Key permutation map.
* Like the input data and encryption result, the key is permuted before
* the algorithm really gets going. The original algorithm called for an
* eight-byte key in which each byte contained a parity bit. During the
* key permutiation, the parity bits were discarded. The DES algorithm,
* as used with SMB, does not make use of the parity bits. Instead, SMB
* passes 7-byte keys to DES. For DES implementations that expect parity,
* the parity bits must be added. In this case, however, we're just going
* to start with a 7-byte (56 bit) key. KeyPermuteMap, below, is adjusted
* accordingly and, of course, each entry in the map is reduced by 1 with
* respect to the documented values because C likes to start counting from
* 0, not 1.
*/
static const unsigned char KeyPermuteMap[56] = {
49, 42, 35, 28, 21, 14, 7, 0,
50, 43, 36, 29, 22, 15, 8, 1,
51, 44, 37, 30, 23, 16, 9, 2,
52, 45, 38, 31, 55, 48, 41, 34,
27, 20, 13, 6, 54, 47, 40, 33,
26, 19, 12, 5, 53, 46, 39, 32,
25, 18, 11, 4, 24, 17, 10, 3
};
/*
* Key rotation table.
* At the start of each round of encryption, the key is split and each
* 28-bit half is rotated left. The number of bits of rotation per round
* is given in the table below.
*/
static const unsigned char KeyRotation[16] = {
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
};
/*
* Key compression table.
* This table is used to select 48 of the 56 bits of the key.
* The left and right halves of the source text are each 32 bits,
* but they are expanded to 48 bits and the results are XOR'd
* against the compressed (48-bit) key.
*/
static const unsigned char KeyCompression[48] = {
13, 16, 10, 23, 0, 4, 2, 27,
14, 5, 20, 9, 22, 18, 11, 3,
25, 7, 15, 6, 26, 19, 12, 1,
40, 51, 30, 36, 46, 54, 29, 39,
50, 44, 32, 47, 43, 48, 38, 55,
33, 52, 45, 41, 49, 35, 28, 31
};
/*
* Data expansion table.
* This table is used after the data block (64-bits) has been split
* into two 32-bit (4-byte) halves (generally denoted L and R).
* Each 32-bit half is "expanded", using this table, to a 48 bit
* data block, which is then XOR'd with the 48 bit subkey for the
* round.
*/
static const unsigned char DataExpansion[48] = {
31, 0, 1, 2, 3, 4, 3, 4,
5, 6, 7, 8, 7, 8, 9, 10,
11, 12, 11, 12, 13, 14, 15, 16,
15, 16, 17, 18, 19, 20, 19, 20,
21, 22, 23, 24, 23, 24, 25, 26,
27, 28, 27, 28, 29, 30, 31, 0
};
/*
* The (in)famous S-boxes.
* These are used to perform substitutions.
* Six bits worth of input will return four bits of output.
* The four bit values are stored in these tables. Each table has
* 64 entries...and 6 bits provides a number between 0 and 63.
* There are eight S-boxes, one per 6 bits of a 48-bit value.
* Thus, 48 bits are reduced to 32 bits. Obviously, this step
* follows the DataExpansion step.
*
* Note that the literature generally shows this as 8 arrays each
* with four rows and 16 colums. There is a complex formula for
* mapping the 6 bit input values to the correct row and column.
* I've pre-computed that mapping, and the tables below provide
* direct 6-bit input to 4-bit output. See pp 274-274 in Schneier.
*/
static const unsigned char sbox[8][64] = {
{ /* S0 */
14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
3, 10, 10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13
},
{ /* S1 */
15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9
},
{ /* S2 */
10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12
},
{ /* S3 */
7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14
},
{ /* S4 */
2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3
},
{ /* S5 */
12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13
},
{ /* S6 */
4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12
},
{ /* S7 */
13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
}
};
/*
* P-Box permutation.
* This permutation is applied to the result of the S-Box Substitutions.
* It's a straight-forward re-arrangement of the bits.
*/
static const unsigned char pbox[32] = {
15, 6, 19, 20, 28, 11, 27, 16,
0, 14, 22, 25, 4, 17, 30, 9,
1, 7, 23, 13, 31, 26, 2, 8,
18, 12, 29, 5, 21, 10, 3, 24
};
/*
* Final permutation map.
* This is supposed to be the inverse of the Initial Permutation,
* but there's been a bit of fiddling done.
* As always, the values given are one less than those in the literature
* (because C starts counting from 0, not 1). In addition, the penultimate
* step in DES is to swap the left and right hand sides of the ciphertext.
* The inverse of the Initial Permutation is then applied to produce the
* final result.
* To save a step, the map below does the left/right swap as well as the
* inverse permutation.
*/
static const unsigned char FinalPermuteMap[64] = {
7, 39, 15, 47, 23, 55, 31, 63,
6, 38, 14, 46, 22, 54, 30, 62,
5, 37, 13, 45, 21, 53, 29, 61,
4, 36, 12, 44, 20, 52, 28, 60,
3, 35, 11, 43, 19, 51, 27, 59,
2, 34, 10, 42, 18, 50, 26, 58,
1, 33, 9, 41, 17, 49, 25, 57,
0, 32, 8, 40, 16, 48, 24, 56
};
/*
* Macros:
*
* CLRBIT( STR, IDX )
* Input: STR - (uchar *) pointer to an array of 8-bit bytes.
* IDX - (int) bitwise index of a bit within the STR array
* that is to be cleared (that is, given a value of 0).
* Notes: This macro clears a bit within an array of bits (which is
* built within an array of bytes).
* - The macro converts to an assignment of the form A &= B.
* - The string of bytes is viewed as an array of bits, read from
* highest order bit first. The highest order bit of a byte
* would, therefore, be bit 0 (within that byte).
*
* SETBIT( STR, IDX )
* Input: STR - (uchar *) pointer to an array of 8-bit bytes.
* IDX - (int) bitwise index of a bit within the STR array
* that is to be set (that is, given a value of 1).
* Notes: This macro sets a bit within an array of bits (which is
* built within an array of bytes).
* - The macro converts to an assignment of the form A |= B.
* - The string of bytes is viewed as an array of bits, read from
* highest order bit first. The highest order bit of a byte
* would, therefore, be bit 0 (within that byte).
*
* GETBIT( STR, IDX )
* Input: STR - (uchar *) pointer to an array of 8-bit bytes.
* IDX - (int) bit-wise index of a bit within the STR array
* that is to be read.
* Output: True (1) if the indexed bit was set, else false (0).
*/
#define CLRBIT(STR, IDX) ((STR)[(IDX)/8] &= ~(0x01 << (7 - ((IDX)%8))))
#define SETBIT( STR, IDX ) ( (STR)[(IDX)/8] |= (0x01 << (7 - ((IDX)%8))) )
#define GETBIT( STR, IDX ) (( ((STR)[(IDX)/8]) >> (7 - ((IDX)%8)) ) & 0x01)
/*
* Performs a DES permutation, which re-arranges the bits in an array of
* bytes.
*
* Input: dst - Destination into which to put the re-arranged bits.
* src - Source from which to read the bits.
* map - Permutation map.
* mapsize - Number of bytes represented by the <map>. This also
* represents the number of bytes to be copied to <dst>.
*
* Output: none.
*
* Notes: <src> and <dst> must not point to the same location.
*
* - No checks are done to ensure that there is enough room
* in <dst>, or that the bit numbers in <map> do not exceed
* the bits available in <src>. A good reason to make this
* function static (private).
*
* - The <mapsize> value is in bytes. All permutations in DES
* use tables that are a multiple of 8 bits, so there is no
* need to handle partial bytes. (Yes, I know that there
* are some machines out there that still use bytes of a size
* other than 8 bits. For our purposes we'll stick with 8-bit
* bytes.)
*/
static void
permute(unsigned char *dst, const unsigned char *src,
const unsigned char * map, const int mapsize)
{
int bitcount;
int i;
/* Clear all bits in the destination. */
for (i = 0; i < mapsize; i++)
dst[i] = 0;
/* Set destination bit if the mapped source bit it set. */
bitcount = mapsize * 8;
for (i = 0; i < bitcount; i++) {
if (GETBIT(src, map[i]))
SETBIT(dst, i);
}
}
/*
* Split the 56-bit key in half & left rotate each half by <numbits> bits.
*
* Input: key - The 56-bit key to be split-rotated.
* numbits - The number of bits by which to rotate the key.
*
* Output: none.
*
* Notes: There are probably several better ways to implement this.
*/
static void
keyshift(unsigned char *key, const int numbits)
{
int i;
unsigned char keep = key[0]; /* Copy the highest order bits of the key. */
/* Repeat the shift process <numbits> times. */
for (i = 0; i < numbits; i++) {
int j;
/* Shift the entire thing, byte by byte.
*/
for (j = 0; j < 7; j++) {
if (j && (key[j] & 0x80)) /* If the top bit of this byte is set. */
key[j - 1] |= 0x01; /* ...shift it to last byte's low bit. */
key[j] <<= 1; /* Then left-shift the whole byte. */
}
/* Now move the high-order bits of each 28-bit half-key to their
* correct locations.
* Bit 27 is the lowest order bit of the first half-key.
* Before the shift, it was the highest order bit of the 2nd half-key.
*/
if (GETBIT(key, 27)) { /* If bit 27 is set... */
CLRBIT(key, 27); /* ...clear bit 27. */
SETBIT(key, 55); /* ...set lowest order bit of 2nd half-key. */
}
/* We kept the highest order bit of the first half-key in <keep>.
* If it's set, copy it to bit 27.
*/
if (keep & 0x80)
SETBIT(key, 27);
/* Rotate the <keep> byte too, in case <numbits> is 2 and there's
* a second round coming.
*/
keep <<= 1;
}
}
/*
* Perform S-Box substitutions.
*
* Input: dst - Destination byte array into which the S-Box substituted
* bitmap will be written.
* src - Source byte array.
*
* Output: none.
*
* Notes: It's really not possible (for me, anyway) to understand how
* this works without reading one or more detailed explanations.
* Quick overview, though:
*
* After the DataExpansion step (in which a 32-bit bit array is
* expanded to a 48-bit bit array) the expanded data block is
* XOR'd with 48-bits worth of key. That 48 bits then needs to
* be condensed back into 32 bits.
*
* The S-Box substitution handles the data reduction by breaking
* the 48-bit value into eight 6-bit values. For each of these
* 6-bit values there is a table (an S-Box table). The table
* contains 64 possible values. Conveniently, a 6-bit integer
* can represent a value between 0 and 63.
*
* So, if you think of the 48-bit bit array as an array of 6-bit
* integers, you use S-Box table 0 with the 0th 6-bit value.
* Table 1 is used with the 6-bit value #1, and so on until #7.
* Within each table, the correct substitution is found based
* simply on the value of the 6-bit integer.
*
* Well, the original algorithm (and most documentation) don't
* make it so simple. There's a complex formula for mapping
* the 6-bit values to the correct substitution. Fortunately,
* those lookups can be precomputed (and have been for this
* implementation). See pp 274-274 in Schneier.
*
* Oh, and the substitute values are all 4-bit values, so each
* 6-bits gets reduced to 4-bits resulting in a 32-bit bit array.
*/
static void
s_box(unsigned char *dst, const unsigned char *src)
{
int i;
/* Clear the destination array. */
for (i = 0; i < 4; i++)
dst[i] = 0;
/* For each set of six input bits... */
for (i = 0; i < 8; i++) {
int j;
int Snum;
int bitnum;
/* Extract the 6-bit integer from the source.
* This will be the lookup key within the sbox[i] array.
*/
for (Snum = j = 0, bitnum = (i * 6); j < 6; j++, bitnum++) {
Snum <<= 1;
Snum |= GETBIT(src, bitnum);
}
/* Find the correct value in the correct sbox[]
* and copy it into the destination.
* Left shift the nibble four bytes for even values of <i>.
*/
if (0 == (i % 2))
dst[i / 2] |= ((sbox[i][Snum]) << 4);
else
dst[i / 2] |= sbox[i][Snum];
}
}
/*
* Perform an XOR operation on two byte arrays.
*
* Input: dst - Destination array to which the result will be written.
* a - The first string of bytes.
* b - The second string of bytes.
* count - Number of bytes to XOR against one another.
*
* Output: none.
*
* Notes: This function operates on whole byte chunks. There's no need
* to XOR partial bytes so no need to write code to handle it.
*
* - This function essentially implements dst = a ^ b; for byte
* arrays.
*
* - <dst> may safely point to the same location as <a> or <b>.
*/
static void xor(unsigned char *dst, const unsigned char *a,
const unsigned char *b, const int count)
{
int i;
for (i = 0; i < count; i++)
dst[i] = a[i] ^ b[i];
}
/*
* DES encryption of the input data using the input key.
*
* Input: dst - Destination buffer. It *must* be at least eight bytes
* in length, to receive the encrypted result.
* key - Encryption key. Exactly seven bytes will be used.
* If your key is shorter, ensure that you pad it to seven
* bytes.
* src - Source data to be encrypted. Exactly eight bytes will
* be used. If your source data is shorter, ensure that
* you pad it to eight bytes.
*
* Output: A pointer to the encrpyted data (same as <dst>).
*
* Notes: In SMB, the DES function is used as a hashing function rather
* than an encryption/decryption tool. When used for generating
* the LM hash the <src> input is the known value "KGS!@#$%" and
* the key is derived from the password entered by the user.
* When used to generate the LM or NTLM response, the <key> is
* derived from the LM or NTLM hash, and the challenge is used
* as the <src> input.
* See: http://ubiqx.org/cifs/SMB.html#SMB.8.3
*
* - This function is called "DEShash" rather than just "DES"
* because it is only used for creating LM hashes and the
* LM/NTLM responses. For all practical purposes, however, it
* is a full DES encryption implementation.
*
* - This DES implementation does not need to be fast, nor is a
* DES decryption function needed. The goal is to keep the
* code small, simple, and well documented.
*
* - The input values are copied and refiddled within the module
* and the result is not written to <dst> until the very last
* step, so it's okay if <dst> points to the same memory as
* <key> or <src>.
*/
unsigned char *
deshash(unsigned char *dst, const unsigned char *key,
const unsigned char *src)
{
int i; /* Loop counter. */
unsigned char K[7]; /* Holds the key, as we manipulate it. */
unsigned char D[8]; /* The data block, as we manipulate it. */
/* Create the permutations of the key and the source. */
permute(K, key, KeyPermuteMap, 7);
permute(D, src, InitialPermuteMap, 8);
/* DES encryption proceeds in 16 rounds.
* The stuff inside the loop is known in the literature as "function f".
*/
for (i = 0; i < 16; i++) {
int j;
unsigned char *L = D; /* The left 4 bytes (half) of the data block. */
unsigned char *R = &(D[4]); /* The right half of the ciphertext block. */
unsigned char Rexp[6]; /* Expanded right half. */
unsigned char Rn[4]; /* New value of R, as we manipulate it. */
unsigned char SubK[6]; /* The 48-bit subkey. */
/* Generate the subkey for this round. */
keyshift(K, KeyRotation[i]);
permute(SubK, K, KeyCompression, 6);
/* Expand the right half (R) of the data block to 48 bytes,
* then XOR the result with the Subkey for this round.
*/
permute(Rexp, R, DataExpansion, 6);
xor(Rexp, Rexp, SubK, 6);
/* S-Box substitutions, P-Box permutation, and final XOR.
* The S-Box substitutions return a 32-bit value, which is then
* run through the 32-bit to 32-bit P-Box permutation. The P-Box
* result is then XOR'd with the left-hand half of the key.
* (Rexp is used as a temporary variable between the P-Box & XOR).
*/
s_box(Rn, Rexp);
permute(Rexp, Rn, pbox, 4);
xor(Rn, L, Rexp, 4);
/* The previous R becomes the new L,
* and Rn is moved into R ready for the next round.
*/
for (j = 0; j < 4; j++) {
L[j] = R[j];
R[j] = Rn[j];
}
}
/* The encryption is complete.
* Now reverse-permute the ciphertext to produce the final result.
* We actually combine two steps here. The penultimate step is to
* swap the positions of L and R in the result of the 16 rounds,
* after which the reverse of the Initial Permutation is applied.
* To save a step, the FinalPermuteMap applies both the L/R swap
* and the inverse of the Initial Permutation.
*/
permute(dst, D, FinalPermuteMap, 8);
return dst;
}
--- NEW FILE: ntlm-des.h ---
#ifndef __NTLM_DES_H__
#define __NTLM_DES_H__
unsigned char * deshash(unsigned char *dst, const unsigned char *key,
const unsigned char *src);
#endif /* __NTLM_DES_H__ */
--- NEW FILE: ntlm-encrypt.c ---
/*
* NTLM and NTLMv2 hash generation.
*
* Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <ctype.h>
#include "lib.h"
#include "buffer.h"
#include "compat.h"
#include "safe-memset.h"
#include "md4.h"
#include "hmac-md5.h"
#include "ntlm.h"
#include "ntlm-des.h"
static unsigned char *
t_unicode_str(const char *src, int ucase, size_t *size)
{
buffer_t *wstr;
wstr = buffer_create_dynamic(unsafe_data_stack_pool, 32, (size_t)-1);
for ( ; *src; src++) {
buffer_append_c(wstr, ucase ? i_toupper(*src) : *src);
buffer_append_c(wstr, '\0');
}
*size = buffer_get_used_size(wstr);
return buffer_free_without_data(wstr);
}
static void
ntlmssp_des_encrypt_triad(const unsigned char *hash,
const unsigned char *challenge,
unsigned char *response)
{
deshash(response, hash, challenge);
deshash(response + 8, hash + 7, challenge);
deshash(response + 16, hash + 14, challenge);
}
const unsigned char *
ntlm_v1_hash(const char *passwd, unsigned char hash[NTLMSSP_HASH_SIZE])
{
size_t len;
void *wpwd = t_unicode_str(passwd, 0, &len);
md4_get_digest(wpwd, len, hash);
safe_memset(wpwd, 0, len);
return hash;
}
static void
hmac_md5_ucs2le_string_ucase(struct hmac_md5_context *ctx, const char *str)
{
size_t len;
unsigned char *wstr = t_unicode_str(str, 1, &len);
hmac_md5_update(ctx, wstr, len);
}
static void
ntlm_v2_hash(const char *user, const char *target,
const unsigned char *hash_v1,
unsigned char hash[NTLMSSP_V2_HASH_SIZE])
{
struct hmac_md5_context ctx;
hmac_md5_init(&ctx, hash_v1, NTLMSSP_HASH_SIZE);
hmac_md5_ucs2le_string_ucase(&ctx, user);
if (target)
hmac_md5_ucs2le_string_ucase(&ctx, target);
hmac_md5_final(&ctx, hash);
}
void
ntlmssp_v1_response(const unsigned char *hash,
const unsigned char *challenge,
unsigned char response[NTLMSSP_RESPONSE_SIZE])
{
unsigned char des_hash[NTLMSSP_DES_KEY_LENGTH * 3];
memcpy(des_hash, hash, NTLMSSP_HASH_SIZE);
memset(des_hash + NTLMSSP_HASH_SIZE, 0,
sizeof(des_hash) - NTLMSSP_HASH_SIZE);
ntlmssp_des_encrypt_triad(des_hash, challenge, response);
}
void
ntlmssp_v2_response(const char *user, const char *target,
const unsigned char *hash_v1,
const unsigned char *challenge,
const unsigned char *blob, size_t blob_size,
unsigned char response[NTLMSSP_V2_RESPONSE_SIZE])
{
struct hmac_md5_context ctx;
unsigned char hash[NTLMSSP_V2_HASH_SIZE];
ntlm_v2_hash(user, target, hash_v1, hash);
hmac_md5_init(&ctx, hash, NTLMSSP_V2_HASH_SIZE);
hmac_md5_update(&ctx, challenge, NTLMSSP_CHALLENGE_SIZE);
hmac_md5_update(&ctx, blob, blob_size);
hmac_md5_final(&ctx, response);
}
--- NEW FILE: ntlm-encrypt.h ---
#ifndef __NTLM_ENCRYPT__
#define __NTLM_ENCRYPT__
const unsigned char *
ntlm_v1_hash(const char *passwd, unsigned char hash[NTLMSSP_HASH_SIZE]);
void ntlmssp_v1_response(const unsigned char *hash,
const unsigned char *challenge,
unsigned char response[NTLMSSP_RESPONSE_SIZE]);
void ntlmssp_v2_response(const char *user, const char *target,
const unsigned char *hash_v1,
const unsigned char *challenge,
const unsigned char *blob, size_t blob_size,
unsigned char response[NTLMSSP_V2_RESPONSE_SIZE]);
#endif /* __NTLM_ENCRYPT__ */
--- NEW FILE: ntlm-flags.h ---
/*
* NTLM message flags.
*
* Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*/
#ifndef __NTLM_FLAGS_H__
#define __NTLM_FLAGS_H__
/*
* Indicates that Unicode strings are supported for use in security
* buffer data.
*/
#define NTLMSSP_NEGOTIATE_UNICODE 0x00000001
/*
* Indicates that OEM strings are supported for use in security buffer data.
*/
#define NTLMSSP_NEGOTIATE_OEM 0x00000002
/*
* Requests that the server's authentication realm be included in the
* Type 2 message.
*/
#define NTLMSSP_REQUEST_TARGET 0x00000004
/*
* Specifies that authenticated communication between the client and server
* should carry a digital signature (message integrity).
*/
#define NTLMSSP_NEGOTIATE_SIGN 0x00000010
/*
* Specifies that authenticated communication between the client and server
* should be encrypted (message confidentiality).
*/
#define NTLMSSP_NEGOTIATE_SEAL 0x00000020
/*
* Indicates that datagram authentication is being used.
*/
#define NTLMSSP_NEGOTIATE_DATAGRAM 0x00000040
/*
* Indicates that the LAN Manager session key should be
* used for signing and sealing authenticated communications.
*/
#define NTLMSSP_NEGOTIATE_LM_KEY 0x00000080
/*
* Indicates that NTLM authentication is being used.
*/
#define NTLMSSP_NEGOTIATE_NTLM 0x00000200
/*
* Sent by the client in the Type 1 message to indicate that the name of the
* domain in which the client workstation has membership is included in the
* message. This is used by the server to determine whether the client is
* eligible for local authentication.
*/
#define NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED 0x00001000
/*
* Sent by the client in the Type 1 message to indicate that the client
* workstation's name is included in the message. This is used by the server
* to determine whether the client is eligible for local authentication.
*/
#define NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED 0x00002000
/*
* Sent by the server to indicate that the server and client are on the same
* machine. Implies that the client may use the established local credentials
* for authentication instead of calculating a response to the challenge.
*/
#define NTLMSSP_NEGOTIATE_LOCAL_CALL 0x00004000
/*
* Indicates that authenticated communication between the client and server
* should be signed with a "dummy" signature.
*/
#define NTLMSSP_NEGOTIATE_ALWAYS_SIGN 0x00008000
/*
* Sent by the server in the Type 2 message to indicate that the target
* authentication realm is a domain.
*/
#define NTLMSSP_TARGET_TYPE_DOMAIN 0x00010000
/*
* Sent by the server in the Type 2 message to indicate that the target
* authentication realm is a server.
*/
#define NTLMSSP_TARGET_TYPE_SERVER 0x00020000
/*
* Sent by the server in the Type 2 message to indicate that the target
* authentication realm is a share. Presumably, this is for share-level
* authentication. Usage is unclear.
*/
#define NTLMSSP_TARGET_TYPE_SHARE 0x00040000
/*
* Indicates that the NTLM2 signing and sealing scheme should be used for
* protecting authenticated communications. Note that this refers to a
* particular session security scheme, and is not related to the use of
* NTLMv2 authentication.
*/
#define NTLMSSP_NEGOTIATE_NTLM2 0x00080000
/*
* Sent by the server in the Type 2 message to indicate that it is including
* a Target Information block in the message. The Target Information block
* is used in the calculation of the NTLMv2 response.
*/
#define NTLMSSP_NEGOTIATE_TARGET_INFO 0x00800000
/*
* Indicates that 128-bit encryption is supported.
*/
#define NTLMSSP_NEGOTIATE_128 0x20000000
/*
* Indicates that the client will provide an encrypted master session key in
* the "Session Key" field of the Type 3 message. This is used in signing and
* sealing, and is RC4-encrypted using the previous session key as the
* encryption key.
*/
#define NTLMSSP_NEGOTIATE_KEY_EXCHANGE 0x40000000
/*
* Indicates that 56-bit encryption is supported.
*/
#define NTLMSSP_NEGOTIATE_56 0x80000000
#endif /* __NTLM_FLAGS_H__ */
--- NEW FILE: ntlm-message.c ---
/*
* NTLM message handling.
*
* Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <stdarg.h>
#include <ctype.h>
#include "lib.h"
#include "str.h"
#include "buffer.h"
#include "hostpid.h"
#include "randgen.h"
#include "ntlm.h"
#include "ntlm-message.h"
const char * __ntlmssp_t_str(const void *message, struct ntlmssp_buffer *buffer)
{
unsigned int len = read_le16(&buffer->length) / sizeof(ucs2le_t);
string_t *str = t_str_new(len / 2);
const char *p = ((char *) message) + read_le32(&buffer->offset);
while (len-- > 0) {
str_append_c(str, *p & 0x7f);
p += sizeof(ucs2le_t);
}
return str_c(str);
}
static unsigned int append_string(buffer_t *buf, const char *str, int ucase)
{
unsigned int length = 0;
for ( ; *str; str++) {
buffer_append_c(buf, ucase ? toupper(*str) : *str);
buffer_append_c(buf, 0);
length += sizeof(ucs2le_t);
}
return length;
}
static void ntlmssp_append_string(buffer_t *buf, size_t buffer_offset,
const char *str)
{
struct ntlmssp_buffer buffer;
unsigned int length;
write_le32(&buffer.offset, buffer_get_used_size(buf));
length = append_string(buf, str, 0);
write_le16(&buffer.length, length);
write_le16(&buffer.space, length);
buffer_write(buf, buffer_offset, &buffer, sizeof(buffer));
}
static void ntlmssp_append_target_info(buffer_t *buf, size_t buffer_offset, ...)
{
struct ntlmssp_v2_target_info info;
struct ntlmssp_buffer buffer;
va_list args;
unsigned int length, total_length = 0;
int type;
write_le32(&buffer.offset, buffer_get_used_size(buf));
va_start(args, buffer_offset);
do {
type = va_arg(args, int);
const char *data;
memset(&info, 0, sizeof(info));
write_le16(&info.type, type);
switch (type) {
case NTPLMSSP_V2_TARGET_END:
buffer_append(buf, &info, sizeof(info));
length = sizeof(info);
break;
case NTPLMSSP_V2_TARGET_SERVER:
case NTPLMSSP_V2_TARGET_DOMAIN:
case NTPLMSSP_V2_TARGET_FQDN:
case NTPLMSSP_V2_TARGET_DNS:
data = va_arg(args, char *);
write_le16(&info.length,
strlen(data) * sizeof(ucs2le_t));
buffer_append(buf, &info, sizeof(info));
length = append_string(buf, data, 0);
break;
default:
i_panic("Invalid NTLM target info block type "
"%u", type);
}
total_length += length;
} while (type != NTPLMSSP_V2_TARGET_END);
va_end(args);
write_le16(&buffer.length, total_length);
write_le16(&buffer.space, total_length);
buffer_write(buf, buffer_offset, &buffer, sizeof(buffer));
}
static inline uint32_t ntlmssp_flags(uint32_t client_flags)
{
uint32_t flags = NTLMSSP_NEGOTIATE_UNICODE |
NTLMSSP_NEGOTIATE_NTLM |
NTLMSSP_NEGOTIATE_TARGET_INFO;
if (client_flags & NTLMSSP_REQUEST_TARGET)
flags |= NTLMSSP_REQUEST_TARGET | NTLMSSP_TARGET_TYPE_SERVER;
return flags;
}
const struct ntlmssp_challenge *
ntlmssp_create_challenge(pool_t pool, const struct ntlmssp_request *request,
size_t *size)
{
buffer_t *buf;
uint32_t flags = ntlmssp_flags(read_le32(&request->flags));
struct ntlmssp_challenge c;
buf = buffer_create_dynamic(pool, sizeof(struct ntlmssp_challenge),
(size_t)-1);
memset(&c, 0, sizeof(c));
write_le64(&c.magic, NTLMSSP_MAGIC);
write_le32(&c.type, NTLMSSP_MSG_TYPE2);
write_le32(&c.flags, flags);
random_fill(c.challenge, sizeof(c.challenge));
buffer_write(buf, 0, &c, sizeof(c));
if (flags & NTLMSSP_TARGET_TYPE_SERVER)
ntlmssp_append_string(buf,
offsetof(struct ntlmssp_challenge, target_name),
my_hostname);
ntlmssp_append_target_info(buf, offsetof(struct ntlmssp_challenge,
target_info),
NTPLMSSP_V2_TARGET_FQDN, my_hostname,
NTPLMSSP_V2_TARGET_END);
*size = buffer_get_used_size(buf);
return buffer_free_without_data(buf);
}
static int ntlmssp_check_buffer(const struct ntlmssp_buffer *buffer,
size_t data_size, const char **error)
{
uint32_t offset = read_le32(&buffer->offset);
if (offset >= data_size) {
*error = "buffer offset out of bounds";
return 0;
}
if (offset + read_le16(&buffer->space) > data_size) {
*error = "buffer end out of bounds";
return 0;
}
return 1;
}
int ntlmssp_check_request(const struct ntlmssp_request *request,
size_t data_size, const char **error)
{
uint32_t flags;
if (data_size < sizeof(struct ntlmssp_request)) {
*error = "request too short";
return 0;
}
if (read_le64(&request->magic) != NTLMSSP_MAGIC) {
*error = "signature mismatch";
return 0;
}
if (read_le32(&request->type) != NTLMSSP_MSG_TYPE1) {
*error = "message type mismatch";
return 0;
}
flags = read_le32(&request->flags);
if ((flags & NTLMSSP_NEGOTIATE_UNICODE) == 0) {
*error = "client doesn't advertise Unicode support";
return 0;
}
if ((flags & NTLMSSP_NEGOTIATE_NTLM) == 0) {
*error = "client doesn't advertise NTLM support";
return 0;
}
return 1;
}
int ntlmssp_check_response(const struct ntlmssp_response *response,
size_t data_size, const char **error)
{
if (data_size < sizeof(struct ntlmssp_response)) {
*error = "response too short";
return 0;
}
if (read_le64(&response->magic) != NTLMSSP_MAGIC) {
*error = "signature mismatch";
return 0;
}
if (read_le32(&response->type) != NTLMSSP_MSG_TYPE3) {
*error = "message type mismatch";
return 0;
}
if (!ntlmssp_check_buffer(&response->lm_response, data_size, error) ||
!ntlmssp_check_buffer(&response->ntlm_response, data_size, error) ||
!ntlmssp_check_buffer(&response->domain, data_size, error) ||
!ntlmssp_check_buffer(&response->user, data_size, error) ||
!ntlmssp_check_buffer(&response->workstation, data_size, error))
return 0;
return 1;
}
--- NEW FILE: ntlm-message.h ---
#ifndef __NTLM_MESSAGE_H__
#define __NTLM_MESSAGE_H__
const struct ntlmssp_challenge *
ntlmssp_create_challenge(pool_t pool, const struct ntlmssp_request *request,
size_t *size);
int ntlmssp_check_request(const struct ntlmssp_request *request,
size_t data_size, const char **error);
int ntlmssp_check_response(const struct ntlmssp_response *response,
size_t data_size, const char **error);
#endif /* __NTLM_MESSAGE_H__ */
--- NEW FILE: ntlm-types.h ---
/*
* NTLM data structures.
*
* Copyright (c) 2004 Andrey Panin <pazke at donpac.ru>
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#ifndef __NTLM_TYPES_H__
#define __NTLM_TYPES_H__
#define NTLMSSP_MAGIC 0x005053534d4c544eULL
#define NTLMSSP_MSG_TYPE1 1
#define NTLMSSP_MSG_TYPE2 2
#define NTLMSSP_MSG_TYPE3 3
#define NTLMSSP_DES_KEY_LENGTH 7
#define NTLMSSP_CHALLENGE_SIZE 8
#define NTLMSSP_HASH_SIZE 16
#define NTLMSSP_RESPONSE_SIZE 24
#define NTLMSSP_V2_HASH_SIZE 16
#define NTLMSSP_V2_RESPONSE_SIZE 16
typedef uint16_t ucs2le_t;
struct ntlmssp_buffer {
uint16_t length; /* length of the buffer */
uint16_t space; /* space allocated space for buffer */
uint32_t offset; /* data offset from the start of the message */
};
typedef struct ntlmssp_buffer ntlmssp_buffer_t;
/*
*
*/
struct ntlmssp_message {
uint64_t magic; /* NTLMSSP\0 */
uint32_t type; /* Should be 1 */
};
/*
* Type 1 message, client sends it to start NTLM authentication sequence.
*/
struct ntlmssp_request {
uint64_t magic; /* NTLMSSP\0 */
uint32_t type; /* Should be 1 */
uint32_t flags; /* Flags */
ntlmssp_buffer_t domain; /* Domain name (optional) */
ntlmssp_buffer_t workstation; /* Workstation name (optional) */
/* Start of the data block */
};
/*
* The Type 2 message is sent by the server to the client in response to
* the client's Type 1 message. It serves to complete the negotiation of
* options with the client, and also provides a challenge to the client.
*/
struct ntlmssp_challenge {
uint64_t magic; /* NTLMSSP\0 */
uint32_t type; /* Should be 2 */
ntlmssp_buffer_t target_name; /* Name of authentication target */
uint32_t flags; /* Flags */
uint8_t challenge[NTLMSSP_CHALLENGE_SIZE]; /* Server challenge */
uint32_t context[2]; /* Local authentication context handle */
ntlmssp_buffer_t target_info; /* Target information block (for NTLMv2) */
/* Start of the data block */
};
/*
* The Type 3 message is the final step in authentication. This message
* contains the client's responses to the Type 2 challenge, which demonstrate
* that the client has knowledge of the account password without sending the
* password directly. The Type 3 message also indicates the domain and username
* of the authenticating account, as well as the client workstation name.
*/
struct ntlmssp_response {
uint64_t magic; /* NTLMSSP\0 */
uint32_t type; /* Should be 3 */
ntlmssp_buffer_t lm_response; /* LM/LMv2 recponse */
ntlmssp_buffer_t ntlm_response; /* NTLM/NTLMv2 recponse */
ntlmssp_buffer_t domain; /* Domain name */
ntlmssp_buffer_t user; /* User name */
ntlmssp_buffer_t workstation; /* Workstation name */
ntlmssp_buffer_t session_key; /* Session key (optional */
uint32_t flags; /* Flags (optional) */
/* Start of the data block */
};
/*
* NTLMv2 Target Information Block item.
*/
struct ntlmssp_v2_target_info {
uint16_t type; /* Data type (see below) */
uint16_t length; /* Length of content field */
/* Content (always in ucs2-le) */
};
/*
* NTLMv2 Target Information Block item data type.
*/
enum {
NTPLMSSP_V2_TARGET_END = 0, /* End of list */
NTPLMSSP_V2_TARGET_SERVER, /* NetBIOS server name */
NTPLMSSP_V2_TARGET_DOMAIN, /* NT Domain NetBIOS name */
NTPLMSSP_V2_TARGET_FQDN, /* Fully qualified host name */
NTPLMSSP_V2_TARGET_DNS, /* DNS domain name */
};
/*
* NTLMv2 Authentication data blob.
*/
struct ntlmssp_v2_blob {
uint32_t magic; /* Should be 0x01010000 */
uint32_t reserved; /* Always 0 */
uint64_t timestamp; /* Timestamp */
uint32_t unknown; /* Unknown something */
/* Target Information Block */
};
#endif /* __NTLM_TYPES_H__ */
--- NEW FILE: ntlm.h ---
#ifndef __NTLM_H__
#define __NTLM_H__
#include <stdint.h>
#include <stddef.h>
#include "ntlm-types.h"
#include "ntlm-flags.h"
#include "ntlm-byteorder.h"
#include "ntlm-encrypt.h"
#include "ntlm-message.h"
#define ntlmssp_buffer_data(message, buffer) \
__ntlmssp_buffer_data((message), &message->buffer)
static inline const void *
__ntlmssp_buffer_data(void * message, struct ntlmssp_buffer *buffer)
{
return ((char *) message) + read_le32(&buffer->offset);
}
#define ntlmssp_buffer_length(message, buffer) \
__ntlmssp_buffer_length(&message->buffer)
static inline unsigned int __ntlmssp_buffer_length(struct ntlmssp_buffer *buffer)
{
return read_le16(&buffer->length);
}
#define ntlmssp_t_str(message, buffer) \
__ntlmssp_t_str((message), &message->buffer)
const char * __ntlmssp_t_str(const void *message,
struct ntlmssp_buffer *buffer);
#endif
- Previous message: [dovecot-cvs] dovecot/src/lib Makefile.am, 1.37, 1.38 md4.c, NONE,
1.1 md4.h, NONE, 1.1
- Next message: [dovecot-cvs] dovecot/src/auth Makefile.am, 1.29, 1.30 mech-ntlm.c,
NONE, 1.1 mech.c, 1.28, 1.29 passdb.c, 1.19, 1.20 passdb.h,
1.10, 1.11 password-scheme-ntlm.c, NONE, 1.1 password-scheme.c,
1.10, 1.11 password-scheme.h, 1.4, 1.5
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the dovecot-cvs
mailing list