Расшифровка тайлов
Последнее изменение: 02/06/2020 13:36:32Все тайлы, передаваемые сервером клиенту являются зашифрованными. Векторные и служебные типы данных (т.е. всё, кроме картинок) дополнительно запаковано в zlib архив. В таком же, оригинальном виде, тайлы сохраняются и в кэш клиента (клиенты версии 5.1 и выше при определённых настройках могут сохранять в кэш не оригинальные тайлы. Конкретно, это касается снимков: Формат снимков в кэше GE 5.1 и выше).
Расшифровка/Шифровка тайлов
Алгоритм шифрования GoogleEarth двунаправленный, это значит, что если ему на вход подать зашифрованный тайл, то после обработки мы получим его дешифрованный вариант (т.е. исходный, что был до шифровки), и аналогично, если мы подадим на вход алгоритму не зашифрованный тайл - на выходе получим его зашифрованный вариант.
Крипто-алгоритм в своей работе использует ключ, которым все данные и шифруются. Ключ этот передаётся клиенту в составе файла dbRoot.v5. Длина ключа в алгоритме - 1024 байта. Ключ для алгоритма получается путём добавления 8 байт заполненных нулями к ключу из dbRoot.v5 (в котором он занимает 1016 байт). Про извлечение ключа из dbRoot.v5 смотреть тут: Назначение и устройство файла dbRoot.v5.
За время существования сервиса, ключ ещё ни разу не изменялся. Вот его подготовленный для алгоритма вариант (добитый нулями до 1024 байт): key.bin
Пример алгоритма криптования:
- procedure CryptTile (Tile: Pointer; Size: integer);
- const
- KeyLen = 1016;
- var
- i,j: integer;
- begin
- if size = 0 then
- Exit;
- j := 16;
- for i := 0 to Size - 1 do
- begin
- Byte(Pointer(LongWord(Tile) + LongWord(i))^) :=
- Byte(Pointer(LongWord(Tile) + LongWord(i))^) xor key[j+8];
- inc(j);
- if (j mod 8) = 0 then
- j := j + 16;
- if j >= KeyLen then
- j := (j + 8) Mod 24;
- end;
- end;
- sub ge_crypt {
- my $ref = $_[0]; #ссылка на тайл
- my @data = unpack("C*", $$ref);
- for (my ($i) = 0, my ($j) = 0x10; $i < length("$$ref"); $i++) {
- $data[$i] ^= $key[$j+8]; $j++;
- if ( ($j % 8) == 0 ) {
- $j += 0x10
- };
- if ( $j >= 0x03f8 ) {
- $j = ($j+8) % 24
- };
- }
- return pack("C*", @data);
- }
Распаковка тайлов
Упакованные тайлы имеют следующую структуру:
- type
- TPackZlib = packed record
- Magic : LongWord; // идентификатор архива 0xADDE6874
- USize : LongWord; // размер распакованного архива
- Data : array of byte; // архив
- end;
Алгоритм распаковки:
- uses zlib;
- ...
- function UnPackGEZlib(InPut: Pointer; InPutSize: integer;
- out OutPut: Pointer; out OutPutSize: integer): Boolean;
- const
- DECRYPTED_ZLIB = $7468DEAD;
- begin
- result := False;
- if LongWord(InPut^) = DECRYPTED_ZLIB then
- begin
- OutPutSize := LongWord(Pointer(LongWord(InPut) + 4)^);
- DecompressBuf(Pointer(LongWord(InPut) + 8), InPutSize - 8,
- OutPutSize, OutPut, OutPutSize);
- result := True;
- end
- else
- begin
- OutPut := nil;
- OutPutSize := 0;
- end;
- end;
- use Compress::Zlib;
- ...
- sub zlib_unpack {
- my $ref = $_[0]; #ссылка на декриптованный тайл
- my @data = unpack("C*", $$ref);
- my @h = splice (@data,0,8); #первые 8 байт -> Magic и Uncompress Size
- my $magic = $h[3] + ($h[2] << 8) + ($h[1] << 16) + ($h[0] << 24);
- my $uncompress_size = $h[4] + ($h[5] << 8) + ($h[6] << 16) + ($h[7] << 24);
- if ($magic == 0xADDE6874) {
- my $raw = pack("C*", @data);
- return uncompress(\$raw);
- }
- }
В итоге, после всех этих операций, мы получаем "сырые" данные с которыми и оперирует клиент.