susi-qemu 0.0.2 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. checksums.yaml +4 -4
  2. data/bin/susi +9 -4
  3. data/lib/disk.rb +7 -5
  4. data/lib/novnc/core/base64.js +104 -0
  5. data/lib/novnc/core/crypto/aes.js +178 -0
  6. data/lib/novnc/core/crypto/bigint.js +34 -0
  7. data/lib/novnc/core/crypto/crypto.js +90 -0
  8. data/lib/novnc/core/crypto/des.js +330 -0
  9. data/lib/novnc/core/crypto/dh.js +55 -0
  10. data/lib/novnc/core/crypto/md5.js +82 -0
  11. data/lib/novnc/core/crypto/rsa.js +132 -0
  12. data/lib/novnc/core/decoders/copyrect.js +27 -0
  13. data/lib/novnc/core/decoders/h264.js +321 -0
  14. data/lib/novnc/core/decoders/hextile.js +181 -0
  15. data/lib/novnc/core/decoders/jpeg.js +146 -0
  16. data/lib/novnc/core/decoders/raw.js +59 -0
  17. data/lib/novnc/core/decoders/rre.js +44 -0
  18. data/lib/novnc/core/decoders/tight.js +393 -0
  19. data/lib/novnc/core/decoders/tightpng.js +27 -0
  20. data/lib/novnc/core/decoders/zlib.js +51 -0
  21. data/lib/novnc/core/decoders/zrle.js +185 -0
  22. data/lib/novnc/core/deflator.js +84 -0
  23. data/lib/novnc/core/display.js +575 -0
  24. data/lib/novnc/core/encodings.js +53 -0
  25. data/lib/novnc/core/inflator.js +65 -0
  26. data/lib/novnc/core/input/domkeytable.js +311 -0
  27. data/lib/novnc/core/input/fixedkeys.js +129 -0
  28. data/lib/novnc/core/input/gesturehandler.js +567 -0
  29. data/lib/novnc/core/input/keyboard.js +294 -0
  30. data/lib/novnc/core/input/keysym.js +616 -0
  31. data/lib/novnc/core/input/keysymdef.js +688 -0
  32. data/lib/novnc/core/input/util.js +191 -0
  33. data/lib/novnc/core/input/vkeys.js +116 -0
  34. data/lib/novnc/core/input/xtscancodes.js +173 -0
  35. data/lib/novnc/core/ra2.js +312 -0
  36. data/lib/novnc/core/rfb.js +3257 -0
  37. data/lib/novnc/core/util/browser.js +172 -0
  38. data/lib/novnc/core/util/cursor.js +249 -0
  39. data/lib/novnc/core/util/element.js +32 -0
  40. data/lib/novnc/core/util/events.js +138 -0
  41. data/lib/novnc/core/util/eventtarget.js +35 -0
  42. data/lib/novnc/core/util/int.js +15 -0
  43. data/lib/novnc/core/util/logging.js +56 -0
  44. data/lib/novnc/core/util/strings.js +28 -0
  45. data/lib/novnc/core/websock.js +365 -0
  46. data/lib/novnc/screen.html +21 -0
  47. data/lib/novnc/vendor/pako/lib/utils/common.js +45 -0
  48. data/lib/novnc/vendor/pako/lib/zlib/adler32.js +27 -0
  49. data/lib/novnc/vendor/pako/lib/zlib/constants.js +47 -0
  50. data/lib/novnc/vendor/pako/lib/zlib/crc32.js +36 -0
  51. data/lib/novnc/vendor/pako/lib/zlib/deflate.js +1846 -0
  52. data/lib/novnc/vendor/pako/lib/zlib/gzheader.js +35 -0
  53. data/lib/novnc/vendor/pako/lib/zlib/inffast.js +324 -0
  54. data/lib/novnc/vendor/pako/lib/zlib/inflate.js +1527 -0
  55. data/lib/novnc/vendor/pako/lib/zlib/inftrees.js +322 -0
  56. data/lib/novnc/vendor/pako/lib/zlib/messages.js +11 -0
  57. data/lib/novnc/vendor/pako/lib/zlib/trees.js +1195 -0
  58. data/lib/novnc/vendor/pako/lib/zlib/zstream.js +24 -0
  59. data/lib/output.rb +11 -0
  60. data/lib/qmp.rb +6 -0
  61. data/lib/ssh.rb +3 -1
  62. data/lib/susi.rb +7 -6
  63. data/lib/version.rb +1 -1
  64. data/lib/vm.rb +44 -26
  65. data/lib/vnc.rb +34 -31
  66. metadata +57 -1
