Расчет SHA-1 хеша средствами 1С. Битовые операции в 1С или урок двоичной математики

Опубликовал Антон Ширяев (Антон Ширяев) в раздел Программирование - Практика программирования

Расчет хеша SHA-1 без использования каких-либо внешних компонет - возможно ли это в 1Cv8? Оказывается вполне возможно!

Я думаю если провести опрос, то многие программисты ответят, что в 1С нет штатных средств для работы с отдельными битами, нет операторов XOR, OR, AND над числами.

Расчет хеша SHA-1 без использования каких-либо внешних компонет - возможно ли это в 1Cv8? Оказывается вполне возможно!

В прикрепленном файле содержится готовая обработка, которая возвращает SHA-1 хеш от указанной строки.

Для понимания как это реализовано на 1с вспомним двоичную систему счисления. В принципе, если представить целое десятичное число в двоичной системе счисления, то как раз получим последовательность бит. Например число 128 в двоичной счисления будет иметь вид 10000000 для 8-битного представления или 00000000000000000000000010000000 для 32-битного, а 129 соответственно 10000001 или 00000000000000000000000010000001.

Т.е. число в десятичной системе = ΣBi·2i, где Bi - бит из двоичного числа, а отсчет битов начинается с нуля. Т.е. для числа 10000001 получаем 128·1+64·0+32·0+16·0+8·0+4·0+2·0+1·1=129

 Для обратного перевода можно пользоваться несколькими способами:

1) Для получения битов начиная со старшего, заканчивая младшим:

Исходное число, например 129, делим на 2^7, если получается больше единицы, то первый бит - 1, иначе 0. Далее Из исходного числа 129 вычитаем 2^7*бит и получаем 129-128*1=1. Далее получаем следующий бит - 1 делим на 2^6, получаем число меньшее единицы, т.е. текущий бит будет равен нулю. Теперь повторем вычитание текущего множителя 2^6 - 1-2^6*0=1. Таким образо дроходим до множителя 2^0 - 1/2^0=1 - т.е. последний бит равен 1.

Число = 129;
Битность = 8;
Биты = "";
Для
й = 1 По Битность Цикл
   
Множитель = pow(2, Битность - й);
   
Бит = Цел(Число / Множитель);
   
Число = Число - Множитель * Бит;
   
Биты = Биты + Бит;
КонецЦикла;
Сообщить(Биты);

2) Для получения битов начиная с младшего до страшего:

Исходное число, например 129, делим оператором % на 2, получаем остаток от деления 1 - это крайний левый бит. Теперь делим нацело 129/2, получаем 64. Далее 64 опять делим оператором % на 2 - получаем следующий бит - 0. Продолжаем так вычислять пока не получим нужные 8 бит.

Число = 129;
Битность = 8;
Биты = "";
Для
й = 1 По Битность Цикл
   
Бит = Число % 2;
   
Число = Цел(Число / 2);
   
Биты = Строка(Бит) + Биты;
КонецЦикла;
Сообщить(Биты);

3) В вышеописаных способах мы изменяем входное число, например 129, но можно вычислять биты не изменяя его. Например старший бит это ЦЕЛ(129/2^7)%2=1, следующий ЦЕЛ(129/2^6)%2=0 и так далее до младшего бита ЦЕЛ(129/2^0)%2=1

Число = 129;
Битность = 32;
Биты = "";
Для
й = 1 По Битность Цикл
   
Бит = Цел(Число / pow(2, Битность - й)) % 2;
   
Биты = Биты + Строка(Бит);
КонецЦикла;
Сообщить(Биты);

Привожу код готовых функций XOR, LR, RR, AND, OR при помощи которых можно вычислить практически любой распространенный хэш

Функция _XOR(Знач A, Знач B, L = 8)
   
R = 0;
    Для
I = 1 по L Цикл
       
M = POW(2, L - I);
       
R = R + M * ?((A < M) = (B < M), 0, 1);
       
A = ?(A < M, A, A - M);
       
B = ?(B < M, B, B - M);
    КонецЦикла;
    Возврат
R;
КонецФункции
 
Функция _LR(Знач A, S, L = 8)
    Возврат
Цел(A / POW(2, L - S)) + POW(2, S) * (A % POW(2, L - S));
КонецФункции

Функция
_RR(Знач A, S, L = 8)
    Возврат
Цел(A / POW(2, S)) + POW(2, S) * (A % POW(2, S));
КонецФункции

Функция
_AND(Знач A, Знач B, L = 8)
   
R = 0;
    Для
I = 1 по L Цикл
       
M = POW(2, L - I);
       
R = R + M * ?((A >= M) AND (B >= M), 1, 0);
       
A = ?(A < M, A, A - M);
       
