Perché tr non può leggere da / dev / urandom su OSX?


35

Un collega ha suggerito di creare una chiave casuale tramite il seguente comando:

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

Mi ha dato l'errore:

tr: sequenza di byte non valida

Sono preoccupato di non avere /dev/urandomsul mio sistema. Ho provato a cercare su Google come installare questo file, ma mi sono trovato vuoto. Ho provato locate urandome anche mi è venuto in mente vuoto. (beh, in realtà, ha trovato la pagina man, ma non aiuta)

Come posso renderlo urandomdisponibile sul mio sistema Mac OSX? (Leone)


3
Interessante uso di xargs...
sendmoreinfo,

Risposte:


49

Sulla base del messaggio di errore che ricevi, non credo che / dev / urandom sia il problema. Se lo fosse, mi aspetterei un errore come "nessun file o directory".

Ho cercato il messaggio di errore che hai ricevuto e l'ho trovato, che potrebbe essere rilevante per il tuo problema: http://nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence

Fondamentalmente, specifica la locale anteponendo il trcomando con LC_CTYPE=C:

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

Grazie, questo ha davvero funzionato. Qualche idea sul perché non riesco a trovare urandomo random? Sono speciali "file" magici che non esistono sul vero filesystem? (Ho anche suggerito una modifica per aiutare a mitigare il collegamento-marciume)
Kirk Woll il

1
Credo locateche non cerchi direttamente nel tuo filesystem, ma piuttosto cerchi la tua query usando un database pre-costruito. Molto probabilmente questo database è configurato per ignorare / dev / e altri filesystem "speciali".
lk-

abbastanza giusto, ma non lo vedo quando guardo direttamente dentro /dev. Vai a capire. Ma grazie ancora per l'aiuto.
Kirk Woll,

1
non sembra funzionare su 10.9; fallisce ancora con lo stesso messaggio di errore. LC_ALL=Cfa il trucco però.
Erik Kaplun,

1
Si prega di cambiare quel link a nerdbynature.de/s9y/2010/04/11/tr-Illegal-byte-sequence poiché attualmente punta alla pagina del blog più recente che non contiene le trinformazioni.
Jeroen Wiert Pluimers,

11

I tuoi trtentativi di interpretare il suo input come testo nella codifica UTF-8. Quindi si lamenterà e interromperà la prima sequenza di byte che non è valida UTF-8. Il prefisso trcon LC_ALL=Co LC_CTYPE=Cesporterà quella variabile nell'ambiente di tr, cambiando così la sua idea del set di caratteri locali allo standard C, cioè tutto è solo una sequenza di byte opachi.

A proposito, la sequenza \)-+nel tuo comando è intenzionale? Questo include *anche quello che hai già incluso, ma non include -se stesso come avresti potuto intendere. Meglio scrivere uno di questi invece:

LC_ALL=C tr -dc 'A-Za-z0-9_!@#$%^&*()\-+=' < /dev/urandom
LC_CTYPE=C tr -dc A-Za-z0-9_\!\@\#\$\%\^\&\*\(\)\\-+= < /dev/urandom

6

Come altri hanno indicato, il tuo problema non è quello che /dev/urandommanca, ma piuttosto come trfunziona su OS X. Invece di fare casini con varialbes ambientali, usa perlal posto di tr:

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

Questo ha il vantaggio di essere portatile su OS X, Redhat e Ubuntu.

(Ho anche rimosso il tubo xargs, in sostituzione di strega echo, per ottenere una nuova riga alla fine dell'output.)


Prima o poi, mi aspetto che Perl diventi binmode ":utf8"standard, a quel punto la tua soluzione Perl avrà lo stesso problema tr.
Segna il

Risolto il problema di Mark aggiungendo binmode (STDIN, ": bytes") all'esempio di codice.
Trenton,

2

In primo luogo, hai intenzione di includere -o *nell'elenco dei caratteri validi? Il parametro trinclude la sequenza )-+che significa "l'intervallo di byte che inizia )e termina con +, che in realtà è)*+ .

