Как расшифровать gif файл
Декодирование GIF
В прошлый раз мы разобрались как устроен JPEG (Декодирование JPEG для чайников). Вполне логично, что следующим форматом стал GIF. Кстати, он гораздо проще. Его, в отличии от JPEG, можно декодировать имея только ручку с бумажкой. Сначала, продолжая традицию, я захотел закодировать в GIF favicon Гугла, но потом решил, что лучше расписать процесс декодирования всего файла на маленьком изображении. Без всяких «а дальше по аналогии. ». Пришлось долго экспериментировать, и картинка получилась неказистой, зато вполне наглядной для изучения.
Итак, мы будем ковырять вот эту картинку . Видите? 🙂 Тогда она же, увеличенная в 10 раз:
Внутренности в hex-редакторе:
Заголовок
[47 49 46 38 37 61] GIF87a.
Тут может быть и GIF89a. Эти форматы различаются опциональными дополнительными секциями, которые мы не будем рассматривать, они описаны в спецификации.
Следом расположена секция
Logical Screen Descriptor
Изображение расположено в некотором logical screen и может быть сдвинуто относительно верхнего левого угла этого экрана. У всех просмотренных мною файлов размеры картинки и экрана совпадали.
Следом расположена секция
Global Color Table
Читаем 12 байт, и формируем такую табличку:
R G B
[04 02 04] — почти черный (это кодировщик так решил)
[FC FE FC] — почти белый
[FC 02 04] — почти красный
[00 00 00] — в нашем примере не используется.
Image Descriptor [2C]
[00 00] [00 00] = (0, 0). Координаты верхнего левого угла в logical screen
[04 00] [04 00] = 4×4. Размеры изображения
[00] = 00000000.
(0) = 0. Локальная таблица цветов не используется.
(0) = 0. Интерлейс не используется (если 1, то меняется порядок строк, см Spec. Appendix E)
(0) = 0. Локальная таблица цветов не отсортирована.
(00) = 0. Зарезервировано
(000) = 0. цветовое разрешение локальной таблицы цветов.
Далее в файле могут быть дополнительные секции (ниже я написал как их определить), но у нас их нет, и мы почти подошли к закодированным данным, и нас отделяют от них
Еще 2 байта
Для сжатия используется алгоритм Лемпеля — Зива — Велча. Ниже опишу его работу в двух словах.
[02] Минимальная длина кода LZW в битах (+1).
[07] Длина секции с данными. Вы спросите: «Как! Тут же всего один байт, то есть максимальная длина 255?». Верно, но таких секций неограниченное число. Если файл еще не закончился, то после окончания секции опять встретится байт с длиной следующей секции. Код может оказаться разрезанным этим байтом. Нужно запоминать его, чтобы вычислить расположение следующего.
LZW encoded image data.
Алгоритм LZW требует это проинициализированный словарь. У нас 4 цвета в таблице, поэтому добавляем 4 значения (они будут являтся индексами цветов):
0: <0>(черный)
1: <1>(белый)
2: <2>(красный)
3: <3>(в нашем примере не используется)
Для gif версии LZW в конец добавляются еще 2 управляющих кода (значения можно не добавлять, просто зарезервировать место):
4:
5:
[84] 10000100
[62] 01100010
[18] 00011000
[2A] 00101010
[10] 00010000
[5D] 01011101
[00] 00000000
Это коды, просто записанные подряд друг за другом. Но справа налево! Просто отсчитываем нужное количество бит справа и берем это число. А если байт закончился, то к уже частично полученному значению спереди дописываем число (с оставшимся количеством битов) из второго байта. На практике будет понятнее.
Мы узнали, что минимальная длина кода LZW в битах равна 2. Но нужно прибавлять еще 1, т.е. 3. Это означает, что текущий размер кода равен 3 и изначально именно по столько битов будем читать.
Словарь достиг предела для 4-х битных кодов. Текущий размер кода увеличиваем на 1 (длина кода увеличивается максимум до 12! При достижении словарем размера 4096 длина кода остается равной 12, и добавлять в словарь ничего не нужно. Обычно следом идет код clear)
(00101) 5:
Выпишем полученные индексы слева направо, сверху вниз (учитывая размер картинки 4×4)
0210
2101
1012
0120
Картинка уже угадывается! Уже понятно, что осталось посмотреть какой цвет скрывается за каждым индексом и вывести на экран. А у нас осталось еще 2 байта:
[00] еще один конец.
[3B] точно-точно конец 🙂
Extensions
Между секцией Image Descriptor и LZW encoded image data могут располагаться еще несколько секций. Там есть информация об анимации, комментарий, какие-то данные приложений, и т.п. Они определяются по маркеру [21][XX]. Описание см. в спецификации. Я описал только самый минимум, но обработка дополнительных секций не представляет проблем, к тому же большинство можно смело пропускать.
GIF изнутри
Вам когда-нибудь было интересно, как устроены gif-ки? В данной статье попробуем разобраться с внутренним строением GIF-формата и методом сжатия LZW.
Структура GIF
Файл в формате GIF состоит из фиксированной области в начале файла, за которой располагается переменное число блоков, и заканчивается файл завершителем изображения.
Основные характеристики формата GIF:
Пример разбора
Рассмотрим разбор дампа анимированного GIF-изображения размера 4х4 пикселя, состоящего из двух кадров. А вот и сами кадры, увеличенные в десятки раз.
Заголовок
В начале каждого файла GIF находится заголовок. Состоит он из текста «GIF87a» или «GIF89a», в зависимости от версии. В формате GIF87a переменная область содержит исключительно описания изображения, а в формате GIF89a она может включать еще и блоки расширений.
Логический дескриптор экрана
[04 00] [04 00] – ширина и высота виртуального экрана в пикселях
[А2] –
     (1) — флаг M использования глобальной таблицы цветов. Если 1, то в файле присутствует глобальная таблица цветов.
     (010) = 2 — флаг CR. Число бит разрешения цвета = CR + 1.
     (0) – флаг S (флаг сортировки). Если 1, то цвета в глобальной карте цветов отсортированы в порядке убывающей важности.
     (010) = 2 — флаг PIXEL. Размер общей таблицы цветов. Число записей в глобальной таблице цветов: 2^(N+1).
