Почему нельзя читать из / dev / urandom в OSX?

35

Коллега предложил создать случайный ключ с помощью следующей команды:

tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs

Это дало мне ошибку:

tr: недопустимая последовательность байтов

Я обеспокоен тем, что у меня нет /dev/urandomв моей системе. Я попытался поискать в Google, чтобы выяснить, как установить этот файл, но у меня ничего не получилось. Я пытался locate urandomи тоже пришел пустой. (ну, на самом деле, он нашел справочную страницу, но это не помогает)

Как сделать urandomдоступным в моей системе Mac OSX? (Лев)

Кирк Волл
источник
3
Интересное использование xargs...
sendmoreinfo

Ответы:

49

Судя по полученному вами сообщению об ошибке, я не думаю, что проблема заключается в / dev / urandom. Если бы это было так, я бы ожидал ошибку типа «нет такого файла или каталога».

Я искал сообщение об ошибке, которое вы получили, и обнаружил, что оно может иметь отношение к вашей проблеме: http://nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence

По сути, укажите локаль, добавив trкоманду с помощью LC_CTYPE=C:

LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+= < /dev/urandom | head -c 32 | xargs
lk-
источник
Спасибо, это действительно помогло. Любая идея, почему я не могу найти urandomили random? Это особые магические «файлы», которых нет в реальной файловой системе? (Также я предложил изменить, чтобы помочь смягчить гниение ссылок)
Кирк Волл
1
Я полагаю, locateчто не ищет непосредственно вашу файловую систему, а скорее ищет ваш запрос, используя предварительно созданную базу данных. Эта база данных, скорее всего, настроена на игнорирование / dev / и других «специальных» файловых систем.
lk-
достаточно справедливо, но я не вижу этого, когда смотрю прямо внутрь /dev. Пойди разберись. Но еще раз спасибо за помощь.
Кирк Волл
1
кажется, не работает на 10,9; по-прежнему не удается с тем же сообщением об ошибке. LC_ALL=Cделает трюк
Эрик Каплун
1
Пожалуйста, измените эту ссылку на nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence, поскольку в настоящее время она указывает на самую последнюю страницу блога, не содержащую trинформацию.
Йерун Wiert Pluimers
11

Ваши trпопытки интерпретировать его ввод как текст в кодировке UTF-8. Таким образом, он будет жаловаться и прерываться на первой последовательности байтов, которая не является допустимой UTF-8. Приставка trс LC_ALL=Cили LC_CTYPE=Cбудет экспортировать эту переменную в окружающую среду tr, тем самым изменяя его идею локального набора символов в стандарте C, то есть все это просто последовательность байтов непрозрачными.

Кстати, последовательность \)-+в вашей команде преднамеренная? Это включает *в себя также, что вы уже включили, но не включает -себя, как вы, возможно, хотели. Лучше написать один из них вместо этого:

LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()\-+=' < /dev/urandom
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)\\-+= < /dev/urandom
MVG
источник
6

Как уже отмечали другие, ваша проблема не в том, что /dev/urandomотсутствует, а скорее в том, как trработает на OS X. Вместо того, чтобы возиться с enviournment varialbes, используйте perlвместо tr:

perl -pe 'binmode(STDIN, ":bytes"); tr/A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)-+=//dc;' < /dev/urandom | head -c 32; echo

Это имеет преимущество в переносимости через OS X, Redhat и Ubuntu.

(Я также удалил канал xargs, заменяя ведьму echo, чтобы получить новую строку в конце вывода.)

Трентон
источник
Рано или поздно я ожидаю, что Perl сделает binmode ":utf8"стандарт, и в этот момент ваше решение Perl будет иметь ту же проблему, что trи.
Марк
Решил проблему Марка, добавив binmode (STDIN, ": bytes") к примеру кода.
Трентон
2

Во-первых, вы намеревались включить -или *в список допустимых символов? Параметр, который trвключает последовательность, )-+которая означает «диапазон байтов, начинающийся с )и заканчивающийся +, который на самом деле )*+.

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

