2003-08-13 05:53:07 +04:00
/*
Unix SMB / CIFS implementation .
a partial implementation of DES designed for use in the
SMB authentication protocol
Copyright ( C ) Andrew Tridgell 1998
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 05:53:07 +04:00
( at your option ) any later version .
This program 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 General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
# include "includes.h"
2008-10-20 20:59:51 +04:00
# include "libcli/auth/libcli_auth.h"
2003-08-13 05:53:07 +04:00
/* NOTES:
This code makes no attempt to be fast ! In fact , it is a very
slow implementation
This code is NOT a complete DES implementation . It implements only
the minimum necessary for SMB authentication , as used by all SMB
products ( including every copy of Microsoft Windows95 ever sold )
In particular , it can only do a unchained forward DES pass . This
means it is not possible to use this code for encryption / decryption
of data , instead it is only useful as a " hash " algorithm .
There is no entry point into this code that allows normal DES operation .
I believe this means that this code does not come under ITAR
regulations but this is NOT a legal opinion . If you are concerned
about the applicability of ITAR regulations to this code then you
should confirm it for yourself ( and maybe let me know if you come
up with a different answer to the one above )
*/
2004-06-01 12:30:34 +04:00
static const uint8_t perm1 [ 56 ] = { 57 , 49 , 41 , 33 , 25 , 17 , 9 ,
2003-08-13 05:53:07 +04:00
1 , 58 , 50 , 42 , 34 , 26 , 18 ,
10 , 2 , 59 , 51 , 43 , 35 , 27 ,
19 , 11 , 3 , 60 , 52 , 44 , 36 ,
63 , 55 , 47 , 39 , 31 , 23 , 15 ,
7 , 62 , 54 , 46 , 38 , 30 , 22 ,
14 , 6 , 61 , 53 , 45 , 37 , 29 ,
21 , 13 , 5 , 28 , 20 , 12 , 4 } ;
2004-06-01 12:30:34 +04:00
static const uint8_t perm2 [ 48 ] = { 14 , 17 , 11 , 24 , 1 , 5 ,
2003-08-13 05:53:07 +04:00
3 , 28 , 15 , 6 , 21 , 10 ,
23 , 19 , 12 , 4 , 26 , 8 ,
16 , 7 , 27 , 20 , 13 , 2 ,
41 , 52 , 31 , 37 , 47 , 55 ,
30 , 40 , 51 , 45 , 33 , 48 ,
44 , 49 , 39 , 56 , 34 , 53 ,
46 , 42 , 50 , 36 , 29 , 32 } ;
2004-06-01 12:30:34 +04:00
static const uint8_t perm3 [ 64 ] = { 58 , 50 , 42 , 34 , 26 , 18 , 10 , 2 ,
2003-08-13 05:53:07 +04:00
60 , 52 , 44 , 36 , 28 , 20 , 12 , 4 ,
62 , 54 , 46 , 38 , 30 , 22 , 14 , 6 ,
64 , 56 , 48 , 40 , 32 , 24 , 16 , 8 ,
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 } ;
2004-06-01 12:30:34 +04:00
static const uint8_t perm4 [ 48 ] = { 32 , 1 , 2 , 3 , 4 , 5 ,
2003-08-13 05:53:07 +04:00
4 , 5 , 6 , 7 , 8 , 9 ,
8 , 9 , 10 , 11 , 12 , 13 ,
12 , 13 , 14 , 15 , 16 , 17 ,
16 , 17 , 18 , 19 , 20 , 21 ,
20 , 21 , 22 , 23 , 24 , 25 ,
24 , 25 , 26 , 27 , 28 , 29 ,
28 , 29 , 30 , 31 , 32 , 1 } ;
2004-06-01 12:30:34 +04:00
static const uint8_t perm5 [ 32 ] = { 16 , 7 , 20 , 21 ,
2003-08-13 05:53:07 +04:00
29 , 12 , 28 , 17 ,
1 , 15 , 23 , 26 ,
5 , 18 , 31 , 10 ,
2 , 8 , 24 , 14 ,
32 , 27 , 3 , 9 ,
19 , 13 , 30 , 6 ,
22 , 11 , 4 , 25 } ;
2004-06-01 12:30:34 +04:00
static const uint8_t perm6 [ 64 ] = { 40 , 8 , 48 , 16 , 56 , 24 , 64 , 32 ,
2003-08-13 05:53:07 +04:00
39 , 7 , 47 , 15 , 55 , 23 , 63 , 31 ,
38 , 6 , 46 , 14 , 54 , 22 , 62 , 30 ,
37 , 5 , 45 , 13 , 53 , 21 , 61 , 29 ,
36 , 4 , 44 , 12 , 52 , 20 , 60 , 28 ,
35 , 3 , 43 , 11 , 51 , 19 , 59 , 27 ,
34 , 2 , 42 , 10 , 50 , 18 , 58 , 26 ,
33 , 1 , 41 , 9 , 49 , 17 , 57 , 25 } ;
2004-06-01 12:30:34 +04:00
static const uint8_t sc [ 16 ] = { 1 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1 , 2 , 2 , 2 , 2 , 2 , 2 , 1 } ;
2003-08-13 05:53:07 +04:00
2004-06-01 12:30:34 +04:00
static const uint8_t sbox [ 8 ] [ 4 ] [ 16 ] = {
2003-08-13 05:53:07 +04:00
{ { 14 , 4 , 13 , 1 , 2 , 15 , 11 , 8 , 3 , 10 , 6 , 12 , 5 , 9 , 0 , 7 } ,
{ 0 , 15 , 7 , 4 , 14 , 2 , 13 , 1 , 10 , 6 , 12 , 11 , 9 , 5 , 3 , 8 } ,
{ 4 , 1 , 14 , 8 , 13 , 6 , 2 , 11 , 15 , 12 , 9 , 7 , 3 , 10 , 5 , 0 } ,
{ 15 , 12 , 8 , 2 , 4 , 9 , 1 , 7 , 5 , 11 , 3 , 14 , 10 , 0 , 6 , 13 } } ,
{ { 15 , 1 , 8 , 14 , 6 , 11 , 3 , 4 , 9 , 7 , 2 , 13 , 12 , 0 , 5 , 10 } ,
{ 3 , 13 , 4 , 7 , 15 , 2 , 8 , 14 , 12 , 0 , 1 , 10 , 6 , 9 , 11 , 5 } ,
{ 0 , 14 , 7 , 11 , 10 , 4 , 13 , 1 , 5 , 8 , 12 , 6 , 9 , 3 , 2 , 15 } ,
{ 13 , 8 , 10 , 1 , 3 , 15 , 4 , 2 , 11 , 6 , 7 , 12 , 0 , 5 , 14 , 9 } } ,
{ { 10 , 0 , 9 , 14 , 6 , 3 , 15 , 5 , 1 , 13 , 12 , 7 , 11 , 4 , 2 , 8 } ,
{ 13 , 7 , 0 , 9 , 3 , 4 , 6 , 10 , 2 , 8 , 5 , 14 , 12 , 11 , 15 , 1 } ,
{ 13 , 6 , 4 , 9 , 8 , 15 , 3 , 0 , 11 , 1 , 2 , 12 , 5 , 10 , 14 , 7 } ,
{ 1 , 10 , 13 , 0 , 6 , 9 , 8 , 7 , 4 , 15 , 14 , 3 , 11 , 5 , 2 , 12 } } ,
{ { 7 , 13 , 14 , 3 , 0 , 6 , 9 , 10 , 1 , 2 , 8 , 5 , 11 , 12 , 4 , 15 } ,
{ 13 , 8 , 11 , 5 , 6 , 15 , 0 , 3 , 4 , 7 , 2 , 12 , 1 , 10 , 14 , 9 } ,
{ 10 , 6 , 9 , 0 , 12 , 11 , 7 , 13 , 15 , 1 , 3 , 14 , 5 , 2 , 8 , 4 } ,
{ 3 , 15 , 0 , 6 , 10 , 1 , 13 , 8 , 9 , 4 , 5 , 11 , 12 , 7 , 2 , 14 } } ,
{ { 2 , 12 , 4 , 1 , 7 , 10 , 11 , 6 , 8 , 5 , 3 , 15 , 13 , 0 , 14 , 9 } ,
{ 14 , 11 , 2 , 12 , 4 , 7 , 13 , 1 , 5 , 0 , 15 , 10 , 3 , 9 , 8 , 6 } ,
{ 4 , 2 , 1 , 11 , 10 , 13 , 7 , 8 , 15 , 9 , 12 , 5 , 6 , 3 , 0 , 14 } ,
{ 11 , 8 , 12 , 7 , 1 , 14 , 2 , 13 , 6 , 15 , 0 , 9 , 10 , 4 , 5 , 3 } } ,
{ { 12 , 1 , 10 , 15 , 9 , 2 , 6 , 8 , 0 , 13 , 3 , 4 , 14 , 7 , 5 , 11 } ,
{ 10 , 15 , 4 , 2 , 7 , 12 , 9 , 5 , 6 , 1 , 13 , 14 , 0 , 11 , 3 , 8 } ,
{ 9 , 14 , 15 , 5 , 2 , 8 , 12 , 3 , 7 , 0 , 4 , 10 , 1 , 13 , 11 , 6 } ,
{ 4 , 3 , 2 , 12 , 9 , 5 , 15 , 10 , 11 , 14 , 1 , 7 , 6 , 0 , 8 , 13 } } ,
{ { 4 , 11 , 2 , 14 , 15 , 0 , 8 , 13 , 3 , 12 , 9 , 7 , 5 , 10 , 6 , 1 } ,
{ 13 , 0 , 11 , 7 , 4 , 9 , 1 , 10 , 14 , 3 , 5 , 12 , 2 , 15 , 8 , 6 } ,
{ 1 , 4 , 11 , 13 , 12 , 3 , 7 , 14 , 10 , 15 , 6 , 8 , 0 , 5 , 9 , 2 } ,
{ 6 , 11 , 13 , 8 , 1 , 4 , 10 , 7 , 9 , 5 , 0 , 15 , 14 , 2 , 3 , 12 } } ,
{ { 13 , 2 , 8 , 4 , 6 , 15 , 11 , 1 , 10 , 9 , 3 , 14 , 5 , 0 , 12 , 7 } ,
{ 1 , 15 , 13 , 8 , 10 , 3 , 7 , 4 , 12 , 5 , 6 , 11 , 0 , 14 , 9 , 2 } ,
{ 7 , 11 , 4 , 1 , 9 , 12 , 14 , 2 , 0 , 6 , 10 , 13 , 15 , 3 , 5 , 8 } ,
{ 2 , 1 , 14 , 7 , 4 , 10 , 8 , 13 , 15 , 12 , 9 , 0 , 3 , 5 , 6 , 11 } } } ;
2004-06-01 12:30:34 +04:00
static void permute ( char * out , const char * in , const uint8_t * p , int n )
2003-08-13 05:53:07 +04:00
{
int i ;
for ( i = 0 ; i < n ; i + + )
out [ i ] = in [ p [ i ] - 1 ] ;
}
static void lshift ( char * d , int count , int n )
{
char out [ 64 ] ;
int i ;
for ( i = 0 ; i < n ; i + + )
out [ i ] = d [ ( i + count ) % n ] ;
for ( i = 0 ; i < n ; i + + )
d [ i ] = out [ i ] ;
}
static void concat ( char * out , char * in1 , char * in2 , int l1 , int l2 )
{
while ( l1 - - )
* out + + = * in1 + + ;
while ( l2 - - )
* out + + = * in2 + + ;
}
static void xor ( char * out , char * in1 , char * in2 , int n )
{
int i ;
for ( i = 0 ; i < n ; i + + )
out [ i ] = in1 [ i ] ^ in2 [ i ] ;
}
static void dohash ( char * out , char * in , char * key , int forw )
{
int i , j , k ;
char pk1 [ 56 ] ;
char c [ 28 ] ;
char d [ 28 ] ;
char cd [ 56 ] ;
char ki [ 16 ] [ 48 ] ;
char pd1 [ 64 ] ;
char l [ 32 ] , r [ 32 ] ;
char rl [ 64 ] ;
permute ( pk1 , key , perm1 , 56 ) ;
for ( i = 0 ; i < 28 ; i + + )
c [ i ] = pk1 [ i ] ;
for ( i = 0 ; i < 28 ; i + + )
d [ i ] = pk1 [ i + 28 ] ;
for ( i = 0 ; i < 16 ; i + + ) {
lshift ( c , sc [ i ] , 28 ) ;
lshift ( d , sc [ i ] , 28 ) ;
concat ( cd , c , d , 28 , 28 ) ;
permute ( ki [ i ] , cd , perm2 , 48 ) ;
}
permute ( pd1 , in , perm3 , 64 ) ;
for ( j = 0 ; j < 32 ; j + + ) {
l [ j ] = pd1 [ j ] ;
r [ j ] = pd1 [ j + 32 ] ;
}
for ( i = 0 ; i < 16 ; i + + ) {
char er [ 48 ] ;
char erk [ 48 ] ;
char b [ 8 ] [ 6 ] ;
char cb [ 32 ] ;
char pcb [ 32 ] ;
char r2 [ 32 ] ;
permute ( er , r , perm4 , 48 ) ;
xor ( erk , er , ki [ forw ? i : 15 - i ] , 48 ) ;
for ( j = 0 ; j < 8 ; j + + )
for ( k = 0 ; k < 6 ; k + + )
b [ j ] [ k ] = erk [ j * 6 + k ] ;
for ( j = 0 ; j < 8 ; j + + ) {
int m , n ;
m = ( b [ j ] [ 0 ] < < 1 ) | b [ j ] [ 5 ] ;
n = ( b [ j ] [ 1 ] < < 3 ) | ( b [ j ] [ 2 ] < < 2 ) | ( b [ j ] [ 3 ] < < 1 ) | b [ j ] [ 4 ] ;
for ( k = 0 ; k < 4 ; k + + )
b [ j ] [ k ] = ( sbox [ j ] [ m ] [ n ] & ( 1 < < ( 3 - k ) ) ) ? 1 : 0 ;
}
for ( j = 0 ; j < 8 ; j + + )
for ( k = 0 ; k < 4 ; k + + )
cb [ j * 4 + k ] = b [ j ] [ k ] ;
permute ( pcb , cb , perm5 , 32 ) ;
xor ( r2 , l , pcb , 32 ) ;
for ( j = 0 ; j < 32 ; j + + )
l [ j ] = r [ j ] ;
for ( j = 0 ; j < 32 ; j + + )
r [ j ] = r2 [ j ] ;
}
concat ( rl , r , l , 32 , 32 ) ;
permute ( out , rl , perm6 , 64 ) ;
}
2004-05-29 12:11:46 +04:00
static void str_to_key ( const uint8_t * str , uint8_t * key )
2003-08-13 05:53:07 +04:00
{
int i ;
key [ 0 ] = str [ 0 ] > > 1 ;
key [ 1 ] = ( ( str [ 0 ] & 0x01 ) < < 6 ) | ( str [ 1 ] > > 2 ) ;
key [ 2 ] = ( ( str [ 1 ] & 0x03 ) < < 5 ) | ( str [ 2 ] > > 3 ) ;
key [ 3 ] = ( ( str [ 2 ] & 0x07 ) < < 4 ) | ( str [ 3 ] > > 4 ) ;
key [ 4 ] = ( ( str [ 3 ] & 0x0F ) < < 3 ) | ( str [ 4 ] > > 5 ) ;
key [ 5 ] = ( ( str [ 4 ] & 0x1F ) < < 2 ) | ( str [ 5 ] > > 6 ) ;
key [ 6 ] = ( ( str [ 5 ] & 0x3F ) < < 1 ) | ( str [ 6 ] > > 7 ) ;
key [ 7 ] = str [ 6 ] & 0x7F ;
for ( i = 0 ; i < 8 ; i + + ) {
key [ i ] = ( key [ i ] < < 1 ) ;
}
}
2004-06-04 03:15:16 +04:00
/*
basic des crypt using a 56 bit ( 7 byte ) key
*/
void des_crypt56 ( uint8_t out [ 8 ] , const uint8_t in [ 8 ] , const uint8_t key [ 7 ] , int forw )
2003-08-13 05:53:07 +04:00
{
int i ;
char outb [ 64 ] ;
char inb [ 64 ] ;
char keyb [ 64 ] ;
2004-05-29 12:11:46 +04:00
uint8_t key2 [ 8 ] ;
2003-08-13 05:53:07 +04:00
str_to_key ( key , key2 ) ;
for ( i = 0 ; i < 64 ; i + + ) {
inb [ i ] = ( in [ i / 8 ] & ( 1 < < ( 7 - ( i % 8 ) ) ) ) ? 1 : 0 ;
keyb [ i ] = ( key2 [ i / 8 ] & ( 1 < < ( 7 - ( i % 8 ) ) ) ) ? 1 : 0 ;
outb [ i ] = 0 ;
}
dohash ( outb , inb , keyb , forw ) ;
for ( i = 0 ; i < 8 ; i + + ) {
out [ i ] = 0 ;
}
for ( i = 0 ; i < 64 ; i + + ) {
if ( outb [ i ] )
out [ i / 8 ] | = ( 1 < < ( 7 - ( i % 8 ) ) ) ;
}
}
2004-05-29 12:11:46 +04:00
void E_P16 ( const uint8_t * p14 , uint8_t * p16 )
2003-08-13 05:53:07 +04:00
{
2004-06-01 14:12:52 +04:00
const uint8_t sp8 [ 8 ] = { 0x4b , 0x47 , 0x53 , 0x21 , 0x40 , 0x23 , 0x24 , 0x25 } ;
2004-06-04 03:15:16 +04:00
des_crypt56 ( p16 , sp8 , p14 , 1 ) ;
des_crypt56 ( p16 + 8 , sp8 , p14 + 7 , 1 ) ;
2003-08-13 05:53:07 +04:00
}
2004-05-29 12:11:46 +04:00
void E_P24 ( const uint8_t * p21 , const uint8_t * c8 , uint8_t * p24 )
2003-08-13 05:53:07 +04:00
{
2004-06-04 03:15:16 +04:00
des_crypt56 ( p24 , c8 , p21 , 1 ) ;
des_crypt56 ( p24 + 8 , c8 , p21 + 7 , 1 ) ;
des_crypt56 ( p24 + 16 , c8 , p21 + 14 , 1 ) ;
2003-08-13 05:53:07 +04:00
}
2004-05-29 12:11:46 +04:00
void D_P16 ( const uint8_t * p14 , const uint8_t * in , uint8_t * out )
2003-08-13 05:53:07 +04:00
{
2004-06-04 03:15:16 +04:00
des_crypt56 ( out , in , p14 , 0 ) ;
des_crypt56 ( out + 8 , in + 8 , p14 + 7 , 0 ) ;
2003-08-13 05:53:07 +04:00
}
2004-05-29 12:11:46 +04:00
void E_old_pw_hash ( uint8_t * p14 , const uint8_t * in , uint8_t * out )
2003-08-13 05:53:07 +04:00
{
2004-06-04 03:15:16 +04:00
des_crypt56 ( out , in , p14 , 1 ) ;
des_crypt56 ( out + 8 , in + 8 , p14 + 7 , 1 ) ;
2003-08-13 05:53:07 +04:00
}
2004-06-04 03:15:16 +04:00
/* des encryption with a 128 bit key */
void des_crypt128 ( uint8_t out [ 8 ] , const uint8_t in [ 8 ] , const uint8_t key [ 16 ] )
2003-08-13 05:53:07 +04:00
{
2004-05-29 12:11:46 +04:00
uint8_t buf [ 8 ] ;
2004-06-04 03:15:16 +04:00
des_crypt56 ( buf , in , key , 1 ) ;
des_crypt56 ( out , buf , key + 9 , 1 ) ;
2003-08-13 05:53:07 +04:00
}
2004-06-04 03:15:16 +04:00
/* des encryption with a 64 bit key */
void des_crypt64 ( uint8_t out [ 8 ] , const uint8_t in [ 8 ] , const uint8_t key [ 8 ] , int forw )
2003-08-13 05:53:07 +04:00
{
2004-05-29 12:11:46 +04:00
uint8_t buf [ 8 ] ;
uint8_t key2 [ 8 ] ;
2003-12-02 01:13:11 +03:00
ZERO_STRUCT ( key2 ) ;
2004-06-04 03:15:16 +04:00
des_crypt56 ( buf , in , key , forw ) ;
2003-08-13 05:53:07 +04:00
key2 [ 0 ] = key [ 7 ] ;
2004-06-04 03:15:16 +04:00
des_crypt56 ( out , buf , key2 , forw ) ;
2003-08-13 05:53:07 +04:00
}
2004-06-04 03:15:16 +04:00
/* des encryption with a 112 bit (14 byte) key */
void des_crypt112 ( uint8_t out [ 8 ] , const uint8_t in [ 8 ] , const uint8_t key [ 14 ] , int forw )
2003-08-13 05:53:07 +04:00
{
2004-06-04 03:15:16 +04:00
uint8_t buf [ 8 ] ;
des_crypt56 ( buf , in , key , forw ) ;
des_crypt56 ( out , buf , key + 7 , forw ) ;
2003-08-13 05:53:07 +04:00
}
2004-06-04 03:15:16 +04:00
/* des encryption of a 16 byte lump of data with a 112 bit key */
2010-03-05 10:22:36 +03:00
void des_crypt112_16 ( uint8_t out [ 16 ] , const uint8_t in [ 16 ] , const uint8_t key [ 14 ] , int forw )
2004-06-04 03:15:16 +04:00
{
des_crypt56 ( out , in , key , forw ) ;
des_crypt56 ( out + 8 , in + 8 , key + 7 , forw ) ;
}
2004-04-21 09:01:31 +04:00
2003-08-13 05:53:07 +04:00
/* Decode a sam password hash into a password. The password hash is the
same method used to store passwords in the NT registry . The DES key
used is based on the RID of the user . */
2010-01-05 20:41:24 +03:00
void sam_rid_crypt ( unsigned int rid , const uint8_t * in , uint8_t * out , int forw )
2003-08-13 05:53:07 +04:00
{
2004-06-01 12:30:34 +04:00
uint8_t s [ 14 ] ;
2003-08-13 05:53:07 +04:00
2004-06-01 12:30:34 +04:00
s [ 0 ] = s [ 4 ] = s [ 8 ] = s [ 12 ] = ( uint8_t ) ( rid & 0xFF ) ;
s [ 1 ] = s [ 5 ] = s [ 9 ] = s [ 13 ] = ( uint8_t ) ( ( rid > > 8 ) & 0xFF ) ;
s [ 2 ] = s [ 6 ] = s [ 10 ] = ( uint8_t ) ( ( rid > > 16 ) & 0xFF ) ;
s [ 3 ] = s [ 7 ] = s [ 11 ] = ( uint8_t ) ( ( rid > > 24 ) & 0xFF ) ;
2003-08-13 05:53:07 +04:00
2004-06-04 03:15:16 +04:00
des_crypt56 ( out , in , s , forw ) ;
des_crypt56 ( out + 8 , in + 8 , s + 7 , forw ) ;
2003-08-13 05:53:07 +04:00
}