B = ?(B < M, B, B - M);
    КонецЦикла;
    Возврат
R;
КонецФункции

Функция
_OR(Знач A, Знач B, L = 8)
   
R = 0;
    Для
I = 1 по L Цикл
       
M = POW(2, L - I);
       
R = R + M * ?((A >= M) OR(B >= M), 1, 0);
       
A = ?(A < M, A, A - M);
       
B = ?(B < M, B, B - M);
    КонецЦикла;
    Возврат
R;
КонецФункции

Так же в обработку встроен простой замер производительности, который показывает, что циклы в одну строку показывают заметный прирост только при включенном сеансе отладки :)

Скачать файлы

Наименование Файл Версия Размер
Калькулятор SHA-1 хеша от строки
.epf 10,11Kb
13.03.13
105
.epf 10,11Kb 105 Скачать

См. также

Добавить вознаграждение
Комментарии
1. Алекс Ю (AlexO) 113 13.03.13 17:34 Сейчас в теме
Антон, вы поразрядно сравниваете числа. По позиции, мантиссе числа.
А не биты.
2. Антон Ширяев (Антон Ширяев) 393 13.03.13 17:40 Сейчас в теме
(1) AlexO,
Чем по сути отличается поразрядное сравнение числа от сравнения битов из которых состоит это число?
3. Алекс Ю (AlexO) 113 13.03.13 17:44 Сейчас в теме
(2) Антон Ширяев,
Вы сравниваете мантиссу чисел, по позиции-разрядности.
А такое работает только там, где байтам поставлено в соответствии какое-либо число (любой системы счисления) - например, с кодировками такое прокатывает, где только числа в качестве кода. А вот реальный двоичный код, где нужно настоящее ПОБИТОВОЕ сравнение - данным методом уже никакого результат не получим.
4. Антон Ширяев (Антон Ширяев) 393 13.03.13 17:57 Сейчас в теме
(3) AlexO, Проблема в том, что нет возможности в 1С8 прочитать двоичный файл побайтово. Можно прочитать только его весь в ДвоичныеДанные. Дальше эти ДвоичныеДанные можно закодировать в BASE64 и уже постепенно раскодируя из BASE64 в числа делать с ними что угодно. Писать обратно опять через то же место :)
5. andrewks 1180 13.03.13 18:00 Сейчас в теме
(4) Антон Ширяев, а почему бы не попробовать читать как unicode? (вот только вопрос, что считается, когда в конце останется один байт, а не два - надо проверять)
6. andrewks 1180 13.03.13 18:03 Сейчас в теме
а если абстрагироваться от кросс-платформенности, то можно привлечь SAPI.spFileStream, например
7. Антон Ширяев (Антон Ширяев) 393 13.03.13 18:15 Сейчас в теме
(5) andrewks,
В обработке как раз идет разбор Unicode-строки на байты и последующее хэширование строки. Кириллица в Unicode занимает от двух байт для основных букв и более (например буква ё).
Если читать бинарные файлы как Unicode думаю ничего хорошего не выйдет, т.к. 100% попадется символ не используемый в Unicode.
Обработку писал давно - больше года назад, нашел время опубликовать только сейчас. В статье не указал как разобрать Unicode-строку на байты, возможно дополню позже.
8. andrewks 1180 13.03.13 20:48 Сейчас в теме
(7) Антон Ширяев,
Кириллица в Unicode занимает от двух байт для основных букв и более (например буква ё)

Вы путаете с UTF-8. Unicode-символ в виде UTF-16LE занимает стабильно 2 байта (хоть английские, хоть русские буквы)
9. andrewks 1180 13.03.13 20:53 Сейчас в теме
т.к. 100% попадется символ не используемый в Unicode.

вот этого не понял вообще. двухбайтный юникод идёт от 0000 до FFFF. что значит "символ не используемый в Unicode"?
10. Сергей Ожерельев (Поручик) 3471 14.03.13 01:04 Сейчас в теме
Я тоже вброшу. символ не используемый в Unicode. Символ EOF или имеется в виду, что размер файла не будет кратен 2?
11. Александр (aet) 37 14.03.13 05:00 Сейчас в теме
Мне тоже нравятся всякие математические штуки на 1С ненужные в реальных системах учета, поэтому плюс.
12. Юрий Осипов (yuraos) 843 14.03.13 06:28 Сейчас в теме
(11)
Математические штучки, олимпиадные задачки.
Это все хорошо с познавательной точки зрения.
---
Только вот беда...
Для практического применения реализация алгоритмов в коде 1С
не самый лутший вариант с точки зрения производительности.
---
ВК эти же алгоритмы выполняют более эффективнее.
Можно сравнить хотя бы на примере
задачи выгрузки результата запроса ADO
Можно сделать все в коде 1С,
но средствами ВК получается на порядок эффективней
13. Антон Ширяев (Антон Ширяев) 393 14.03.13 09:08 Сейчас в теме
(8) andrewks,
Вы путаете с UTF-8. Unicode-символ в виде UTF-16LE занимает стабильно 2 байта (хоть английские, хоть русские буквы)


