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 6550 : int sess_crypt_blob(DATA_BLOB *out, const DATA_BLOB *in, const DATA_BLOB *session_key,
33 : enum samba_gnutls_direction encrypt)
34 : {
35 : int i, k, rc;
36 :
37 6550 : if (in->length % 8 != 0) {
38 0 : return GNUTLS_E_INVALID_REQUEST;
39 : }
40 :
41 26122 : for (i=0,k=0;
42 31668 : i<in->length;
43 25118 : i += 8, k += 7) {
44 : uint8_t bin[8], bout[8], key[7];
45 :
46 25118 : memcpy(bin, &in->data[i], 8);
47 :
48 25118 : if (k + 7 > session_key->length) {
49 6012 : k = (session_key->length - k);
50 : }
51 25118 : memcpy(key, &session_key->data[k], 7);
52 :
53 25118 : rc = des_crypt56_gnutls(bout, bin, key, encrypt);
54 25118 : if (rc != 0) {
55 0 : return rc;
56 : }
57 :
58 25118 : memcpy(&out->data[i], bout, 8);
59 : }
60 6550 : return 0;
61 : }
62 :
63 :
64 : /*
65 : a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
66 :
67 : note that we round the length to a multiple of 8. This seems to be needed for
68 : compatibility with windows
69 :
70 : caller should free using data_blob_free()
71 : */
72 1182 : DATA_BLOB sess_encrypt_string(const char *str, const DATA_BLOB *session_key)
73 : {
74 : DATA_BLOB ret, src;
75 1182 : int slen = strlen(str);
76 1182 : int dlen = (slen+7) & ~7;
77 : int rc;
78 :
79 1182 : src = data_blob(NULL, 8+dlen);
80 1182 : if (!src.data) {
81 0 : return data_blob(NULL, 0);
82 : }
83 :
84 1182 : ret = data_blob(NULL, 8+dlen);
85 1182 : if (!ret.data) {
86 0 : data_blob_free(&src);
87 0 : return data_blob(NULL, 0);
88 : }
89 :
90 1182 : SIVAL(src.data, 0, slen);
91 1182 : SIVAL(src.data, 4, 1);
92 1182 : memset(src.data+8, 0, dlen);
93 1182 : memcpy(src.data+8, str, slen);
94 :
95 1182 : rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
96 :
97 1182 : data_blob_free(&src);
98 1182 : if (rc != 0) {
99 0 : data_blob_free(&ret);
100 0 : return data_blob(NULL, 0);
101 : }
102 :
103 1182 : return ret;
104 : }
105 :
106 : /*
107 : a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
108 :
109 : caller should free the returned string
110 : */
111 1192 : char *sess_decrypt_string(TALLOC_CTX *mem_ctx,
112 : DATA_BLOB *blob, const DATA_BLOB *session_key)
113 : {
114 : DATA_BLOB out;
115 : int rc, slen;
116 : char *ret;
117 :
118 1192 : if (blob->length < 8) {
119 0 : return NULL;
120 : }
121 :
122 1192 : out = data_blob_talloc(mem_ctx, NULL, blob->length);
123 1192 : if (!out.data) {
124 0 : return NULL;
125 : }
126 :
127 1192 : rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
128 1192 : if (rc != 0) {
129 0 : data_blob_free(&out);
130 0 : return NULL;
131 : }
132 :
133 1192 : if (IVAL(out.data, 4) != 1) {
134 0 : DEBUG(0,("Unexpected revision number %d in session crypted string\n",
135 : IVAL(out.data, 4)));
136 0 : data_blob_free(&out);
137 0 : return NULL;
138 : }
139 :
140 1192 : slen = IVAL(out.data, 0);
141 1192 : if (slen > blob->length - 8) {
142 0 : DEBUG(0,("Invalid crypt length %d\n", slen));
143 0 : data_blob_free(&out);
144 0 : return NULL;
145 : }
146 :
147 1192 : ret = talloc_strndup(mem_ctx, (const char *)(out.data+8), slen);
148 :
149 1192 : data_blob_free(&out);
150 :
151 1192 : DEBUG(0,("decrypted string '%s' of length %d\n", ret, slen));
152 :
153 1192 : return ret;
154 : }
155 :
156 : /*
157 : a convenient wrapper around sess_crypt_blob() for DATA_BLOBs, using the LSA convention
158 :
159 : note that we round the length to a multiple of 8. This seems to be needed for
160 : compatibility with windows
161 :
162 : caller should free using data_blob_free()
163 : */
164 1198 : DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_BLOB *session_key)
165 : {
166 : DATA_BLOB ret, src;
167 1198 : int dlen = (blob_in->length+7) & ~7;
168 : int rc;
169 :
170 1198 : src = data_blob_talloc(mem_ctx, NULL, 8+dlen);
171 1198 : if (!src.data) {
172 0 : return data_blob(NULL, 0);
173 : }
174 :
175 1198 : ret = data_blob_talloc(mem_ctx, NULL, 8+dlen);
176 1198 : if (!ret.data) {
177 0 : data_blob_free(&src);
178 0 : return data_blob(NULL, 0);
179 : }
180 :
181 1198 : SIVAL(src.data, 0, blob_in->length);
182 1198 : SIVAL(src.data, 4, 1);
183 1198 : memset(src.data+8, 0, dlen);
184 1198 : memcpy(src.data+8, blob_in->data, blob_in->length);
185 :
186 1198 : rc = sess_crypt_blob(&ret, &src, session_key, SAMBA_GNUTLS_ENCRYPT);
187 :
188 1198 : data_blob_free(&src);
189 1198 : if (rc != 0) {
190 0 : data_blob_free(&ret);
191 0 : return data_blob(NULL, 0);
192 : }
193 :
194 1198 : return ret;
195 : }
196 :
197 : /*
198 : Decrypt a DATA_BLOB using the LSA convention
199 : */
200 2350 : NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key,
201 : DATA_BLOB *ret)
202 : {
203 : DATA_BLOB out;
204 : int rc, slen;
205 :
206 2350 : if (blob->length < 8) {
207 0 : DEBUG(0, ("Unexpected length %d in session crypted secret (BLOB)\n",
208 : (int)blob->length));
209 0 : return NT_STATUS_INVALID_PARAMETER;
210 : }
211 :
212 2350 : out = data_blob_talloc(mem_ctx, NULL, blob->length);
213 2350 : if (!out.data) {
214 0 : return NT_STATUS_NO_MEMORY;
215 : }
216 :
217 2350 : rc = sess_crypt_blob(&out, blob, session_key, SAMBA_GNUTLS_DECRYPT);
218 2350 : if (rc != 0) {
219 0 : data_blob_free(&out);
220 0 : return gnutls_error_to_ntstatus(rc, NT_STATUS_ACCESS_DISABLED_BY_POLICY_OTHER);
221 : }
222 :
223 2350 : if (IVAL(out.data, 4) != 1) {
224 1162 : DEBUG(2,("Unexpected revision number %d in session crypted secret (BLOB)\n",
225 : IVAL(out.data, 4)));
226 1162 : return NT_STATUS_UNKNOWN_REVISION;
227 : }
228 :
229 1188 : slen = IVAL(out.data, 0);
230 1188 : if (slen > blob->length - 8) {
231 0 : DEBUG(0,("Invalid crypt length %d in session crypted secret (BLOB)\n", slen));
232 0 : return NT_STATUS_WRONG_PASSWORD;
233 : }
234 :
235 1188 : *ret = data_blob_talloc(mem_ctx, out.data+8, slen);
236 1188 : if (slen && !ret->data) {
237 0 : return NT_STATUS_NO_MEMORY;
238 : }
239 :
240 1188 : data_blob_free(&out);
241 :
242 1188 : return NT_STATUS_OK;
243 : }
|