Spec-Zone.ru › D

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, и т. д.
API шаблонов немного эффективнее. Он не должен выделять память динамически, вся память выделяется в стеке. API ООП должен выделить память в методе finish, если буфер не был предоставлен. Если вы предоставите буфер для функции finish API ООП, память не выделяется, но классы 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 isDigest test.

Примечание
  • 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)

Используйте этот шаблон для получения типа, возвращаемого методом finish digest.

Примеры:
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 с ElementType ubyte, 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 с ElementType ubyte, 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));

Безопасно сравнивает два представления дайджеста, защищаясь от атак по времени. Не используйте == для сравнения представлений дайджестов.

Атака происходит следующим образом:

  1. Злоумышленник хочет отправить вредоносные данные на ваш сервер, что требует токена целостности HMAC SHA1, подписанного секретом.
  2. Длина токена известна и составляет 40 символов, поэтому злоумышленник сначала отправляет "0000000000000000000000000000000000000000", затем "1000000000000000000000000000000000000000", и так далее.
  3. Полученный токен HMAC сравнивается с ожидаемым токеном с помощью == сравнения строк, которое возвращает false как только будет найден первый неверный элемент. Если найден неверный элемент, отправителю возвращается сообщение об отклонении.
  4. В конечном итоге злоумышленник может определить первый символ правильного токена, потому что сервер немного дольше возвращает сообщение об отклонении. Это происходит из-за того, что сравнение переходит ко второму элементу в двух массивах, видит, что они разные, и затем отправляет сообщение об отклонении.
  5. Может показаться, что разница во времени слишком мала для обнаружения злоумышленником, но исследователи в области безопасности показали, что различия вплоть до 20µs могут быть надежно различимы даже с сетевыми несоответствиями.
  6. Повторите процесс для каждого символа, пока злоумышленник не получит весь правильный токен, и сервер не примет вредоносные данные. Это можно сделать за неделю, если злоумышленник осуществляет атаку с частотой 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

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API