Эта конкретная версия проблемы немного необычна, поскольку использует 76 различных символов; большинству просто нужны буквенно-цифровые символы, поэтому, если вы будете удовлетворены только 64 символами, использование base64утилиты сведет к минимуму потребление пула энтропии (обратите внимание, что 24 равно 6/8 из 32):

head -c24 < /dev/random | base64
Мартин Кили
источник
1

Кодировка символов вашей локали (которую вы можете сказать locale charmap) - многобайтовая на символ.

Наиболее распространенным в настоящее время является UTF-8, где символы могут быть закодированы от 1 до 4 байтов. Не все последовательности байтов образуют допустимые символы в UTF-8. Каждый не ASCII-символ в UTF-8 начинается с одного байта, в котором установлены два старших бита, и сообщает, сколько байтов следует за старшим (но не вторым старшим) битом.

/dev/urandomсодержит случайный поток байтов. trтранслитерирует символ, поэтому он должен декодировать эти байты как символы. Все символы ASCII в вашем диапазоне кодируются одним символом в UTF-8, но trвсе же необходимо декодировать все символы. Есть, например, другие многобайтовые кодировки, где некоторые символы, кроме, Aсодержат байт 0x41 (код для A).

Поскольку этот случайный поток байтов должен содержать недопустимые последовательности (например, сам по себе байт 0x80 является недопустимым в UTF-8, так как не-ASCII-символ должен начинаться с байта, большего чем 0xc1 (0xc0 и 0xc1 отсутствуют в UTF- 8 символов)), поэтому trвозвращается с ошибкой, когда это происходит.

Здесь вы хотите рассмотреть этот поток байтов как символы в кодировке, которая имеет один байт на символ. Какой бы вы выбрали, не важно , так как все эти символы в вашем диапазоне (предполагая , что от AZ, вы имели в виду ABCDEFGHIJKLMNOPQRSTUVWXYZ и не такие вещи , как Ý, Ê) являются частью портативного набора символов так быть закодированы то же самое во всех кодировок , поддерживаемых в системе.

Для этого, нужно установить LC_CTYPEпеременную локализации , которая является тот , который решает , какой набор символов используется и то , что такие вещи , как blank, alphaсимвольные классы содержат. Но для определения диапазона AZ вы также захотите установить LC_COLLATEпеременную (ту, которая решает порядок строк).

CАка POSIXлокаль одно , что гарантирует символы в одиночные байты и AZ является АБВГДЕЖЗИКЛМНОПРСТУФХЧШЭЮЯ. Вы могли бы сделать:

 LC_CTYPE=C LC_COLLATE=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'

(здесь перемещение -до конца, в противном случае, )-+будет восприниматься как диапазон A-Z)

Но обратите внимание, что LC_ALLпеременная переопределяет все остальные LC_*и LANGпеременные. Таким образом, если LC_ALLиное уже определено, вышеприведенное не будет иметь никакого эффекта. Так что вместо этого вы можете просто сделать:

 LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()+=-'

Это повлияет на другие вещи, такие как язык сообщений об ошибках, но в любом случае изменение LC_CTYPE уже могло быть проблемой для сообщений об ошибках (например, нет способа выразить русские или японские сообщения об ошибках в кодировке локали C).

Стефан Шазелас
источник
0

Согласно справочной странице , / dev / random, вероятно, будет достаточно для ваших нужд. Возможно, Apple перестала создавать / dev / urandom, потому что в этом нет необходимости?

jsbillings
источник
У меня тоже нет /dev/random.
Кирк Уолл,
MacOSX должен иметь как / dev / random, так и / dev / urandom. Возможно, Apple больше не включает эти специальные файлы? Или, может быть, это только там, если вы установите XCode?
Jsbillings
1
FWIW, оба устройства присутствуют на моей рабочей станции, обновленной до Lion. Я полагаю, что это присутствовало и на Льве. Узлы тоже разные (13,0 против 13,1)
mrb