[00] – Индекс цвета фона.
[00] – Соотношение сторон. По умолчанию — 1:1.
Глобальная таблица цветов
[0A B2 5D] —
[C8 A6 2D] —
[F3 ED 63] —  
[BA 60 A5] —
[00 80 C8] —  
[F1 60 22] —  
[00 00 00] —  
[FF FF FF] —   
После глобальной таблицы цветов располагается переменная часть GIF. Файл содержит последовательность блоков, которые иденцифицируются 1-байтовым кодом в начале блока.
Коды блоков:
    0x21 – Расширение
    0x2С – Блок изображения
    0x3B – Завершение файла GIF
Блок расширения
Коды расширения:
    0x1 – расширение простого текста
    0xF9 – расширение управления графикой
    0xFE – расширение комментария
    0xFF – расширение программы
[FF] — код расширения. В нашем случае имеем расширение программы.
[0B] — размер последующего блока в байтах.
[4E 45 54 53 43 41 50 45] — (NETSCAPE) идентификатор приложения, которому принадлежит это расширение.
[32 2E 30] — (2.0) код приложения. С его помощью приложение проверяет, действительно ли это расширение принадлежит ему.
[03] — размер последующего блока в байтах.
[01] — фиксированное значение.
[00 00] — значение 0..65535. Беззнаковое целое в формате little-endian. Определяет, сколько раз должен повторяться цикл.
            Для 0 – бесконечно.
[00] — конец блока.
[F9] — код расширения (расширение управления графикой).
[04] — размер последующего блока в байтах.
[04] —
    (000) – зарезервировано. Рекомендуется заполнять нулями.
    (001) — метод обработки. Определяет, что делать после отображения.
                0 – к картинке не будет применяться никакой обработки
                1 – картинка останется без изменений
                2 – картинка затрется фоном
                3 – восстановится изображение под картинкой
                4-7 – не определены
    (0) – флаг ввода пользователя. Если 1, то для продолжения обработки изображения требуется реакция пользователя.
    (0) – флаг цвета прозрачности. Указывает, будет ли какой-нибудь цвет использоваться как прозрачный.
[32 00] – время задержки в анимации. = 50/100 секунды = 0,5 с
[00] – индекс цвета прозрачности.
[00] — конец блока.
Блок изображения
[00 00] [00 00] — номер строки и столбца. Определяет координаты верхнего левого угла логического экрана. (0, 0).
[04 00] [04 00] — ширина и высота изображения в пикселях.
[00] —
    (0) – флаг использования локальной таблицы цветов
    (0) – флаг чересстрочной развертки. Указывает, в каком порядке считываются пиксели изображения.
                0 – по строкам слева направо, сверху вниз
                1 – порядок:0-я. 8-я, 16-я…, 4-я, 12-я, 24-я…
    (0) – флаг сортировки локальной таблицы цветов. Если 1, то цвета в локальной карте цветов отсортированы в порядке убывающей важности.
    (00) – зарезервированы.
    (000) – флаг PIXEL. Размер локальной таблицы цветов, если есть.