Для начала заглянем в Википедию.
UTF-8 и UTF-16LE это способы представления Юникода.
Посмотрим пример где используются хеши SHA-1 в 1C - на память приходит пока только хеши паролей пользователей.
Кодируется как раз представление пароля в UTF-8.

Сейчас посмотрел - в списке доступных кодировок в 1С есть UTF-16. Попробую поиграться и отпишусь о результатах.

Действительно все что я писал выше я подразумевал, что Юникод закодирован UTF-8.
14. Алексей Бочков (Aleksey.Bochkov) 2627 14.03.13 09:48 Сейчас в теме
(0) а в 8.3 для вычисления хэша уже сделали полноценные методы встроенного языка
15. Алекс Ю (AlexO) 113 14.03.13 10:00 Сейчас в теме
(14) Aleksey.Bochkov,
а в 8.3

а в 9.0 обещают, что кодить не надо будет совсем :)
16. Антон Ширяев (Антон Ширяев) 393 14.03.13 10:11 Сейчас в теме
Итак, попробовал записать в файл все символы средствами 1с

Текст = Новый ЗаписьТекста("c:\t2.txt", КодировкаТекста.UTF16);
Для й = 0 По 65535 Цикл
Текст.Записать(Символ(й));
КонецЦикла;
Текст.Закрыть();

Получил следующие проблемы
1) В начало файла пишется лишний символ - заголовок "FF FE"
2) Вместо символа "0A 00" пишется 2 символа "0A 00 OD 00"
3) Вместо символов "00 D8" - "FF DF", кроме символов "FF DB" и "00 DC" пишется символ "FD FF"

Т.е. через ЗаписьТекста() бинарные файлы писать не получится. Поэкспериментирую еще с чтением.
17. Алекс Ю (AlexO) 113 14.03.13 10:18 Сейчас в теме
(16) Антон Ширяев,
1) В начало файла пишется лишний символ - заголовок "FF FE"

это "стандарт" у 1С (один из многих "стандартов 1С", за соблюдение которых тут ратуют тру-1сники): в любой, даже пустой текстовик - писать перевод каретки в начале. За кой - тайна за семью печатями.
18. Антон Ширяев (Антон Ширяев) 393 14.03.13 10:51 Сейчас в теме
(17) AlexO,
Снова смотрим Википедию :)
1С тут ни при чем, "FF FE" - это заголовок обозначающий что файл закодирован UTF-16LE. Для UTF-8 пишется "EF BB BF"
19. Алекс Ю (AlexO) 113 14.03.13 11:53 Сейчас в теме
(18) Антон Ширяев,
Да, похоже, насчет первых символов - это от кодировок..
а на кой тогда? все равно путаница с кодировками...
20. andrewks 1180 14.03.13 14:25 Сейчас в теме
(16) Антон Ширяев, да, с BOM в 1С засада - нельзя управлять записью маркера, она его пишет всегда. вот только речь-то была не про запись, а про чтение :-)
однако, видимо, траблы с перекодировкой некоторых служебных символов всё равно будут
21. andrewks 1180 14.03.13 14:31 Сейчас в теме
возможно, выгоднее тогда будет заюзать ЧтениеТекста с кодировкой ANSI и посимвольным чтением Прочитать(1)
однако ж здесь тоже таится засада - в 8-ке 1с перекодирует строки в 2-х байтовый Unicode
22. andrewks 1180 14.03.13 14:33 Сейчас в теме
видимо, извращаться через разбор BASE64 единственный гарантированный способ, если религией запрещены ВК
23. Алекс Ю (AlexO) 113 14.03.13 15:02 Сейчас в теме
Самое интересное - что сама 1С юзает вовсю двоичную запись в платформе, но программистам - ни-ни.
(22) andrewks,
видимо, извращаться

Почему извращаться?! Обычная сериализация нетекствоого содержимого.
через разбор BASE64

