123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import Check from "./Check.js";
- import RuntimeError from "./RuntimeError.js";
- const compressedMagic = 0x7468dead;
- const compressedMagicSwap = 0xadde6874;
- /**
- * Decodes data that is received from the Google Earth Enterprise server.
- *
- * @param {ArrayBuffer} key The key used during decoding.
- * @param {ArrayBuffer} data The data to be decoded.
- *
- * @private
- */
- function decodeGoogleEarthEnterpriseData(key, data) {
- if (decodeGoogleEarthEnterpriseData.passThroughDataForTesting) {
- return data;
- }
- //>>includeStart('debug', pragmas.debug);
- Check.typeOf.object("key", key);
- Check.typeOf.object("data", data);
- //>>includeEnd('debug');
- const keyLength = key.byteLength;
- if (keyLength === 0 || keyLength % 4 !== 0) {
- throw new RuntimeError(
- "The length of key must be greater than 0 and a multiple of 4."
- );
- }
- const dataView = new DataView(data);
- const magic = dataView.getUint32(0, true);
- if (magic === compressedMagic || magic === compressedMagicSwap) {
- // Occasionally packets don't come back encoded, so just return
- return data;
- }
- const keyView = new DataView(key);
- let dp = 0;
- const dpend = data.byteLength;
- const dpend64 = dpend - (dpend % 8);
- const kpend = keyLength;
- let kp;
- let off = 8;
- // This algorithm is intentionally asymmetric to make it more difficult to
- // guess. Security through obscurity. :-(
- // while we have a full uint64 (8 bytes) left to do
- // assumes buffer is 64bit aligned (or processor doesn't care)
- while (dp < dpend64) {
- // rotate the key each time through by using the offets 16,0,8,16,0,8,...
- off = (off + 8) % 24;
- kp = off;
- // run through one key length xor'ing one uint64 at a time
- // then drop out to rotate the key for the next bit
- while (dp < dpend64 && kp < kpend) {
- dataView.setUint32(
- dp,
- dataView.getUint32(dp, true) ^ keyView.getUint32(kp, true),
- true
- );
- dataView.setUint32(
- dp + 4,
- dataView.getUint32(dp + 4, true) ^ keyView.getUint32(kp + 4, true),
- true
- );
- dp += 8;
- kp += 24;
- }
- }
- // now the remaining 1 to 7 bytes
- if (dp < dpend) {
- if (kp >= kpend) {
- // rotate the key one last time (if necessary)
- off = (off + 8) % 24;
- kp = off;
- }
- while (dp < dpend) {
- dataView.setUint8(dp, dataView.getUint8(dp) ^ keyView.getUint8(kp));
- dp++;
- kp++;
- }
- }
- }
- decodeGoogleEarthEnterpriseData.passThroughDataForTesting = false;
- export default decodeGoogleEarthEnterpriseData;
|