[03] — минимальный размер кода в LZW.
[08] — размер последующего блока в байтах.
[08 0A D2 42 90 94 59 12] — блок данных, сжатых алгоритмом LZW. Представлены в виде последовательности кодов, имеющих длину [мин. размер кода] + 1
[00] — окончание потока данных.
Разбор алгоритма LZW
Кадр 1
Словарь инициализирован по количеству цветов и кодами
Решим обратную задачу. Возьмем исходные данные изображения и закодируем их с использованием алгоритма LZW. Под исходными данными понимаем последовательность индексов цветов из словаря, соответствующих каждому из пикселей. Пискели рассматриваем сверху вниз, слева направо.
Step | Action | Index Stream | New Code Table Row | Code Stream |
---|---|---|---|---|
1 | Init | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 | |
2 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 | |
3 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #10 – 0 0 | #8 #0 |
4 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 | |
5 | Found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 | |
6 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 | |
7 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #11 – 0 0 0 | #8 #0 #10 |
8 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 | |
9 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #12 – 0 2 | #8 #0 #10 #0 |
10 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 | |
11 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #13 – 2 2 | #8 #0 #10 #0 #2 |
12 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 | |
13 | Found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 | |
14 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 | |
15 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #14 – 2 2 2 | #8 #0 #10 #0 #2 #13 |
16 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 | |
17 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #15 – 2 4 | #8 #0 #10 #0 #2 #13 #2 |
18 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 | |
19 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #16 – 4 4 | #8 #0 #10 #0 #2 #13 #2 #4 |
20 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 | |
21 | Found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 | |
22 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 | |
23 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #17 – 4 4 4 | #8 #0 #10 #0 #2 #13 #2 #4 #16 |
24 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 | |
25 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #18 – 4 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 |
26 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 | |
27 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #19 – 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 #5 |
28 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 #5 | |
29 | Found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 #5 | |
30 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 #5 | |
31 | Not found | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #20 –5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 #5 #19 |
32 | Read | 0 0 0 0 2 2 2 2 4 4 4 4 5 5 5 5 | #8 #0 #10 #0 #2 #13 #2 #4 #16 #4 #5 #19 #5 #9 |
Теперь сравним результат кодирования со сжатыми данными, хранящимися в дампе. Формат GIF в данном блоке хранит многобайтовые целые числа с младшим байтом на первом месте (прямой порядок байтов).
[08 0A D2 42 90 94 59 12] — блок данных, сжатых алгоритмом LZW.
Аналогично поступаем со вторым кадром.
Кадр 2
Step | Action | Index Stream | New Code Table Row | Code Stream |
---|---|---|---|---|
1 | Init | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 | |
2 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 | |
3 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #10 – 3 6 | #8 #3 |
4 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 | |
5 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #11 – 6 1 | #8 #3 #6 |
6 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 | |
7 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #12 – 1 7 | #8 #3 #6 #1 |
8 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 | |
9 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #13 – 7 3 | #8 #3 #6 #1 #7 |
10 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 | |
11 | Found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1#7 | |
12 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1#7 | |
13 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #14 – 3 6 1 | #8 #3 #6 #1 #7 #10 |
14 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 | |
15 | Found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 | |
16 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 | |
17 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #15 – 1 7 3 | #8 #3 #6 #1 #7 #10 #12 |
18 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 | |
19 | Found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 | |
20 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 | |
21 | Found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 | |
22 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 | |
23 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #16 – 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 |
24 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 | |
25 | Found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 | |
26 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 | |
27 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #17 – 7 3 6 | #8 #3 #6 #1 #7 #10 #12 #14 #13 |
28 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 #13 | |
29 | Found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 #13 | |
30 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 #13 | |
31 | Not found | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #18 – 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 #13 #11 |
32 | Read | 3 6 1 7 3 6 1 7 3 6 1 7 3 6 1 7 | #8 #3 #6 #1 #7 #10 #12 #14 #13 #11 #7 #9 |
[38 16 A7 EC 6D 9D 04] — блок данных, сжатых алгоритмом LZW.
Блок завершения файла GIF
Заключение
На этом всё. Надеемся, эта статья была полезна для вас (ну или хотя бы интересна).
Стеганография в GIF
Введение
Приветствую.
Не так давно, когда учился в университете, была курсовая по дисциплине «Программные методы защиты информации». По заданию требовалось сделать программу, внедряющую сообщение в файлы формата GIF. Решил делать на Java.
В данной статье я опишу некоторые теоретические моменты, а также, как создавалась эта небольшая программа.
Теоретическая часть
Формат GIF
GIF (англ. Graphics Interchange Format — формат для обмена изображениями) — формат хранения графических изображений, способен хранить сжатые данные без потери качества в формате до 256 цветов. Данный формат был разработан в 1987 году (GIF87a) фирмой CompuServe для передачи растровых изображений по сетям. В 1989-м формат был модифицирован (GIF89a), были добавлены поддержка прозрачности и анимации.
Файлы формата GIF имеют блочную структуру. Данные блоки всегда имеют фиксированную длину (либо она зависит от некоторых флагов), так что ошибиться в том, где какой блок находится, практически невозможно. Структура простейшего неанимированного GIF-изображения формата GIF89a:
Методы шифрования
В программе будут использоваться в рамках этого метода два последних бита в байтах глобальной палитры. Это означает, что для 24-битного изображения, где цвет палитры представляет собой три байта для красного, синего, и зеленого цветов, после внедрения сообщения в него, каждая составляющая цвета изменится максимум на 3/255 градации. Такое изменение, во-первых, будет незаметно или труднозаметно для человеческого глаза, а во-вторых, не будет различимо на низкокачественных устройствах вывода информации.
Количество информации будет напрямую зависеть от размера палитры изображения. Поскольку максимальный размер палитры 256 цветов и, если записывать по два бита сообщения в составляющую каждого цвета, то максимальная длина сообщения (при максимальной палитре в изображении) составляет 192 байта. После внедрения сообщения в изображение, размер файла не изменяется.
Метод расширения палитры, работающий только для структуры GIF. Он будет наиболее эффективен в изображениях с палитрой небольших размеров. Суть его состоит в том, что он увеличивает размер палитры, тем самым дав дополнительное пространство для записи необходимых байт на месте байт цветов. Если учесть что минимальный размер палитры составляет 2 цвета (6 байт), то максимальный размер внедряемого сообщения может быть 256×3–6=762 байт. Недостаток — низкая криптозащищенность, прочесть внедренное сообщение можно при помощи любого текстового редактора, если сообщение не подвергалось дополнительному шифрованию.
Практическая часть
Проектирование программы
На основе структуры формата GIF можно составить общий алгоритм внедрения сообщения в палитру изображения:
Для определения присутствия сообщения в изображении необходимо в начало сообщения добавлять некую последовательность бит, которую дешифратор считывает в первую очередь и проверяет на корректность. Если она не совпадает, то считается, что в изображении нет сокрытого сообщения. Далее надо указывать длину сообщения. Затем сам текст сообщения.
Диаграмма классов всего приложения:
Реализация программы
Поля firstLSBit и secondLSBit содержат номера битов каждого байта изображения, в которые должно заноситься и откуда считываться сообщение. Поле checkSequence хранит контрольную последовательность бит для обеспечения распознавания встроенного сообщения. Статический метод getEncryptingFileParameters возвращает параметры указанного файла и характеристики потенциального сообщения.
Алгоритм метода encrypt класса GIFEncryptorByLSBMethod :
Алгоритм и исходный код метода decrypt класса GIFEncryptorByLSBMethod :
Реализация класса GIFEncryptorByPaletteExtensionMethod будет аналогичной, только отличается метод сохранения/считывания информации.
Работа программы
Метод LBS
Допустим есть такое изображение:
В данном изображении палитра состоит из 256 цветов (так сохраняет Paint). Первые четыре цвета: белый, черный, красный, зеленый. Остальные цвета — черные. Последовательность бит глобальной палитры будет следующая:
11111111 11111111 11111111 00000000 00000000 00000000 11111111 00000000 00000000 00000000 11111111 00000000…
После внедрения сообщения подчеркнутые биты будут заменены битами из сообщения. Полученное изображение почти не отличается от оригинала.
Оригинал | Изображение с внедренным сообщением |
---|---|
Метод расширения палитры
Открыв изображение, в которое помещено сообщение по данному методу, можно обнаружиться такую картину:
Понятное дело, что для полноценной шпионской деятельности такой метод не пойдет, и требует, может, дополнительной шифровки сообщения.
Шифрование/дешифрование в анимированных изображениях работает, как и в обычных статических изображениях, при этом анимация не нарушается.