Так кто-бы еще сохранил в BASE64, чтобы потом разбирать в 1С....
24. Алекс Ю (AlexO) 113 14.03.13 15:09 Сейчас в теме
(18) Антон Ширяев,
так ведь эти символы вообще практического никакого влияния и значения не оказывают..
только под ногами "мешаются".
Видимо, 1С - как всегда! - запользовало при разработке платформы некую сторонне-бесплатную (когда 1С что-либо лицензировало у третьих фирм? ну, собственно, и качество отсюда, сама-то ни в дугу, ни в красную армию разработать что-либо...) примочку, которая "на автомате" пихает "лишние" символы в файл.
25. andrewks 1180 14.03.13 16:37 Сейчас в теме
(24) AlexO, не сказать, чтобы они лишние, просто неплохо было бы предоставить возможность управлять выводом маркеров, чего сделано ими не было
26. andrewks 1180 14.03.13 16:39 Сейчас в теме
а уж за то, что объект ДвоичныеДанные недоделан, и не позволяет практически ничего с ними делать - я готов был 1соцев укусить, когда писал свою обработку по шифрованию файлов отчётности для ФСРАР
27. Юрий Осипов (yuraos) 843 14.03.13 17:26 Сейчас в теме
(15) AlexO,
ага, вся платформа будет "управляемой", конфигуратор - тоже.
в нем останутся одни "ТЫЧИ".
НАЖМИ НА "ТЫЧУ" - И ПОЛУЧИШЬ РЕЗУЛЬТАТ!!!
;)))
28. Антон Ширяев (Антон Ширяев) 393 18.03.13 10:26 Сейчас в теме
Попробовал прочитать заранее подготовленный файл со всеми двухбайтовыми символами

Текст = Новый ЧтениеТекста("c:\1.bin", КодировкаТекста.UTF16);
Для й = 0 По 65535 Цикл
С = Текст.Прочитать(1);
Если Кодсимвола(С) <> й Тогда
Сообщить("Кодсимвола = " + Кодсимвола(С) + " Й = " + й);
КонецЕсли;
КонецЦикла;
Текст.Закрыть();

Вместо символов "00 D8" - "FF DF", кроме символов "FF DB" и "00 DC" читается символ "FD FF".

Т.е. никак не получается прочитать бинарный файл через ЧтениеТекста...
29. Алекс Ю (AlexO) 113 18.03.13 10:43 Сейчас в теме
(28) Антон Ширяев,
Т.е. никак не получается прочитать бинарный файл через ЧтениеТекста

Так это ЧТЕНИЕ ТЕКСТА :)
А не бинарника. 1С не осилила реализовать "ПрочитатьБинарныйФайлПобайтово".
Да и текст читает эта ЧтениеТекста - сплошной мрак и тормоза. Лучше и быстрее на порядок для чтения текста - использовать FileSystemObject.
30. Сергей Маслов (LexSeIch) 180 20.03.13 05:35 Сейчас в теме
Мир этому дому. Статья заинтересовала - взял на заметку. Автору спасибо.
31. Dimon Phoenix (NGPhoenix) 7 03.06.14 22:08 Сейчас в теме
Проверил обработку на предмет совпадения пароля пользователя и заявленного хеша. Совпало!!! Значит обработка точно кодирует. Хочу на основе данной обработки попробывать обратный подход (брутфорс). Посмотрим, что получиться.
32. Dimon Phoenix (NGPhoenix) 7 04.06.14 07:37 Сейчас в теме
Брутфорс SHA1 утомительное дело. Слишком долго. Даже трехзначный пароль за 5 часов полностью не перебрался. Но к работе обработки это дела не имеет.
33. андрей ульянников (andrushok_7@mail.ru) 20.01.15 15:55 Сейчас в теме
Обработка неверно считает хэш по алгоритму SHA-1, проверил на многочисленных онлайн-генераторах
34. Игорь Фелькер (Brawler) 276 04.02.16 10:56 Сейчас в теме
Скоро, скоро придет мир в этот дом, однако не на 100%
http://v8.1c.ru/o7/201602bin/index.htm
35. Максим *** (premier) 130 17.02.16 08:35 Сейчас в теме
(7) Антон Ширяев, Ildarovich вот в этой публикации "предлагает ограничиться только символами, имеющимися в таблице windows-1251". И даже приводит функцию преобразования. Вполне рабочий вариант.
А идея реализации бинарных операций очень даже неплохая. Только про инверсию забыли, незаслуженно, имхо.
36. Максим *** (premier) 130 02.03.16 14:31 Сейчас в теме
(0) Раз автор публикации не желает обнародовать функцию инверсии числа, попытаюсь сделать это сам:
Функция _INV(Знач A, L = 32) Экспорт
    Возврат POW(2, L) - 1 - A;
КонецФункции 
...Показать Скрыть
37. Сергей (ildarovich) 4819 22.06.16 12:15 Сейчас в теме
Вот в этой статье: Простая и быстрая эмуляция операций с битовыми строками приведен другой способ реализации операций с битовыми строками в языке 1С. Он не требует использования циклов и поэтому гораздо быстрее. По оценкам, сделанным в той статье, если длина битовой строки равна 300 символов, то выигрыш достигает 15-ти раз.
Не знаю, подойдет ли метод из упомянутой статьи для решения этой задачи.