Как создать HashCode в .net(С#) для строки, безопасной для хранения в базе данных?

В цитате из Руководства и правила для GetHashCode Эрика Липперта:

Правило: Потребители GetHashCode не могут полагаться на то, что он стабилен с течением времени или через приложения.

Предположим, что у вас есть объект Customer у которого есть куча таких полей, как Name, Адрес и т.д. Если вы сделаете два такие объекты с точно такими же данных в двух разных процессах, они не нужно возвращать один и тот же хэш код. Если вы сделаете такой объект на Вторник в один процесс, выключите его, и снова запустить программу В среду хэш-коды могут быть отличается.

Это укусило людей в прошлом. Документация для Заметки System.String.GetHashCode в частности, что два идентичных строки могут иметь разные хэш-коды в разных версиях CLR и на самом деле они это делают. Не хранить хеши в базах данных и ожидать, что они будут неизменными навсегда, потому что они не будут.

Итак, каков правильный способ создания HashCode строки, которую я могу хранить в базе данных?

(Пожалуйста, скажите мне, что я не первый человек, который оставил эту ошибку в программном обеспечении, которое я написал!)

Ответ 1

Это зависит от того, какие свойства вы хотите, чтобы иметь хэш. Например, вы можете просто написать что-то вроде этого:

public int HashString(string text)
{
    // TODO: Determine nullity policy.

    unchecked
    {
        int hash = 23;
        foreach (char c in text)
        {
            hash = hash * 31 + c;
        }
        return hash;
    }
}

Пока вы документируете, что так вычисляется хеш, это действительно. Это никоим образом не криптографически безопасно или что-то в этом роде, но вы можете сохранить его без проблем. Две строки, которые абсолютно равны в порядковом смысле (т.е. Без какого-либо культурного равенства и т.д., Точно одинаковые по характеру, будут иметь одинаковый хэш с этим кодом.

Проблемы возникают, когда вы полагаетесь на недокументированное хеширование - то есть что-то, что подчиняется GetHashCode(), но никоим образом не гарантируется, что оно останется неизменным с версии на версию... например string.GetHashCode().

Написание и документирование вашего собственного хэша, как это, немного напоминает высказывание: "Эта конфиденциальная информация хешируется MD5 (или что-то еще)". Пока это четко определенный хеш, это прекрасно.

EDIT: Другие ответы предложили использовать криптографические хеши, такие как SHA-1 или MD5. Я бы сказал, что до тех пор, пока мы не узнаем, что требуется криптографическая безопасность, а не просто стабильность, нет смысла переходить к тому, чтобы преобразовать строку в массив байтов и хешировать. Конечно, если хеш предназначен для использования в любых связанных с безопасностью, стандартная хэш-версия - именно то, к чему вы должны стремиться. Но об этом не упоминалось нигде в вопросе.

Ответ 2

Например, вы можете создать хэш MD5.

Ответ 3

Вот повторная реализация текущий способ .NET вычисляет строковый хеш-код для 64-битных систем. Это не использует указатели, как реальный GetHashCode(), поэтому он будет немного медленнее, но делает его более устойчивым к внутренним изменениям в string, это даст более равномерно распределенный хэш-код, чем Jon Skeet, что может привести к лучшему времени поиска в словарях.

public static class StringExtensionMethods
{
    public static int GetStableHashCode(this string str)
    {
        unchecked
        {
            int hash1 = 5381;
            int hash2 = hash1;

            for(int i = 0; i < str.Length && str[i] != '\0'; i += 2)
            {
                hash1 = ((hash1 << 5) + hash1) ^ str[i];
                if (i == str.Length - 1 || str[i+1] == '\0')
                    break;
                hash2 = ((hash2 << 5) + hash2) ^ str[i+1];
            }

            return hash1 + (hash2*1566083941);
        }
    }
}

Ответ 4

Ответ заключается в том, чтобы просто написать собственную функцию хэширования. Вы можете найти источник для некоторых из следующих ссылок в комментариях к статье, которую вы опубликовали. Или вы можете использовать встроенную хэш-функцию, которая первоначально предназначалась для криптографии (MD5, SHA1 и т.д.) И просто не использовать все биты.