decodeGoogleEarthEnterpriseData.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import Check from './Check.js';
  2. import RuntimeError from './RuntimeError.js';
  3. var compressedMagic = 0x7468dead;
  4. var compressedMagicSwap = 0xadde6874;
  5. /**
  6. * Decodes data that is received from the Google Earth Enterprise server.
  7. *
  8. * @param {ArrayBuffer} key The key used during decoding.
  9. * @param {ArrayBuffer} data The data to be decoded.
  10. *
  11. * @private
  12. */
  13. function decodeGoogleEarthEnterpriseData(key, data) {
  14. if (decodeGoogleEarthEnterpriseData.passThroughDataForTesting) {
  15. return data;
  16. }
  17. //>>includeStart('debug', pragmas.debug);
  18. Check.typeOf.object('key', key);
  19. Check.typeOf.object('data', data);
  20. //>>includeEnd('debug');
  21. var keyLength = key.byteLength;
  22. if (keyLength === 0 || (keyLength % 4) !== 0) {
  23. throw new RuntimeError('The length of key must be greater than 0 and a multiple of 4.');
  24. }
  25. var dataView = new DataView(data);
  26. var magic = dataView.getUint32(0, true);
  27. if (magic === compressedMagic || magic === compressedMagicSwap) {
  28. // Occasionally packets don't come back encoded, so just return
  29. return data;
  30. }
  31. var keyView = new DataView(key);
  32. var dp = 0;
  33. var dpend = data.byteLength;
  34. var dpend64 = dpend - (dpend % 8);
  35. var kpend = keyLength;
  36. var kp;
  37. var off = 8;
  38. // This algorithm is intentionally asymmetric to make it more difficult to
  39. // guess. Security through obscurity. :-(
  40. // while we have a full uint64 (8 bytes) left to do
  41. // assumes buffer is 64bit aligned (or processor doesn't care)
  42. while (dp < dpend64) {
  43. // rotate the key each time through by using the offets 16,0,8,16,0,8,...
  44. off = (off + 8) % 24;
  45. kp = off;
  46. // run through one key length xor'ing one uint64 at a time
  47. // then drop out to rotate the key for the next bit
  48. while ((dp < dpend64) && (kp < kpend)) {
  49. dataView.setUint32(dp, dataView.getUint32(dp, true) ^ keyView.getUint32(kp, true), true);
  50. dataView.setUint32(dp + 4, dataView.getUint32(dp + 4, true) ^ keyView.getUint32(kp + 4, true), true);
  51. dp += 8;
  52. kp += 24;
  53. }
  54. }
  55. // now the remaining 1 to 7 bytes
  56. if (dp < dpend) {
  57. if (kp >= kpend) {
  58. // rotate the key one last time (if necessary)
  59. off = (off + 8) % 24;
  60. kp = off;
  61. }
  62. while (dp < dpend) {
  63. dataView.setUint8(dp, dataView.getUint8(dp) ^ keyView.getUint8(kp));
  64. dp++;
  65. kp++;
  66. }
  67. }
  68. }
  69. decodeGoogleEarthEnterpriseData.passThroughDataForTesting = false;
  70. export default decodeGoogleEarthEnterpriseData;