In secondo luogo, piuttosto che leggere molti kilobyte dal pool di entropia del kernel (e quindi contrassegnare l'intero pool come insicuro, che avrà un impatto su tutti gli altri processi che richiedono entropia sicura), considera di leggere solo tutti i bit di cui hai bisogno: usa head -c...come primo passo, e quindi tradurre anziché scartare i caratteri indesiderati.

Questa particolare versione del problema è un po 'insolita in quanto utilizza 76 simboli diversi; la maggior parte vuole solo alfanumerico, quindi se ti accontenti solo di 64 simboli, l'utilizzo base64dell'utilità minimizzerà il consumo del pool di entropia (nota che 24 è 6/8 di 32):

head -c24 < /dev/random | base64

1

La codifica dei caratteri della tua locale (che puoi capire locale charmap) è un multibyte per carattere.

Il più comune al giorno d'oggi è UTF-8 in cui i caratteri possono essere codificati da 1 a 4 byte. Non tutte le sequenze di byte formano caratteri validi in UTF-8. Ogni carattere non ASCII in UTF-8 inizia con un byte con i due bit più alti impostati e indica quanti byte seguono il set di bit più alto (ma non il secondo più alto).

/dev/urandomcontiene un flusso casuale di byte. trtraslittera carattere, quindi deve decodificare quei byte come caratteri. Quei caratteri ASCII nel tuo intervallo sono tutti codificati su un carattere in UTF-8, ma trdevono comunque decodificare tutti i caratteri. Esistono ad esempio altre codifiche multi-byte in cui alcuni caratteri diversi da quelli Acontengono il byte 0x41 (il codice per A).

Perché quel flusso casuale di byte è destinato a contenere sequenze non valide (ad esempio un byte 0x80 da solo non è valido in UTF-8 poiché un carattere non ASCII deve iniziare con un byte maggiore di 0xc1 (0xc0 e 0xc1 non sono in UTF- 8 caratteri)), quindi trritorna con un errore quando ciò accade.

Quello che vuoi qui è considerare quel flusso di byte come caratteri in una codifica che ha un byte per carattere. Quale scegliete non è importante come tutti quei personaggi nella vostra gamma (assumendo AZ, è significava ABCDEFGHIJKLMNOPQRSTUVWXYZ e non le cose come Ý, Ê) fanno parte del set di caratteri portatile in modo da codificare la stessa in tutti i set di caratteri supportati sul sistema.

Per questo, quando si imposta la LC_CTYPEvariabile di localizzazione, che è quella che decide quali set di caratteri viene utilizzato e quali cose come blank, alphaclassi di personaggi contengono. Ma per la definizione dell'intervallo AZ, dovrai anche impostare la LC_COLLATEvariabile (quella che decide dell'ordinamento delle stringhe).

La locale Caka POSIXè quella che garantisce che i caratteri siano a byte singolo e AZ sia ABCDEFGHIJKLMNOPQRSTUVWXYZ. Potresti fare:

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

(qui spostare la -fine, altrimenti, )-+sarebbe come un intervallo come A-Z)

Ma si noti che la LC_ALLvariabile sovrascrive tutti gli altri LC_*e LANGvariabili. Quindi, se LC_ALLaltrimenti è già definito, quanto sopra non avrà alcun effetto. Quindi invece puoi semplicemente fare:

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

Ciò influirà su altre cose come la lingua dei messaggi di errore, ma comunque, cambiare LC_CTYPE potrebbe già essere stato un problema per i messaggi di errore (ad esempio, nessun modo di esprimere messaggi di errore russo o giapponese nel set di caratteri della locale C).


0

Secondo la pagina man , / dev / random sarà probabilmente sufficiente per le tue esigenze. Forse Apple ha smesso di creare / dev / urandom perché non è necessario?


Non ho /dev/randomneanche.
Kirk Woll,

MacOSX dovrebbe avere sia / dev / random che / dev / urandom. Forse Apple non include più quei file speciali? O forse è lì solo se installi XCode?
jsbillings

1
FWIW, entrambi i dispositivi sono presenti sulla mia workstation Lion aggiornata a Mountain Lion. Credo che fosse presente anche su Lion. Anche i nodi sono diversi (13,0 contro 13,1)
mrb
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.