Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : code to encrypt/decrypt data using the user session key
5 :
6 : Copyright (C) Andrew Tridgell 2004
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include "includes.h"
23 : #include "libcli/auth/libcli_auth.h"
24 :
25 : /*
26 : encrypt or decrypt a blob of data using the user session key
27 : as used in lsa_SetSecret
28 :
29 : before calling, the out blob must be initialised to be the same size
30 : as the in blob
31 : */
32 7858 : int sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
33 : enum samba_gnutls_direction encrypt)
34 : {
35 2 : int i, k, rc;
36 :
37 7858 : if (in->length % 8 != 0) {
38 0 : return GNUTLS_E_INVALID_REQUEST;
39 : }
40 :
41 7858 : if (session_key->length < 7) {
42 0 : return GNUTLS_E_INVALID_REQUEST;
43 : }
44 :
45 7856 : for (i=0,k=0;
46 37554 : i<in->length;
47 29696 : i += 8, k += 7) {
48 6 : uint8_t bin[8], bout[8], key[7];
49 :
50 29696 : memcpy(bin, &in->data[i], 8);
51 :
52 29696 : if (k + 7 > session_key->length) {
53 6994 : k = (session_key->length - k);
54 : }
55 29696 : memcpy(key, &session_key->data[k], 7);
56 :
57 29696 : rc = des_crypt56_gnutls(bout, bin, key, encrypt);
58 29696 : if (rc != 0) {
59 0 : return rc;
60 : }
61 :
62 29696 : memcpy(&out->data[i], bout, 8);
63 : }
64 7856 : return 0;
65 : }
66 :
67 :
68 : /*
69 : a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
70 :
71 : note that we round the length to a multiple of 8. This seems to be needed for
72 : compatibility with windows
73 :
74 : caller should free using data_blob_free()
75 : */
76 1634 : DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key)
77 : {
78 0 : DATA_BLOB ret, src;
79 1634 : int slen = strlen(str);
80 1634 : int dlen = (slen+7) & ~7;
81 0 : int rc;
82 :
83 1634 : src = data_blob(NULL, 8+dlen);
84 1634 : if (!src.data) {
85 0 : return data_blob(NULL, 0);
86 : }
87 :
88 1634 : ret = data_blob(NULL, 8+dlen);
89 1634 : if (!ret.data) {
90 0 : data_blob_free(&src);
91 0 : return data_blob(NULL, 0);
92 : }
93 :
94 1634 : SIVAL(src.data, 0, slen);
95 1634 : SIVAL(src.data, 4, 1);
96 1634 : memset(src.data+8, 0, dlen);
97 1634 : memcpy(src.data+8, str, slen);
98 :
99 1634 : rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
100 :
101 1634 : data_blob_free(&src);
102 1634 : if (rc != 0) {
103 0 : data_blob_free(&ret);
104 0 : return data_blob(NULL, 0);
105 : }
106 :
107 1634 : return ret;
108 : }
109 :
110 : /*
111 : a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
112 :
113 : caller should free the returned string
114 : */
115 1656 : char *sess_decrypt_string(TALLOC_CTX *mem_ctx,
116 : DATA_BLOB *blob, const DATA_BLOB *session_key)
117 : {
118 0 : DATA_BLOB out;
119 0 : int rc, slen;
120 0 : char *ret;
121 :
122 1656 : if (blob->length < 8) {
123 0 : return NULL;
124 : }
125 :
126 1656 : out = data_blob_talloc(mem_ctx, NULL, blob->length);
127 1656 : if (!out.data) {
128 0 : return NULL;
129 : }
130 :
131 1656 : rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
132 1656 : if (rc != 0) {
133 0 : data_blob_free(&out);
134 0 : return NULL;
135 : }
136 :
137 1656 : if (IVAL(out.data, 4) != 1) {
138 0 : DEBUG(0,("Unexpected revision number %d in session encrypted string\n",
139 : IVAL(out.data, 4)));
140 0 : data_blob_free(&out);
141 0 : return NULL;
142 : }
143 :
144 1656 : slen = IVAL(out.data, 0);
145 1656 : if (slen > blob->length - 8) {
146 0 : DEBUG(0,("Invalid crypt length %d\n", slen));
147 0 : data_blob_free(&out);
148 0 : return NULL;
149 : }
150 :
151 1656 : ret = talloc_strndup(mem_ctx, (const char *)(out.data+8), slen);
152 :
153 1656 : data_blob_free(&out);
154 :
155 1656 : DEBUG(0,("decrypted string '%s' of length %d\n", ret, slen));
156 :
157 1656 : return ret;
158 : }
159 :
160 : /*
161 : a convenient wrapper around sess_crypt_blob() for DATA_BLOBs, using the LSA convention
162 :
163 : note that we round the length to a multiple of 8. This seems to be needed for
164 : compatibility with windows
165 :
166 : caller should free using data_blob_free()
167 : */
168 1230 : DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key)
169 : {
170 0 : DATA_BLOB ret, src;
171 1230 : int dlen = (blob_in->length+7) & ~7;
172 0 : int rc;
173 :
174 1230 : src = data_blob_talloc(mem_ctx, NULL, 8+dlen);
175 1230 : if (!src.data) {
176 0 : return data_blob(NULL, 0);
177 : }
178 :
179 1230 : ret = data_blob_talloc(mem_ctx, NULL, 8+dlen);
180 1230 : if (!ret.data) {
181 0 : data_blob_free(&src);
182 0 : return data_blob(NULL, 0);
183 : }
184 :
185 1230 : SIVAL(src.data, 0, blob_in->length);
186 1230 : SIVAL(src.data, 4, 1);
187 1230 : memset(src.data+8, 0, dlen);
188 1230 : memcpy(src.data+8, blob_in->data, blob_in->length);
189 :
190 1230 : rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
191 :
192 1230 : data_blob_free(&src);
193 1230 : if (rc != 0) {
194 0 : data_blob_free(&ret);
195 0 : return data_blob(NULL, 0);
196 : }
197 :
198 1230 : return ret;
199 : }
200 :
201 : /*
202 : Decrypt a DATA_BLOB using the LSA convention
203 : */
204 2382 : NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key,
205 : DATA_BLOB *ret)
206 : {
207 0 : DATA_BLOB out;
208 0 : int rc, slen;
209 :
210 2382 : if (blob->length < 8) {
211 0 : DEBUG(0, ("Unexpected length %d in session encrypted secret (BLOB)\n",
212 : (int)blob->length));
213 0 : return NT_STATUS_INVALID_PARAMETER;
214 : }
215 :
216 2382 : out = data_blob_talloc(mem_ctx, NULL, blob->length);
217 2382 : if (!out.data) {
218 0 : return NT_STATUS_NO_MEMORY;
219 : }
220 :
221 2382 : rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
222 2382 : if (rc != 0) {
223 0 : data_blob_free(&out);
224 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
225 : }
226 :
227 2382 : if (IVAL(out.data, 4) != 1) {
228 1170 : DEBUG(2,("Unexpected revision number %d in session encrypted secret (BLOB)\n",
229 : IVAL(out.data, 4)));
230 1170 : return NT_STATUS_UNKNOWN_REVISION;
231 : }
232 :
233 1212 : slen = IVAL(out.data, 0);
234 1212 : if (slen > blob->length - 8) {
235 0 : DEBUG(0,("Invalid crypt length %d in session encrypted secret (BLOB)\n", slen));
236 0 : return NT_STATUS_WRONG_PASSWORD;
237 : }
238 :
239 1212 : *ret = data_blob_talloc(mem_ctx, out.data+8, slen);
240 1212 : if (slen && !ret->data) {
241 0 : return NT_STATUS_NO_MEMORY;
242 : }
243 :
244 1212 : data_blob_free(&out);
245 :
246 1212 : return NT_STATUS_OK;
247 : }
|