@@ -0,0 +1,312 @@
1
+ import { encodeUTF8 } from './util/strings.js';
2
+ import EventTargetMixin from './util/eventtarget.js';
3
+ import legacyCrypto from './crypto/crypto.js';
4
+
5
+ class RA2Cipher {
6
+ constructor() {
7
+ this._cipher = null;
8
+ this._counter = new Uint8Array(16);
9
+ }
10
+
11
+ async setKey(key) {
12
+ this._cipher = await legacyCrypto.importKey(
13
+ "raw", key, { name: "AES-EAX" }, false, ["encrypt, decrypt"]);
14
+ }
15
+
16
+ async makeMessage(message) {
17
+ const ad = new Uint8Array([(message.length & 0xff00) >>> 8, message.length & 0xff]);
18
+ const encrypted = await legacyCrypto.encrypt({
19
+ name: "AES-EAX",
20
+ iv: this._counter,
21
+ additionalData: ad,
22
+ }, this._cipher, message);
23
+ for (let i = 0; i < 16 && this._counter[i]++ === 255; i++);
24
+ const res = new Uint8Array(message.length + 2 + 16);
25
+ res.set(ad);
26
+ res.set(encrypted, 2);
27
+ return res;
28
+ }
29
+
30
+ async receiveMessage(length, encrypted) {
31
+ const ad = new Uint8Array([(length & 0xff00) >>> 8, length & 0xff]);
32
+ const res = await legacyCrypto.decrypt({
33
+ name: "AES-EAX",
34
+ iv: this._counter,
35
+ additionalData: ad,
36
+ }, this._cipher, encrypted);
37
+ for (let i = 0; i < 16 && this._counter[i]++ === 255; i++);
38
+ return res;
39
+ }
40
+ }
41
+
42
+ export default class RSAAESAuthenticationState extends EventTargetMixin {
43
+ constructor(sock, getCredentials) {
44
+ super();
45
+ this._hasStarted = false;
46
+ this._checkSock = null;
47
+ this._checkCredentials = null;
48
+ this._approveServerResolve = null;
49
+ this._sockReject = null;
50
+ this._credentialsReject = null;
51
+ this._approveServerReject = null;
52
+ this._sock = sock;
53
+ this._getCredentials = getCredentials;
54
+ }
55
+
56
+ _waitSockAsync(len) {
57
+ return new Promise((resolve, reject) => {
58
+ const hasData = () => !this._sock.rQwait('RA2', len);
59
+ if (hasData()) {
60
+ resolve();
61
+ } else {
62
+ this._checkSock = () => {
63
+ if (hasData()) {
64
+ resolve();
65
+ this._checkSock = null;
66
+ this._sockReject = null;
67
+ }
68
+ };
69
+ this._sockReject = reject;
70
+ }
71
+ });
72
+ }
73
+
74
+ _waitApproveKeyAsync() {
75
+ return new Promise((resolve, reject) => {
76
+ this._approveServerResolve = resolve;
77
+ this._approveServerReject = reject;
78
+ });
79
+ }
80
+
81
+ _waitCredentialsAsync(subtype) {
82
+ const hasCredentials = () => {
83
+ if (subtype === 1 && this._getCredentials().username !== undefined &&
84
+ this._getCredentials().password !== undefined) {
85
+ return true;
86
+ } else if (subtype === 2 && this._getCredentials().password !== undefined) {
87
+ return true;
88
+ }
89
+ return false;
90
+ };
91
+ return new Promise((resolve, reject) => {
92
+ if (hasCredentials()) {
93
+ resolve();
94
+ } else {
95
+ this._checkCredentials = () => {
96
+ if (hasCredentials()) {
97
+ resolve();
98
+ this._checkCredentials = null;
99
+ this._credentialsReject = null;
100
+ }
101
+ };
102
+ this._credentialsReject = reject;
103
+ }
104
+ });
105
+ }
106
+
107
+ checkInternalEvents() {
108
+ if (this._checkSock !== null) {
109
+ this._checkSock();
110
+ }
111
+ if (this._checkCredentials !== null) {
112
+ this._checkCredentials();
113
+ }
114
+ }
115
+
116
+ approveServer() {
117
+ if (this._approveServerResolve !== null) {
118
+ this._approveServerResolve();
119
+ this._approveServerResolve = null;
120
+ }
121
+ }
122
+
123
+ disconnect() {
124
+ if (this._sockReject !== null) {
125
+ this._sockReject(new Error("disconnect normally"));
126
+ this._sockReject = null;
127
+ }
128
+ if (this._credentialsReject !== null) {
129
+ this._credentialsReject(new Error("disconnect normally"));
130
+ this._credentialsReject = null;
131
+ }
132
+ if (this._approveServerReject !== null) {
133
+ this._approveServerReject(new Error("disconnect normally"));
134
+ this._approveServerReject = null;
135
+ }
136
+ }
137
+
138
+ async negotiateRA2neAuthAsync() {
139
+ this._hasStarted = true;
140
+ // 1: Receive server public key
141
+ await this._waitSockAsync(4);
142
+ const serverKeyLengthBuffer = this._sock.rQpeekBytes(4);
143
+ const serverKeyLength = this._sock.rQshift32();
144
+ if (serverKeyLength < 1024) {
145
+ throw new Error("RA2: server public key is too short: " + serverKeyLength);
146
+ } else if (serverKeyLength > 8192) {
147
+ throw new Error("RA2: server public key is too long: " + serverKeyLength);
148
+ }
149
+ const serverKeyBytes = Math.ceil(serverKeyLength / 8);
150
+ await this._waitSockAsync(serverKeyBytes * 2);
151
+ const serverN = this._sock.rQshiftBytes(serverKeyBytes);
152
+ const serverE = this._sock.rQshiftBytes(serverKeyBytes);
153
+ const serverRSACipher = await legacyCrypto.importKey(
154
+ "raw", { n: serverN, e: serverE }, { name: "RSA-PKCS1-v1_5" }, false, ["encrypt"]);
155
+ const serverPublickey = new Uint8Array(4 + serverKeyBytes * 2);
156
+ serverPublickey.set(serverKeyLengthBuffer);
157
+ serverPublickey.set(serverN, 4);
158
+ serverPublickey.set(serverE, 4 + serverKeyBytes);
159
+
160
+ // verify server public key
161
+ let approveKey = this._waitApproveKeyAsync();
162
+ this.dispatchEvent(new CustomEvent("serververification", {
163
+ detail: { type: "RSA", publickey: serverPublickey }
164
+ }));
165
+ await approveKey;
166
+
167
+ // 2: Send client public key
168
+ const clientKeyLength = 2048;
169
+ const clientKeyBytes = Math.ceil(clientKeyLength / 8);
170
+ const clientRSACipher = (await legacyCrypto.generateKey({
171
+ name: "RSA-PKCS1-v1_5",
172
+ modulusLength: clientKeyLength,
173
+ publicExponent: new Uint8Array([1, 0, 1]),
174
+ }, true, ["encrypt"])).privateKey;
175
+ const clientExportedRSAKey = await legacyCrypto.exportKey("raw", clientRSACipher);
176
+ const clientN = clientExportedRSAKey.n;
177
+ const clientE = clientExportedRSAKey.e;
178
+ const clientPublicKey = new Uint8Array(4 + clientKeyBytes * 2);
179
+ clientPublicKey[0] = (clientKeyLength & 0xff000000) >>> 24;
180
+ clientPublicKey[1] = (clientKeyLength & 0xff0000) >>> 16;
181
+ clientPublicKey[2] = (clientKeyLength & 0xff00) >>> 8;
182
+ clientPublicKey[3] = clientKeyLength & 0xff;
183
+ clientPublicKey.set(clientN, 4);
184
+ clientPublicKey.set(clientE, 4 + clientKeyBytes);
185
+ this._sock.sQpushBytes(clientPublicKey);
186
+ this._sock.flush();
187
+
188
+ // 3: Send client random
189
+ const clientRandom = new Uint8Array(16);
190
+ window.crypto.getRandomValues(clientRandom);
191
+ const clientEncryptedRandom = await legacyCrypto.encrypt(
192
+ { name: "RSA-PKCS1-v1_5" }, serverRSACipher, clientRandom);
193
+ const clientRandomMessage = new Uint8Array(2 + serverKeyBytes);
194
+ clientRandomMessage[0] = (serverKeyBytes & 0xff00) >>> 8;
195
+ clientRandomMessage[1] = serverKeyBytes & 0xff;
196
+ clientRandomMessage.set(clientEncryptedRandom, 2);
197
+ this._sock.sQpushBytes(clientRandomMessage);
198
+ this._sock.flush();
199
+
200
+ // 4: Receive server random
201
+ await this._waitSockAsync(2);
202
+ if (this._sock.rQshift16() !== clientKeyBytes) {
203
+ throw new Error("RA2: wrong encrypted message length");
204
+ }
205
+ const serverEncryptedRandom = this._sock.rQshiftBytes(clientKeyBytes);
206
+ const serverRandom = await legacyCrypto.decrypt(
207
+ { name: "RSA-PKCS1-v1_5" }, clientRSACipher, serverEncryptedRandom);
208
+ if (serverRandom === null || serverRandom.length !== 16) {
209
+ throw new Error("RA2: corrupted server encrypted random");
210
+ }
211
+
212
+ // 5: Compute session keys and set ciphers
213
+ let clientSessionKey = new Uint8Array(32);
214
+ let serverSessionKey = new Uint8Array(32);
215
+ clientSessionKey.set(serverRandom);
216
+ clientSessionKey.set(clientRandom, 16);
217
+ serverSessionKey.set(clientRandom);
218
+ serverSessionKey.set(serverRandom, 16);
219
+ clientSessionKey = await window.crypto.subtle.digest("SHA-1", clientSessionKey);
220
+ clientSessionKey = new Uint8Array(clientSessionKey).slice(0, 16);
221
+ serverSessionKey = await window.crypto.subtle.digest("SHA-1", serverSessionKey);
222
+ serverSessionKey = new Uint8Array(serverSessionKey).slice(0, 16);
223
+ const clientCipher = new RA2Cipher();
224
+ await clientCipher.setKey(clientSessionKey);
225
+ const serverCipher = new RA2Cipher();
226
+ await serverCipher.setKey(serverSessionKey);
227
+
228
+ // 6: Compute and exchange hashes
229
+ let serverHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2);
230
+ let clientHash = new Uint8Array(8 + serverKeyBytes * 2 + clientKeyBytes * 2);
231
+ serverHash.set(serverPublickey);
232
+ serverHash.set(clientPublicKey, 4 + serverKeyBytes * 2);
233
+ clientHash.set(clientPublicKey);
234
+ clientHash.set(serverPublickey, 4 + clientKeyBytes * 2);
235
+ serverHash = await window.crypto.subtle.digest("SHA-1", serverHash);
236
+ clientHash = await window.crypto.subtle.digest("SHA-1", clientHash);
237
+ serverHash = new Uint8Array(serverHash);
238
+ clientHash = new Uint8Array(clientHash);
239
+ this._sock.sQpushBytes(await clientCipher.makeMessage(clientHash));
240
+ this._sock.flush();
241
+ await this._waitSockAsync(2 + 20 + 16);
242
+ if (this._sock.rQshift16() !== 20) {
243
+ throw new Error("RA2: wrong server hash");
244
+ }
245
+ const serverHashReceived = await serverCipher.receiveMessage(
246
+ 20, this._sock.rQshiftBytes(20 + 16));
247
+ if (serverHashReceived === null) {
248
+ throw new Error("RA2: failed to authenticate the message");
249
+ }
250
+ for (let i = 0; i < 20; i++) {
251
+ if (serverHashReceived[i] !== serverHash[i]) {
252
+ throw new Error("RA2: wrong server hash");
253
+ }
254
+ }
255
+
256
+ // 7: Receive subtype
257
+ await this._waitSockAsync(2 + 1 + 16);
258
+ if (this._sock.rQshift16() !== 1) {
259
+ throw new Error("RA2: wrong subtype");
260
+ }
261
+ let subtype = (await serverCipher.receiveMessage(
262
+ 1, this._sock.rQshiftBytes(1 + 16)));
263
+ if (subtype === null) {
264
+ throw new Error("RA2: failed to authenticate the message");
265
+ }
266
+ subtype = subtype[0];
267
+ let waitCredentials = this._waitCredentialsAsync(subtype);
268
+ if (subtype === 1) {
269
+ if (this._getCredentials().username === undefined ||
270
+ this._getCredentials().password === undefined) {
271
+ this.dispatchEvent(new CustomEvent(
272
+ "credentialsrequired",
273
+ { detail: { types: ["username", "password"] } }));
274
+ }
275
+ } else if (subtype === 2) {
276
+ if (this._getCredentials().password === undefined) {
277
+ this.dispatchEvent(new CustomEvent(
278
+ "credentialsrequired",
279
+ { detail: { types: ["password"] } }));
280
+ }
281
+ } else {
282
+ throw new Error("RA2: wrong subtype");
283
+ }
284
+ await waitCredentials;
285
+ let username;
286
+ if (subtype === 1) {
287
+ username = encodeUTF8(this._getCredentials().username).slice(0, 255);
288
+ } else {
289
+ username = "";
290
+ }
291
+ const password = encodeUTF8(this._getCredentials().password).slice(0, 255);
292
+ const credentials = new Uint8Array(username.length + password.length + 2);
293
+ credentials[0] = username.length;
294
+ credentials[username.length + 1] = password.length;
295
+ for (let i = 0; i < username.length; i++) {
296
+ credentials[i + 1] = username.charCodeAt(i);
297
+ }
298
+ for (let i = 0; i < password.length; i++) {
299
+ credentials[username.length + 2 + i] = password.charCodeAt(i);
300
+ }
301
+ this._sock.sQpushBytes(await clientCipher.makeMessage(credentials));
302
+ this._sock.flush();
303
+ }
304
+
305
+ get hasStarted() {
306
+ return this._hasStarted;
307
+ }
308
+
309
+ set hasStarted(s) {
310
+ this._hasStarted = s;
311
+ }
312
+ }