001: ///////////////////////////////////////////////////////////////////////////////
002: //
003: // This program is free software; you can redistribute it and/or modify
004: // it under the terms of the GNU General Public License and GNU Library
005: // General Public License as published by the Free Software Foundation;
006: // either version 2, or (at your option) any later version.
007: //
008: // This program is distributed in the hope that it will be useful,
009: // but WITHOUT ANY WARRANTY; without even the implied warranty of
010: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: // GNU General Public License and GNU Library General Public License
012: // for more details.
013: //
014: // You should have received a copy of the GNU General Public License
015: // and GNU Library General Public License along with this program; if
016: // not, write to the Free Software Foundation, 675 Mass Ave, Cambridge,
017: // MA 02139, USA.
018: //
019: ///////////////////////////////////////////////////////////////////////////////
020:
021: package org.rdesktop.server.rdp;
022:
023: import java.io.*;
024: import org.rdesktop.server.rdp.crypto.*;
025:
026: public class RdpLicense {
027: private static final int LICENSE_TOKEN_SIZE = 10;
028: private static final int LICENSE_HWID_SIZE = 20;
029: private static final int LICENSE_SIGNATURE_SIZE = 16;
030:
031: /*
032: private static final int LICENSE_TAG_DEMAND = 0x0201;
033: private static final int LICENSE_TAG_AUTHREQ = 0x0202;
034: private static final int LICENSE_TAG_ISSUE = 0x0203;
035: private static final int LICENSE_TAG_REISSUE = 0x0204;
036: private static final int LICENSE_TAG_PRESENT = 0x0212;
037: private static final int LICENSE_TAG_REQUEST = 0x0213;
038: private static final int LICENSE_TAG_AUTHRESP = 0x0215;
039: private static final int LICENSE_TAG_RESULT = 0x02ff;
040: */
041:
042: private static final int LICENSE_TAG_DEMAND = 0x01;
043: private static final int LICENSE_TAG_AUTHREQ = 0x02;
044: private static final int LICENSE_TAG_ISSUE = 0x03;
045: private static final int LICENSE_TAG_REISSUE = 0x04;
046: private static final int LICENSE_TAG_PRESENT = 0x12;
047: private static final int LICENSE_TAG_REQUEST = 0x13;
048: private static final int LICENSE_TAG_AUTHRESP = 0x15;
049: private static final int LICENSE_TAG_RESULT = 0xff;
050:
051: private static final int LICENSE_TAG_USER = 0x000f;
052: private static final int LICENSE_TAG_HOST = 0x0010;
053:
054: private byte[] m_in_sig;
055: private byte[] m_in_token;
056: private byte[] m_license_key;
057: private byte[] m_license_sign_key;
058:
059: private RdpSecure m_secure;
060:
061: RdpLicense(RdpSecure secure) {
062: m_secure = secure;
063:
064: m_in_sig = null;
065: m_in_token = null;
066: m_license_key = new byte[16];
067: m_license_sign_key = new byte[16];
068: }
069:
070: protected byte[] load_license() {
071: return (new RdpLicenseStore())
072: .load_license(m_secure.m_rdpProto.m_host);
073: }
074:
075: protected void save_license(String host, RdpPacket data, int length) {
076: int len;
077: int startpos = data.getPosition();
078: data.incrementPosition(2);
079: for (int i = 0; i < 3; i++) {
080: len = data.getLittleEndian32();
081: data.incrementPosition(len);
082: if (data.getPosition() + 4 - startpos > length) {
083: return;
084: }
085: }
086:
087: len = data.getLittleEndian32();
088: if (data.getPosition() + len - startpos > length) {
089: return;
090: }
091:
092: byte[] databytes = new byte[len];
093: data.copyToByteArray(databytes, 0, data.getPosition(), len);
094:
095: new RdpLicenseStore().save_license(m_secure.m_rdpProto.m_host,
096: databytes);
097:
098: /*
099: String dirpath = RdpOptions.license_path;//home+"/.rdesktop";
100: String filepath = dirpath +"/license." + host;
101:
102: File file = new File(dirpath);
103: file.mkdir();
104: try
105: {
106: FileOutputStream fd = new FileOutputStream(filepath);
107:
108: // write to the license file
109: byte[] databytes = new byte[len];
110: data.copyToByteArray(databytes,0,data.getPosition(),len);
111: fd.write(databytes);
112: fd.close();
113: }
114: catch(FileNotFoundException e)
115: {
116: e.printStackTrace();
117: }
118: catch(IOException e)
119: {
120: e.printStackTrace();
121: }
122: */
123: }
124:
125: public byte[] generate_hwid(String host)
126: throws UnsupportedEncodingException {
127: byte[] hwid = new byte[LICENSE_HWID_SIZE];
128: m_secure.setLittleEndian32(hwid, 2);
129: byte[] name = host.getBytes("US-ASCII");
130:
131: if (name.length > LICENSE_HWID_SIZE - 4) {
132: System.arraycopy(name, 0, hwid, 4, LICENSE_HWID_SIZE - 4);
133: } else {
134: System.arraycopy(name, 0, hwid, 4, name.length);
135: }
136:
137: return hwid;
138: }
139:
140: public void process(RdpPacket data) throws RdpDesktopException,
141: IOException, CryptoException {
142: int tag = 0;
143: tag = data.get8();
144: data.incrementPosition(3);
145:
146: switch (tag) {
147: case LICENSE_TAG_DEMAND: {
148: process_demand(data);
149: break;
150: }
151: case LICENSE_TAG_AUTHREQ: {
152: process_authreq(data);
153: break;
154: }
155: case LICENSE_TAG_ISSUE: {
156: process_issue(data);
157: break;
158: }
159: case LICENSE_TAG_REISSUE: {
160: break;
161: }
162: case LICENSE_TAG_RESULT: {
163: break;
164:
165: }
166: default: {
167: }
168: }
169: }
170:
171: public void process_demand(RdpPacket data)
172: throws UnsupportedEncodingException, RdpDesktopException,
173: IOException, CryptoException {
174: byte[] null_data = new byte[RdpSecure.SEC_MODULUS_SIZE];
175: byte[] server_random = new byte[RdpSecure.SEC_RANDOM_SIZE];
176: byte[] host = m_secure.m_rdpProto.m_host.getBytes("US-ASCII");
177: byte[] user = m_secure.m_rdpProto.m_username
178: .getBytes("US-ASCII");
179:
180: data.copyToByteArray(server_random, 0, data.getPosition(),
181: server_random.length);
182: data.incrementPosition(server_random.length);
183:
184: generate_keys(null_data, server_random, null_data);
185:
186: if ((RdpOptions.built_in_license == false)
187: && (RdpOptions.load_license == true)) {
188: byte[] license_data = load_license();
189: if ((license_data != null) && (license_data.length > 0)) {
190: byte[] hwid = generate_hwid(m_secure.m_rdpProto.m_host);
191: byte[] signature = m_secure.sign(m_license_sign_key,
192: 16, 16, hwid, hwid.length);
193:
194: RC4 rc4_license = new RC4();
195: byte[] crypt_key = new byte[m_license_key.length];
196: byte[] crypt_hwid = new byte[LICENSE_HWID_SIZE];
197: System.arraycopy(m_license_key, 0, crypt_key, 0,
198: m_license_key.length);
199: rc4_license.engineInitEncrypt(crypt_key);
200: rc4_license.crypt(hwid, 0, LICENSE_HWID_SIZE,
201: crypt_hwid, 0);
202:
203: present(null_data, null_data, license_data,
204: license_data.length, crypt_hwid, signature);
205: return;
206: }
207: }
208:
209: send_request(null_data, null_data, user, host);
210: }
211:
212: public boolean parse_authreq(RdpPacket data)
213: throws RdpDesktopException {
214: int tokenlen = 0;
215:
216: data.incrementPosition(6);
217:
218: tokenlen = data.getLittleEndian16();
219:
220: if (tokenlen != LICENSE_TOKEN_SIZE) {
221: throw new RdpDesktopException("Wrong Tokenlength!");
222: }
223:
224: m_in_token = new byte[tokenlen];
225: data.copyToByteArray(m_in_token, 0, data.getPosition(),
226: tokenlen);
227: data.incrementPosition(tokenlen);
228: m_in_sig = new byte[LICENSE_SIGNATURE_SIZE];
229: data.copyToByteArray(m_in_sig, 0, data.getPosition(),
230: LICENSE_SIGNATURE_SIZE);
231: data.incrementPosition(LICENSE_SIGNATURE_SIZE);
232:
233: if (data.getPosition() == data.getEnd()) {
234: return true;
235: } else {
236: return false;
237: }
238: }
239:
240: public void send_authresp(byte[] token, byte[] crypt_hwid,
241: byte[] signature) throws RdpDesktopException, IOException,
242: CryptoException {
243: int sec_flags = RdpSecure.SEC_LICENSE_NEG;
244: int length = 58;
245: RdpPacket data = null;
246:
247: data = m_secure.init(sec_flags, length + 2);
248:
249: data.set8(LICENSE_TAG_AUTHRESP);
250: data.set8(2);
251: data.setLittleEndian16(length);
252:
253: data.setLittleEndian16(1);
254: data.setLittleEndian16(LICENSE_TOKEN_SIZE);
255: data.copyFromByteArray(token, 0, data.getPosition(),
256: LICENSE_TOKEN_SIZE);
257: data.incrementPosition(LICENSE_TOKEN_SIZE);
258:
259: data.setLittleEndian16(1);
260: data.setLittleEndian16(LICENSE_HWID_SIZE);
261: data.copyFromByteArray(crypt_hwid, 0, data.getPosition(),
262: LICENSE_HWID_SIZE);
263: data.incrementPosition(LICENSE_HWID_SIZE);
264:
265: data.copyFromByteArray(signature, 0, data.getPosition(),
266: LICENSE_SIGNATURE_SIZE);
267: data.incrementPosition(LICENSE_SIGNATURE_SIZE);
268: data.markEnd();
269: m_secure.send(data, sec_flags);
270: }
271:
272: public void present(byte[] client_random, byte[] rsa_data,
273: byte[] license_data, int license_size, byte[] hwid,
274: byte[] signature) throws RdpDesktopException, IOException,
275: CryptoException {
276: int sec_flags = RdpSecure.SEC_LICENSE_NEG;
277: int length = 20 + RdpSecure.SEC_RANDOM_SIZE
278: + RdpSecure.SEC_MODULUS_SIZE
279: + RdpSecure.SEC_PADDING_SIZE + license_size
280: + LICENSE_HWID_SIZE + LICENSE_SIGNATURE_SIZE;
281:
282: RdpPacket s = m_secure.init(sec_flags, length + 4);
283:
284: s.set8(LICENSE_TAG_PRESENT);
285: s.set8(2);
286: s.setLittleEndian16(length);
287:
288: s.setLittleEndian32(1);
289: s.setLittleEndian16(0);
290: s.setLittleEndian16(0x0201);
291:
292: s.copyFromByteArray(client_random, 0, s.getPosition(),
293: RdpSecure.SEC_RANDOM_SIZE);
294: s.incrementPosition(RdpSecure.SEC_RANDOM_SIZE);
295: s.setLittleEndian16(0);
296: s
297: .setLittleEndian16((RdpSecure.SEC_MODULUS_SIZE + RdpSecure.SEC_PADDING_SIZE));
298: s.copyFromByteArray(rsa_data, 0, s.getPosition(),
299: RdpSecure.SEC_MODULUS_SIZE);
300: s.incrementPosition(RdpSecure.SEC_MODULUS_SIZE);
301: s.incrementPosition(RdpSecure.SEC_PADDING_SIZE);
302:
303: s.setLittleEndian16(1);
304: s.setLittleEndian16(license_size);
305: s.copyFromByteArray(license_data, 0, s.getPosition(),
306: license_size);
307: s.incrementPosition(license_size);
308:
309: s.setLittleEndian16(1);
310: s.setLittleEndian16(LICENSE_HWID_SIZE);
311: s
312: .copyFromByteArray(hwid, 0, s.getPosition(),
313: LICENSE_HWID_SIZE);
314: s.incrementPosition(LICENSE_HWID_SIZE);
315: s.copyFromByteArray(signature, 0, s.getPosition(),
316: LICENSE_SIGNATURE_SIZE);
317: s.incrementPosition(LICENSE_SIGNATURE_SIZE);
318:
319: s.markEnd();
320: m_secure.send(s, sec_flags);
321: }
322:
323: public void process_authreq(RdpPacket data)
324: throws RdpDesktopException, UnsupportedEncodingException,
325: IOException, CryptoException {
326: byte[] out_token = new byte[LICENSE_TOKEN_SIZE];
327: byte[] decrypt_token = new byte[LICENSE_TOKEN_SIZE];
328:
329: byte[] crypt_hwid = new byte[LICENSE_HWID_SIZE];
330: byte[] sealed_buffer = new byte[LICENSE_TOKEN_SIZE
331: + LICENSE_HWID_SIZE];
332: byte[] out_sig = new byte[LICENSE_SIGNATURE_SIZE];
333: RC4 rc4_license = new RC4();
334: byte[] crypt_key = null;
335:
336: if (parse_authreq(data) != true) {
337: throw new RdpDesktopException(
338: "Authentication Request was corrupt!");
339: }
340:
341: System.arraycopy(m_in_token, 0, out_token, 0,
342: LICENSE_TOKEN_SIZE);
343:
344: crypt_key = new byte[m_license_key.length];
345: System.arraycopy(m_license_key, 0, crypt_key, 0,
346: m_license_key.length);
347: rc4_license.engineInitDecrypt(crypt_key);
348: rc4_license.crypt(m_in_token, 0, LICENSE_TOKEN_SIZE,
349: decrypt_token, 0);
350:
351: byte[] hwid = generate_hwid(m_secure.m_rdpProto.m_host);
352:
353: System.arraycopy(decrypt_token, 0, sealed_buffer, 0,
354: LICENSE_TOKEN_SIZE);
355: System.arraycopy(hwid, 0, sealed_buffer, LICENSE_TOKEN_SIZE,
356: LICENSE_HWID_SIZE);
357:
358: out_sig = m_secure.sign(m_license_sign_key, 16, 16,
359: sealed_buffer, sealed_buffer.length);
360:
361: if (RdpOptions.license == false) {
362: out_sig = new byte[LICENSE_SIGNATURE_SIZE];
363: }
364:
365: System.arraycopy(m_license_key, 0, crypt_key, 0,
366: m_license_key.length);
367: rc4_license.engineInitEncrypt(crypt_key);
368: rc4_license.crypt(hwid, 0, LICENSE_HWID_SIZE, crypt_hwid, 0);
369:
370: send_authresp(out_token, crypt_hwid, out_sig);
371: }
372:
373: public void process_issue(RdpPacket data) throws CryptoException {
374: int length = 0;
375: int check = 0;
376: RC4 rc4_license = new RC4();
377: byte[] key = new byte[m_license_key.length];
378: System
379: .arraycopy(m_license_key, 0, key, 0,
380: m_license_key.length);
381:
382: data.incrementPosition(2);
383: length = data.getLittleEndian16();
384:
385: if (data.getPosition() + length > data.getEnd()) {
386: return;
387: }
388:
389: rc4_license.engineInitDecrypt(key);
390: byte[] buffer = new byte[length];
391: data.copyToByteArray(buffer, 0, data.getPosition(), length);
392: rc4_license.crypt(buffer, 0, length, buffer, 0);
393: data.copyFromByteArray(buffer, 0, data.getPosition(), length);
394:
395: check = data.getLittleEndian16();
396: /*
397: if (check!=0)
398: {
399: return;
400: }
401: */
402: m_secure.m_licenseIssued = true;
403:
404: /*
405: data.incrementPosition(2);
406:
407: length = 0;
408: for (int i = 0; i < 4; i++)
409: {
410: data.incrementPosition(length);
411: length = data.getLittleEndian32(length);
412:
413: if ((data.getPosition() + length <= data.getEnd()) == false)
414: {
415: return;
416: }
417: }
418: */
419:
420: m_secure.m_licenseIssued = true;
421:
422: if (RdpOptions.save_license == true) {
423: save_license(m_secure.m_rdpProto.m_host, data, length - 2);
424: }
425: }
426:
427: public void send_request(byte[] client_random, byte[] rsa_data,
428: byte[] username, byte[] hostname)
429: throws RdpDesktopException, IOException, CryptoException {
430: int sec_flags = RdpSecure.SEC_LICENSE_NEG;
431: int userlen = (username.length == 0 ? 0 : username.length + 1);
432: int hostlen = (hostname.length == 0 ? 0 : hostname.length + 1);
433: int length = 128 + userlen + hostlen;
434:
435: RdpPacket buffer = m_secure.init(sec_flags, length);
436:
437: buffer.set8(LICENSE_TAG_REQUEST);
438: buffer.set8(2);
439: buffer.setLittleEndian16(length);
440:
441: buffer.setLittleEndian32(1);
442:
443: if ((RdpOptions.built_in_license == true)
444: && (RdpOptions.load_license == false)
445: && (RdpOptions.save_license == false)) {
446: buffer.setLittleEndian32(0x03010000);
447: } else {
448: buffer.setLittleEndian32(0xff010000);
449: }
450:
451: buffer.copyFromByteArray(client_random, 0,
452: buffer.getPosition(), RdpSecure.SEC_RANDOM_SIZE);
453: buffer.incrementPosition(RdpSecure.SEC_RANDOM_SIZE);
454: buffer.setLittleEndian16(0);
455:
456: buffer.setLittleEndian16(RdpSecure.SEC_MODULUS_SIZE
457: + RdpSecure.SEC_PADDING_SIZE);
458: buffer.copyFromByteArray(rsa_data, 0, buffer.getPosition(),
459: RdpSecure.SEC_MODULUS_SIZE);
460: buffer.incrementPosition(RdpSecure.SEC_MODULUS_SIZE);
461:
462: buffer.incrementPosition(RdpSecure.SEC_PADDING_SIZE);
463:
464: buffer.setLittleEndian16(LICENSE_TAG_USER);
465: buffer.setLittleEndian16(userlen);
466:
467: if (username.length != 0) {
468: buffer.copyFromByteArray(username, 0, buffer.getPosition(),
469: userlen - 1);
470: } else {
471: buffer.copyFromByteArray(username, 0, buffer.getPosition(),
472: userlen);
473: }
474:
475: buffer.incrementPosition(userlen);
476:
477: buffer.setLittleEndian16(LICENSE_TAG_HOST);
478: buffer.setLittleEndian16(hostlen);
479:
480: if (hostname.length != 0) {
481: buffer.copyFromByteArray(hostname, 0, buffer.getPosition(),
482: hostlen - 1);
483: } else {
484: buffer.copyFromByteArray(hostname, 0, buffer.getPosition(),
485: hostlen);
486: }
487:
488: buffer.incrementPosition(hostlen);
489: buffer.markEnd();
490: m_secure.send(buffer, sec_flags);
491: }
492:
493: public void generate_keys(byte[] client_key, byte[] server_key,
494: byte[] client_rsa) throws CryptoException {
495: byte[] session_key = new byte[48];
496: byte[] temp_hash = new byte[48];
497:
498: temp_hash = m_secure.hash48(client_rsa, client_key, server_key,
499: 65);
500: session_key = m_secure.hash48(temp_hash, server_key,
501: client_key, 65);
502:
503: System.arraycopy(session_key, 0, m_license_sign_key, 0, 16);
504:
505: m_license_key = m_secure.hash16(session_key, client_key,
506: server_key, 16);
507: }
508: }
|