std.digest
В этом модуле описаны API для хэширования, используемые в Phobos. Все хэширования следуют этим API. Кроме того, этот модуль содержит полезные вспомогательные методы, которые могут быть использованы с каждым типом хэширования.
| Категория | Функции |
|---|---|
| API шаблонов | isDigest DigestType hasPeek hasBlockSize ExampleDigest digest hexDigest makeDigest |
| API ООП | Digest |
| Вспомогательные функции | toHexString secureEqual |
| Вспомогательные функции реализации | digestLength WrapperDigest |
- API
- Существуют два API для хэширования: API шаблонов и API ООП. API шаблонов использует структуры и шаблоны-помощники, такие как
isDigest. API ООП реализует хэширования как классы, наследующие интерфейсDigest. Все хэширования имеют имена, при которых структура API шаблонов называется "x", а класс API ООП называется "xDigest". Например,MD5<-->MD5Digest,CRC32<-->CRC32Digest, и т. д.
Digest все равно должны быть созданы с помощью new , который выделяет их с помощью сборщика мусора. API ООП полезен для изменения функции хэширования и/или бэкенда хэширования во время выполнения. Преимущество здесь состоит в том, что переключение, например, с Phobos MD5Digest на OpenSSLMD5Digest реализацию, совместимо с ABI. Если требуется только один определенный тип хэширования и бэкенд, API шаблонов, как правило, хорошо подходит. В этом простом случае API шаблонов можно использовать даже без шаблонов: просто используйте структуры "x" напрямую. - Лицензия:
- Boost License 1.0.
- Авторы:
- Johannes Pfau
- Исходный код
- std/digest/package.d
- CTFE
- Хэширование не работает в CTFE
- TODO
- Хэширование отдельных битов (в отличие от байтов) не реализовано. Это будет сделано как дополнительный помощник шаблона-ограничения (hasBitDigesting!T) и дополнительный интерфейс (BitDigest)
- Примеры:
-
import std.digest.crc; //Simple example char[8] hexHash = hexDigest!CRC32("The quick brown fox jumps over the lazy dog"); writeln(hexHash); // "39A34F41" //Simple example, using the API manually CRC32 context = makeDigest!CRC32(); context.put(cast(ubyte[])"The quick brown fox jumps over the lazy dog"); ubyte[4] hash = context.finish(); writeln(toHexString(hash)); // "39A34F41"
- Примеры:
-
//Generating the hashes of a file, idiomatic D way import std.digest.crc, std.digest.md, std.digest.sha; import std.stdio; // Digests a file and prints the result. void digestFile(Hash)(string filename) if (isDigest!Hash) { auto file = File(filename); auto result = digest!Hash(file.byChunk(4096 * 1024)); writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); } void main(string[] args) { foreach (name; args[1 .. $]) { digestFile!MD5(name); digestFile!SHA1(name); digestFile!CRC32(name); } }
- Примеры:
-
//Generating the hashes of a file using the template API import std.digest.crc, std.digest.md, std.digest.sha; import std.stdio; // Digests a file and prints the result. void digestFile(Hash)(ref Hash hash, string filename) if (isDigest!Hash) { File file = File(filename); //As digests imlement OutputRange, we could use std.algorithm.copy //Let's do it manually for now foreach (buffer; file.byChunk(4096 * 1024)) hash.put(buffer); auto result = hash.finish(); writefln("%s (%s) = %s", Hash.stringof, filename, toHexString(result)); } void uMain(string[] args) { MD5 md5; SHA1 sha1; CRC32 crc32; md5.start(); sha1.start(); crc32.start(); foreach (arg; args[1 .. $]) { digestFile(md5, arg); digestFile(sha1, arg); digestFile(crc32, arg); } }
- Примеры:
-
import std.digest.crc, std.digest.md, std.digest.sha; import std.stdio; // Digests a file and prints the result. void digestFile(Digest hash, string filename) { File file = File(filename); //As digests implement OutputRange, we could use std.algorithm.copy //Let's do it manually for now foreach (buffer; file.byChunk(4096 * 1024)) hash.put(buffer); ubyte[] result = hash.finish(); writefln("%s (%s) = %s", typeid(hash).toString(), filename, toHexString(result)); } void umain(string[] args) { auto md5 = new MD5Digest(); auto sha1 = new SHA1Digest(); auto crc32 = new CRC32Digest(); foreach (arg; args[1 .. $]) { digestFile(md5, arg); digestFile(sha1, arg); digestFile(crc32, arg); } }
- struct ExampleDigest;
-
This documents the general structure of a Digest in the template API. All digest implementations should implement the following members and therefore pass the
isDigesttest.- Примечание
- Digest должен быть структурой (типом-значением), чтобы пройти проверку
isDigest. - Digest, прошедший проверку
isDigest, всегда являетсяOutputRange
- Примеры:
-
//Using the OutputRange feature import std.algorithm.mutation : copy; import std.digest.md; import std.range : repeat; auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); auto ctx = makeDigest!MD5(); copy(oneMillionRange, &ctx); //Note: You must pass a pointer to copy! writeln(ctx.finish().toHexString()); // "7707D6AE4E027C70EEA2A935C2296F21"
- @trusted void put(scope const(ubyte)[] data...);
-
Используйте эту функцию для передачи данных в digest. Также реализует интерфейс
std.range.primitives.isOutputRangeдляubyteиconst(ubyte)[]. Следующие использованияputдолжны работать для любого типа, прошедшего проверкуisDigest:- Пример
ExampleDigest dig; dig.put(cast(ubyte) 0); //single ubyte dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic ubyte[10] buf; dig.put(buf); //buffer
- @trusted void start();
-
Эта функция используется для (пере)инициализации digest. Она должна вызываться перед использованием digest, а также работает как функция «сброса» (reset), если digest уже обработало данные.
- @trusted ubyte[16] finish();
-
Функция finish возвращает итоговую сумму хеша и сбрасывает digest.
- Примечание
- Фактический тип, возвращаемый finish, зависит от реализации digest.
ubyte[16]используется просто в качестве примера. Гарантируется, что тип является статическим массивом ubyte.
- Используйте
DigestTypeдля получения фактического типа возврата. - Используйте
digestLengthдля получения длины массива ubyte.
- enum bool isDigest(T);
-
Используйте эту функцию для проверки, является ли тип типом digest. Обратитесь к
ExampleDigest, чтобы увидеть, что должен предоставлять тип для прохождения этой проверки.- Примечание
- Это очень полезно в качестве шаблона ограничения (см. примеры)
- Ошибки:
- Пока не проверяется, что put принимает параметры scope.
- Нужно проверить, что finish() возвращает массив ubyte[num].
- Примеры:
-
import std.digest.crc; static assert(isDigest!CRC32);
- Примеры:
-
import std.digest.crc; void myFunction(T)() if (isDigest!T) { T dig; dig.start(); auto result = dig.finish(); } myFunction!CRC32();
- template DigestType(T)
-
Используйте этот шаблон для получения типа, возвращаемого методом
finishdigest.- Примеры:
-
import std.digest.crc; assert(is(DigestType!(CRC32) == ubyte[4]));
- Примеры:
-
import std.digest.crc; CRC32 dig; dig.start(); DigestType!CRC32 result = dig.finish();
- enum bool hasPeek(T);
-
Используется для проверки, поддерживает ли digest метод
peek. Peek имеет те же самые сигнатуры функций, что и finish, но не сбрасывает внутреннее состояние digest.- Примечание
- Это очень полезно в качестве шаблона ограничения (см. примеры)
- Это также проверяет, проходит ли T проверку
isDigest
- Примеры:
-
import std.digest.crc, std.digest.md; assert(!hasPeek!(MD5)); assert(hasPeek!CRC32);
- Примеры:
-
import std.digest.crc; void myFunction(T)() if (hasPeek!T) { T dig; dig.start(); auto result = dig.peek(); } myFunction!CRC32();
- template hasBlockSize(T) if (isDigest!T)
-
Проверяет, имеет ли digest член
blockSize, который содержит внутренний размер блока digest в битах. В основном используетсяstd.digest.hmac.HMAC.- Примеры:
-
import std.digest.hmac, std.digest.md; static assert(hasBlockSize!MD5 && MD5.blockSize == 512); static assert(hasBlockSize!(HMAC!MD5) && HMAC!MD5.blockSize == 512);
- DigestType!Hash digest(Hash, Range)(auto ref Range range)
Constraints: if (!isArray!Range && isDigestibleRange!Range); -
Это вспомогательная функция для вычисления хеша с помощью шаблона API. Любой digest, прошедший проверку
isDigest, может быть использован с этой функцией.- Параметры:
Range rangeобъект InputRangeсElementTypeubyte,ubyte[]илиubyte[num]
- Примеры:
-
import std.digest.md; import std.range : repeat; auto testRange = repeat!ubyte(cast(ubyte)'a', 100); auto md5 = digest!MD5(testRange);
- DigestType!Hash digest(Hash, T...)(scope const T data)
Constraints: if (allSatisfy!(isArray, typeof(data))); -
Этот перегруз функции digest обрабатывает массивы.
- Параметры:
T dataодин или более массивов любого типа
- Примеры:
-
import std.digest.crc, std.digest.md, std.digest.sha; auto md5 = digest!MD5( "The quick brown fox jumps over the lazy dog"); auto sha1 = digest!SHA1( "The quick brown fox jumps over the lazy dog"); auto crc32 = digest!CRC32("The quick brown fox jumps over the lazy dog"); writeln(toHexString(crc32)); // "39A34F41"
- Примеры:
-
import std.digest.crc; auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); writeln(toHexString(crc32)); // "39A34F41"
- char[digestLength!Hash * 2] hexDigest(Hash, Order order = Order.increasing, Range)(ref Range range)
Constraints: if (!isArray!Range && isDigestibleRange!Range); -
Это вспомогательная функция, аналогичная
digest, но она возвращает строковое представление хеша. Любой digest, прошедший проверкуisDigest, может быть использован с этой функцией.- Параметры:
order порядок обработки байтов (см. toHexString)Range rangeобъект InputRangeсElementTypeubyte,ubyte[]илиubyte[num]
- Примеры:
-
import std.digest.md; import std.range : repeat; auto testRange = repeat!ubyte(cast(ubyte)'a', 100); writeln(hexDigest!MD5(testRange)); // "36A92CC94A9E0FA21F625F8BFB007ADF"
- char[digestLength!Hash * 2] hexDigest(Hash, Order order = Order.increasing, T...)(scope const T data)
Constraints: if (allSatisfy!(isArray, typeof(data))); -
Этот перегруз функции hexDigest обрабатывает массивы.
- Параметры:
order порядок обработки байтов (см. toHexString)T dataодин или более массивов любого типа
- Примеры:
-
import std.digest.crc; // "414FA339" writeln(hexDigest!(CRC32, Order.decreasing)("The quick brown fox jumps over the lazy dog"));
- Примеры:
-
import std.digest.crc; // "414FA339" writeln(hexDigest!(CRC32, Order.decreasing)("The quick ", "brown ", "fox jumps over the lazy dog"));
- Hash makeDigest(Hash)();
-
Это вспомогательная функция, которая возвращает инициализированный digest, поэтому нет необходимости вызывать start вручную.
- Примеры:
-
import std.digest.md; auto md5 = makeDigest!MD5(); md5.put(0); writeln(toHexString(md5.finish())); // "93B885ADFE0DA089CDF634904FD59F71"
- interface Digest;
-
Это описывает API с объектно-ориентированным подходом. Чтобы понять, когда использовать шаблонный API, а когда API с объектно-ориентированным подходом, обратитесь к документации модуля в верхней части этой страницы.
Интерфейс Digest — это базовый интерфейс, реализованный всеми digest.
- Примечание
- Реализация Digest всегда является
OutputRange
- Примеры:
-
//Using the OutputRange feature import std.algorithm.mutation : copy; import std.digest.md; import std.range : repeat; auto oneMillionRange = repeat!ubyte(cast(ubyte)'a', 1000000); auto ctx = new MD5Digest(); copy(oneMillionRange, ctx); writeln(ctx.finish().toHexString()); // "7707D6AE4E027C70EEA2A935C2296F21"
- Примеры:
-
import std.digest.crc, std.digest.md, std.digest.sha; ubyte[] md5 = (new MD5Digest()).digest("The quick brown fox jumps over the lazy dog"); ubyte[] sha1 = (new SHA1Digest()).digest("The quick brown fox jumps over the lazy dog"); ubyte[] crc32 = (new CRC32Digest()).digest("The quick brown fox jumps over the lazy dog"); writeln(crcHexString(crc32)); // "414FA339"
- Примеры:
-
import std.digest.crc; ubyte[] crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); writeln(crcHexString(crc32)); // "414FA339"
- Примеры:
-
void test(Digest dig) { dig.put(cast(ubyte) 0); //single ubyte dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic ubyte[10] buf; dig.put(buf); //buffer }
- abstract nothrow @trusted void put(scope const(ubyte)[] data...);
-
Используйте эту функцию для передачи данных в digest. Также реализует интерфейс
std.range.primitives.isOutputRangeдляubyteиconst(ubyte)[].- Пример
void test(Digest dig) { dig.put(cast(ubyte) 0); //single ubyte dig.put(cast(ubyte) 0, cast(ubyte) 0); //variadic ubyte[10] buf; dig.put(buf); //buffer } - abstract nothrow @trusted void reset();
-
Сбрасывает внутреннее состояние digest.
- Примечание
-
finishвызывает это внутри, поэтому нет необходимости вызыватьresetвручную после вызоваfinish.
- abstract const nothrow @property @trusted size_t length();
-
Это длина в байтах значения хеша, возвращаемого
finish. Это также требуемый размер буфера, переданного вfinish. - abstract nothrow @trusted ubyte[] finish();
abstract nothrow ubyte[] finish(ubyte[] buf); -
Функция finish возвращает значение хеша. Она принимает необязательный буфер для копирования данных. Если буфер передан, он должен быть не меньше
lengthбайтов. - final nothrow @trusted ubyte[] digest(scope const(void[])[] data...);
-
Это вспомогательная функция для вычисления хеша значения с помощью API с объектно-ориентированным подходом.
- enum Order: bool;
-
См.
toHexString- Примеры:
-
import std.digest.crc : CRC32; auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); writeln(crc32.toHexString!(Order.decreasing)); // "414FA339" writeln(crc32.toHexString!(LetterCase.lower, Order.decreasing)); // "414fa339"
- increasing
- decreasing
- char[num * 2] toHexString(Order order = Order.increasing, size_t num, LetterCase letterCase = LetterCase.upper)(const ubyte[num] digest);
char[num * 2] toHexString(LetterCase letterCase, Order order = Order.increasing, size_t num)(in ubyte[num] digest);
string toHexString(Order order = Order.increasing, LetterCase letterCase = LetterCase.upper)(in ubyte[] digest);
string toHexString(LetterCase letterCase, Order order = Order.increasing)(in ubyte[] digest);
-
Используется для преобразования значения хэша (статического или динамического массива ubyte) в строку. Может использоваться с OOP и с API шаблонов.
Дополнительный параметр order может быть использован для указания порядка входных данных. По умолчанию данные обрабатываются в порядке возрастания, начиная с индекса 0. Для обработки в обратном порядке передайте Order.decreasing в качестве параметра.
Дополнительный параметр letterCase может быть использован для указания регистра выходных данных. По умолчанию вывод в верхнем регистре. Для изменения на нижний регистр передайте LetterCase.lower в качестве параметра.- Примечание
- Функции с возвращаемым значением типа строка выделяют свои возвращаемые значения с помощью GC. Версии, возвращающие статические массивы, используют передачу значения по значению для возвращаемого значения, фактически избегая динамического выделения.
- Примеры:
-
import std.digest.crc; //Test with template API: auto crc32 = digest!CRC32("The quick ", "brown ", "fox jumps over the lazy dog"); //Lower case variant: writeln(toHexString!(LetterCase.lower)(crc32)); // "39a34f41" //Usually CRCs are printed in this order, though: writeln(toHexString!(Order.decreasing)(crc32)); // "414FA339" writeln(toHexString!(LetterCase.lower, Order.decreasing)(crc32)); // "414fa339"
- Примеры:
-
import std.digest.crc; // With OOP API auto crc32 = (new CRC32Digest()).digest("The quick ", "brown ", "fox jumps over the lazy dog"); //Usually CRCs are printed in this order, though: writeln(toHexString!(Order.decreasing)(crc32)); // "414FA339"
- class WrapperDigest(T) if (isDigest!T): Digest;
-
Оборачивает структуру хэша API шаблонов в интерфейс Digest. Модули, предоставляющие реализации дайджестов, обычно предоставляют псевдоним для этого шаблона (например, MD5Digest, SHA1Digest, ...).
- Примеры:
-
import std.digest.md; //Simple example auto hash = new WrapperDigest!MD5(); hash.put(cast(ubyte) 0); auto result = hash.finish();
- Примеры:
-
//using a supplied buffer import std.digest.md; ubyte[16] buf; auto hash = new WrapperDigest!MD5(); hash.put(cast(ubyte) 0); auto result = hash.finish(buf[]); //The result is now in result (and in buf). If you pass a buffer which is bigger than //necessary, result will have the correct length, but buf will still have it's original //length
- this();
-
Инициализирует дайджест.
- nothrow @trusted void put(scope const(ubyte)[] data...);
-
Используйте это для подачи данных в дайджест. Также реализует интерфейс
std.range.primitives.isOutputRangeдляubyteиconst(ubyte)[]. - nothrow @trusted void reset();
-
Сбрасывает внутреннее состояние дайджеста.
- Примечание
- Вызовы
finishвызывают это внутри, поэтому нет необходимости вызыватьresetвручную после вызоваfinish.
- const pure nothrow @property @trusted size_t length();
-
Это длина в байтах значения хэша, которое возвращается вызовом
finish. Это также необходимый размер буфера, передаваемого вfinish. - nothrow ubyte[] finish(ubyte[] buf);
nothrow @trusted ubyte[] finish(); -
Функция finish возвращает значение хэша. Она принимает необязательный буфер для копирования данных. Если буфер передан, он должен иметь длину не менее
lengthбайт.- Пример
import std.digest.md; ubyte[16] buf; auto hash = new WrapperDigest!MD5(); hash.put(cast(ubyte) 0); auto result = hash.finish(buf[]); //The result is now in result (and in buf). If you pass a buffer which is bigger than //necessary, result will have the correct length, but buf will still have it's original //length
- const @trusted ubyte[] peek(ubyte[] buf);
const @trusted ubyte[] peek(); -
Действует как
finishно не сбрасывает внутреннее состояние, поэтому после вызова peek можно продолжить подачу данных в этот WrapperDigest.Эти функции доступны только если
hasPeek!Tимеет значение true.
- bool secureEqual(R1, R2)(R1 r1, R2 r2)
Constraints: if (isInputRange!R1 && isInputRange!R2 && !isInfinite!R1 && !isInfinite!R2 && (isIntegral!(ElementEncodingType!R1) || isSomeChar!(ElementEncodingType!R1)) && !is(CommonType!(ElementEncodingType!R1, ElementEncodingType!R2) == void)); -
Безопасно сравнивает два представления дайджеста, защищаясь от атак по времени. Не используйте
==для сравнения представлений дайджестов.Атака происходит следующим образом:
- Злоумышленник хочет отправить вредоносные данные на ваш сервер, что требует токена целостности HMAC SHA1, подписанного секретом.
- Длина токена известна и составляет 40 символов, поэтому злоумышленник сначала отправляет
"0000000000000000000000000000000000000000", затем"1000000000000000000000000000000000000000", и так далее. - Полученный токен HMAC сравнивается с ожидаемым токеном с помощью
==сравнения строк, которое возвращаетfalseкак только будет найден первый неверный элемент. Если найден неверный элемент, отправителю возвращается сообщение об отклонении. - В конечном итоге злоумышленник может определить первый символ правильного токена, потому что сервер немного дольше возвращает сообщение об отклонении. Это происходит из-за того, что сравнение переходит ко второму элементу в двух массивах, видит, что они разные, и затем отправляет сообщение об отклонении.
- Может показаться, что разница во времени слишком мала для обнаружения злоумышленником, но исследователи в области безопасности показали, что различия вплоть до 20µs могут быть надежно различимы даже с сетевыми несоответствиями.
- Повторите процесс для каждого символа, пока злоумышленник не получит весь правильный токен, и сервер не примет вредоносные данные. Это можно сделать за неделю, если злоумышленник осуществляет атаку с частотой 10 запросов в секунду с использованием только одного клиента.
Эта функция защищает от этой атаки, всегда сравнивая каждый элемент в массиве, если длины двух массивов одинаковы. Поэтому эта функция всегда Ο(n) для диапазонов одинаковой длины.
Эту атаку также можно смягчить с помощью ограничения скорости и блокировки IP-адресов с слишком большим количеством отклоненных запросов. Однако это не полностью решает проблему, так как злоумышленник может контролировать ботнет. Для полной защиты от атаки по времени необходимо использовать ограничение скорости, блокировку IP-адресов и данную функцию вместе.- Параметры:
R1 r1Представление дайджеста R2 r2Представление дайджеста
- Возвращаемое значение:
-
trueесли оба представления равны,falseв противном случае
- См. также:
- Статья Википедии об атаках по времени.
- Примеры:
-
import std.digest.hmac : hmac; import std.digest.sha : SHA1; import std.string : representation; // a typical HMAC data integrity verification auto secret = "A7GZIP6TAQA6OHM7KZ42KB9303CEY0MOV5DD6NTV".representation; auto data = "data".representation; auto hex1 = data.hmac!SHA1(secret).toHexString; auto hex2 = data.hmac!SHA1(secret).toHexString; auto hex3 = "data1".representation.hmac!SHA1(secret).toHexString; assert( secureEqual(hex1[], hex2[])); assert(!secureEqual(hex1[], hex3[]));
© 1999–2021 The D Language Foundation
Licensed under the Boost License 1.0.
https://dlang.org/phobos/std_digest.html