c6c4441930630ac0fffdc0c9084fe1d2efe748f8
[samba.git] / libcli / auth / smbdes.c
1 /* 
2    Unix SMB/CIFS implementation.
3
4    a partial implementation of DES designed for use in the 
5    SMB authentication protocol
6
7    Copyright (C) Andrew Tridgell 1998
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "libcli/auth/libcli_auth.h"
25
26 #include <gnutls/gnutls.h>
27 #include <gnutls/crypto.h>
28
29 static void str_to_key(const uint8_t *str,uint8_t *key)
30 {
31         int i;
32
33         key[0] = str[0]>>1;
34         key[1] = ((str[0]&0x01)<<6) | (str[1]>>2);
35         key[2] = ((str[1]&0x03)<<5) | (str[2]>>3);
36         key[3] = ((str[2]&0x07)<<4) | (str[3]>>4);
37         key[4] = ((str[3]&0x0F)<<3) | (str[4]>>5);
38         key[5] = ((str[4]&0x1F)<<2) | (str[5]>>6);
39         key[6] = ((str[5]&0x3F)<<1) | (str[6]>>7);
40         key[7] = str[6]&0x7F;
41         for (i=0;i<8;i++) {
42                 key[i] = (key[i]<<1);
43         }
44 }
45
46 int des_crypt56_gnutls(uint8_t out[8], const uint8_t in[8],
47                        const uint8_t key_in[7],
48                        enum samba_gnutls_direction encrypt)
49 {
50         /*
51          * A single block DES-CBC op, with an all-zero IV is the same as DES
52          * because the IV is combined with the data using XOR.
53          * This allows us to use GNUTLS_CIPHER_DES_CBC from GnuTLS and not
54          * implement single-DES in Samba.
55          *
56          * In turn this is used to build DES-ECB, which is used
57          * for example in the NTLM challenge/response calculation.
58          */
59         static const uint8_t iv8[8];
60         gnutls_datum_t iv = { discard_const(iv8), 8 };
61         gnutls_datum_t key;
62         gnutls_cipher_hd_t ctx;
63         uint8_t key2[8];
64         uint8_t outb[8];
65         int ret;
66
67         memset(out, 0, 8);
68
69         str_to_key(key_in, key2);
70
71         key.data = key2;
72         key.size = 8;
73
74         ret = gnutls_global_init();
75         if (ret != 0) {
76                 return ret;
77         }
78
79         ret = gnutls_cipher_init(&ctx, GNUTLS_CIPHER_DES_CBC, &key, &iv);
80         if (ret != 0) {
81                 return ret;
82         }
83
84         memcpy(outb, in, 8);
85         if (encrypt == SAMBA_GNUTLS_ENCRYPT) {
86                 ret = gnutls_cipher_encrypt(ctx, outb, 8);
87         } else {
88                 ret = gnutls_cipher_decrypt(ctx, outb, 8);
89         }
90
91         if (ret == 0) {
92                 memcpy(out, outb, 8);
93         }
94
95         gnutls_cipher_deinit(ctx);
96
97         return ret;
98 }
99
100 int E_P16(const uint8_t *p14,uint8_t *p16)
101 {
102         const uint8_t sp8[8] = {0x4b, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25};
103         int ret;
104
105         ret = des_crypt56_gnutls(p16, sp8, p14, SAMBA_GNUTLS_ENCRYPT);
106         if (ret != 0) {
107                 return ret;
108         }
109
110         return des_crypt56_gnutls(p16+8, sp8, p14+7, SAMBA_GNUTLS_ENCRYPT);
111 }
112
113 int E_P24(const uint8_t *p21, const uint8_t *c8, uint8_t *p24)
114 {
115         int ret;
116
117         ret = des_crypt56_gnutls(p24, c8, p21, SAMBA_GNUTLS_ENCRYPT);
118         if (ret != 0) {
119                 return ret;
120         }
121
122         ret = des_crypt56_gnutls(p24+8, c8, p21+7, SAMBA_GNUTLS_ENCRYPT);
123         if (ret != 0) {
124                 return ret;
125         }
126
127         return des_crypt56_gnutls(p24+16, c8, p21+14, SAMBA_GNUTLS_ENCRYPT);
128 }
129
130 int E_old_pw_hash( uint8_t *p14, const uint8_t *in, uint8_t *out)
131 {
132         int ret;
133
134         ret = des_crypt56_gnutls(out, in, p14, SAMBA_GNUTLS_ENCRYPT);
135         if (ret != 0) {
136                 return ret;
137         }
138
139         return des_crypt56_gnutls(out+8, in+8, p14+7, SAMBA_GNUTLS_ENCRYPT);
140 }
141
142 /* des encryption with a 128 bit key */
143 int des_crypt128(uint8_t out[8], const uint8_t in[8], const uint8_t key[16])
144 {
145         uint8_t buf[8];
146         int ret;
147
148         ret = des_crypt56_gnutls(buf, in, key, SAMBA_GNUTLS_ENCRYPT);
149         if (ret != 0) {
150                 return ret;
151         }
152
153         return des_crypt56_gnutls(out, buf, key+9, SAMBA_GNUTLS_ENCRYPT);
154 }
155
156 /* des encryption with a 112 bit (14 byte) key */
157 int des_crypt112(uint8_t out[8], const uint8_t in[8], const uint8_t key[14],
158                  enum samba_gnutls_direction encrypt)
159 {
160         uint8_t buf[8];
161         int ret;
162
163         if (encrypt == SAMBA_GNUTLS_ENCRYPT) {
164                 ret = des_crypt56_gnutls(buf, in, key, SAMBA_GNUTLS_ENCRYPT);
165                 if (ret != 0) {
166                         return ret;
167                 }
168
169                 return des_crypt56_gnutls(out, buf, key+7, SAMBA_GNUTLS_ENCRYPT);
170         }
171
172         ret = des_crypt56_gnutls(buf, in, key+7, SAMBA_GNUTLS_DECRYPT);
173         if (ret != 0) {
174                 return ret;
175         }
176
177         return des_crypt56_gnutls(out, buf, key, SAMBA_GNUTLS_DECRYPT);
178 }
179
180 /* des encryption of a 16 byte lump of data with a 112 bit key */
181 int des_crypt112_16(uint8_t out[16], const uint8_t in[16], const uint8_t key[14],
182                     enum samba_gnutls_direction encrypt)
183 {
184         int ret;
185
186         ret = des_crypt56_gnutls(out, in, key, encrypt);
187         if (ret != 0) {
188                 return ret;
189         }
190
191         return des_crypt56_gnutls(out + 8, in + 8, key+7, encrypt);
192 }
193
194 /* Decode a sam password hash into a password.  The password hash is the
195    same method used to store passwords in the NT registry.  The DES key
196    used is based on the RID of the user. */
197 int sam_rid_crypt(unsigned int rid, const uint8_t *in, uint8_t *out,
198                   enum samba_gnutls_direction encrypt)
199 {
200         uint8_t s[14];
201         int ret;
202
203         s[0] = s[4] = s[8] = s[12] = (uint8_t)(rid & 0xFF);
204         s[1] = s[5] = s[9] = s[13] = (uint8_t)((rid >> 8) & 0xFF);
205         s[2] = s[6] = s[10]        = (uint8_t)((rid >> 16) & 0xFF);
206         s[3] = s[7] = s[11]        = (uint8_t)((rid >> 24) & 0xFF);
207
208         ret = des_crypt56_gnutls(out, in, s, encrypt);
209         if (ret != 0) {
210                 return ret;
211         }
212         return des_crypt56_gnutls(out+8, in+8, s+7, encrypt);
213 }