Generator losowych haseł


40

Serwer domeny wymaga, aby wszyscy pracownicy mieli silne, losowe hasło zgodne z następującymi zasadami:

  • Dokładnie 15 znaków.
  • Tylko znaki wpisywane na klawiaturze (jak pokazano poniżej w kodzie). Nauczanie sprzedaży używania kodów ALT + NUMPAD jest niedozwolone.
  • Co najmniej 1 mała litera: abcdefghijklmnopqrstuvwxyz
  • Co najmniej 1 duża litera: ABCDEFGHIJKLMNOPQRSTUVWXYZ
  • Co najmniej 1 cyfra: 0123456789
  • Co najmniej 1 symbol: `~!@#$%^&*()_+-={}|[]\:";'<>?,./

W tym celu dział IT zlecił i rozprowadzi generator losowych haseł do wszystkich pracowników. Wszyscy pracownicy będą zobowiązani do korzystania z generatora losowych haseł. Wymagania dotyczące generatora losowych haseł to, oprócz powyższych ograniczeń hasła:

  • Musi być w stanie wygenerować wszystkie permutacje wszystkich dozwolonych znaków.
  • Musi wyświetlać wygenerowane hasło na ekranie.
  • Kod musi być jak najmniejszy (w bajtach).

Prześlij swoje proponowane rozwiązanie w ciągu następnego tygodnia.


10
Powinieneś także zażądać, aby wszystkie dozwolone hasła pojawiały się z takim samym prawdopodobieństwem (w przeciwnym razie mogę po prostu utworzyć listę o długości 30 znaków z dozwolonymi znakami, przetasować ją i podać pierwsze 15)
— Martin Thoma

@moose, zgodził się. Dodałem nową regułę.
— Hand-E-Food

22
Informatycy powinni zostać zwolnieni, a przynajmniej lepiej wykształceni: jeśli generujesz hasła losowo, wówczas ograniczenie zestawu dozwolonych haseł do tych, które zawierają co najmniej jedną postać z każdej kategorii, w rzeczywistości osłabia hasła, ponieważ zmniejsza rozmiar dopuszczalny zestaw. A nasze programy byłyby o wiele łatwiejsze, gdybyśmy nie musieli tego sprawdzać… OK, nie modyfikuj konkursu po otrzymaniu tylu zgłoszeń; jest w porządku jako wyzwanie.
— MvG


1
Tak naprawdę nie odpowiedziałeś na @moose, wymagając, aby wszystkie hasła były generowalne. Powinny pojawić się z jednakowym prawdopodobieństwem.
— Ethan Bolker

Odpowiedzi:


29

Matematyka (18)

Pozwól mi trochę oszukać

= 15char ASCII pwd
&(^F7yP8k:*1P<t

PS to nie bezpieczeństwo :)


6
Gdzie jest kod
— DavidC

11
Czy to gwarantuje spełnienie przynajmniej jednego z wymagań każdej klasy postaci ?
— Hand-E-Food

3
@ Hand-E-Food Tak, jest! Jeśli spojrzysz na interpretację, zobaczysz: długość hasła 15, wymagane małe litery, wymagane duże litery, wymagane cyfry, wymagane znaki specjalne.
— ybeltukov,

6
+1 Sprytny, ale podstępny.
— DavidC

10
Wiedziałem, że Mathematica ma funkcję do wszystkiego, ale to ?
— Konrad Borowski

13

Ruby, 74 69 bajtów

Po prostu losowo próbkuj z zakresu ascii 33–126, aż wszystkie klasy znaków będą obecne:

$_=[*?!..?~].sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
p$_

Rubin, 39 bajtów

Wykorzystując sprytne odkrycie łosia:

p"0123abcdABCD-+/<".chars.sample(15)*''

Edytuj, aby zaspokoić tłum:

Pamiętaj, że zasady uległy zmianie po pierwszym opublikowaniu tego. W tym czasie oba poprzednie wpisy dotyczyły reguł. Chciałbym również zauważyć, że reguły wciąż nie są zbyt dobrze zdefiniowane:

(..) wszystkie kombinacje wszystkich dopuszczalnych znaków

„Permutacje”. Nie ma permutacji dozwolonych znaków, która jest zgodna z resztą reguł, ponieważ każda permutacja zestawu dozwolonych znaków jest tak długa, jak sam zestaw dopuszczalnych znaków (podczas gdy hasło powinno mieć 15 znaków). I nie ma powtórzeń w permutacji. Mój pierwszy wpis jest jednak bardziej „losowy” niż wiele innych dobrze ocenianych odpowiedzi tutaj.

Niemniej jednak masz to. Umożliwia powtórzenia znaków i podkreślenie:

Rubinowy, 77 bajtów

$_=([*?!..?~]*15).sample(15)*''until~/\d/&&~/[a-z]/&&~/[A-Z]/&&~/\W|_/
puts$_

Użyłem również putszamiast ptego, ponieważ pdrukuje ciąg zamknięty w „cudzysłowie”, a niektóre znaki uciekały odwrotnym ukośnikiem.

Rubinowy, 70 bajtów

Jak zauważa Ventero, ~można go pominąć przed wyrażeniami regularnymi i printzastąpić puts$_. Ale z brzydkim wyjściem powoduje to, że równie dobrze możesz wydrukować wszystkie odrzucone hasła, ściskając je w jednej linijce:

puts$_=([*?!..?~]*15).sample(15)*''until/\d/&&/[a-z]/&&/[A-Z]/&&/\W|_/

Wyjaśnienie

Zgodnie z prośbą. $_jest pół-magiczną zmienną, która zawiera ostatni wiersz odczytany z danych wejściowych - więc nie zawsze musisz ją przechowywać, tak jak to . Tutaj jednak używamy go z powodu innej właściwości, a mianowicie, że ~operator stosuje do niej wyrażenie regularne, sztuczkę, której nauczyłem się po raz pierwszy przez Chrona . Zastąpiłem użycie all, ale powinno być dość łatwe do zrozumienia, jeśli dostaniesz resztę ( zobacz dokumenty ).


2
Czy mógłbyś wyjaśnić trochę swój kod? Co ma .all?{|r|~r}zrobić? Co ma $_=zrobić?
— Martin Thoma,

3
Przykładowa linia jest sprytna, ale myślę, że narusza „Musi być w stanie wygenerować wszystkie permutacje wszystkich dozwolonych znaków”. Nigdzie nie jest powiedziane, że hasło może zawierać reklamy tylko w zakresie liter. Jeśli z jest znakiem dozwolonym, powinna istnieć szansa> 0, że z jest w haśle.
— nitro2k01

1
Czy \Ww Ruby zawiera podkreślenie _? W większości dialektów regularnych wiem, że tak nie jest. A jeśli twój kod nie mógł wygenerować haseł, w których pojedynczy _był jedynym niealfanumerycznym symbolem, to naruszyłoby jedno wymaganie. Drugie podejście bardzo oczywiście narusza ten wymóg, ale wydaje mi się, że w tamtym czasie nie było poprawnie sformułowane.
— MvG

1
@MvG: Masz rację. \Wnie zawiera podkreślenia w RegEx kompatybilnym z Perlem ( źródło ).
— Martin Thoma,

1
Co więcej, na twoje rozwiązanie wpływa ten sam problem @moose, który miałem z Pythonem: samplenie powtarza elementów, więc hasła z powtarzającymi się elementami nie mogą być generowane przez kod. Czy możesz rozwiązać te dwa problemy, aby twoja odpowiedź była zgodna z pytaniem? Widząc, jak twoje jest wiodącym rozwiązaniem, z wyjątkiem Wolfram Alpha, fajnie byłoby zobaczyć, czy możesz się dostosować i nadal utrzymać pozycję lidera. Myślę, że nie powinno to być zbyt trudne.
— MvG

12

Java 8 - 354 329 319 275 267 znaków

Dla zabawy, używając lambda z Javą 8 - każde możliwe wyjście ma takie samo prawdopodobieństwo znalezienia.

Wykorzystuje fakt, że dozwolone znaki mają kolejne kody ascii, od 33 do 126.

class A {
    //flags for, respectively, small caps, large caps, digits, punctuation
    static int a, A, d, p;

    public static void main(String[] x) {
        String s;
        do {
            //Using special String constructor that takes an int[]
            s = new String(new java.util.Random().ints(15, 33, 127)
                                .toArray(),
                           0, 15);
            a = A = d = p = 0;
            s.chars()
                .map(c ->
                      c > 96 & c < 123 ? a = 1
                    : c > 64 & c < 90  ? A = 1
                    : c > 47 & c < 58  ? d = 1
                    : (p = 1))
                .min();
        } while (a + A + d + p < 4);
        System.out.println(s);
    }
}

Przykładowe dane wyjściowe:

.*;Tm?svthiEK`3  
o.dzMgtW5|Q?ATo  
FUmVsu<4JF4eB]1

Skompresowany program:

class A{static int a,A,d,p;public static void main(String[]x){String s;do{s=new String(new java.util.Random().ints(15,33,127).toArray(),0,15);a=A=d=p=0;s.chars().map(c->c>96&c<123?a=1:c>64&c<90?A=1:c>47&c<58?d=1:(p=1)).min();}while(a+A+d+p<4);System.out.println(s);}}


Jak o while(a+A+d+p<4)wraz z a|=1zamiast a++? Lub użyj masek bitowych, tj. Takich jak a|=1przelotowe a|=8, z a<15warunkiem pętli as. To oszczędza kolejne 13 znaków, jeśli poprawnie policzyłem.
— MvG

@MvG dobra uwaga - zrobiłem coś podobnego, oszczędzając kilka dodatkowych znaków, jak sądzę.
— assylias

@MvG A używanie new String(int[],int,int)zapisuje kolejne 40 znaków nieparzystych!
— assylias

8

Python 2.X + 3.X (229 znaków): Generuj i zamień

Pomysł

  1. Najpierw utwórz listę z 15 dozwolonymi symbolami
  2. Zamień losową pozycję rna losową cyfrę
  3. Wymienić losową pozycję s, z s != r, przez górną litery
  4. To samo dotyczy małych liter i symboli jak w 2 i 3.

Kod

from random import randint as r, shuffle as s
a=list(range(15))
p=a[:]
for i in range(15):
    a[i]=chr(r(32,126))
s(p)
a[p.pop()]=chr(r(48,57))
a[p.pop()]=chr(r(65,90))
a[p.pop()]=chr(r(97,122))
a[p.pop()]=chr(r(33,47))
print(a)

Python 2.X + 3.X (194 znaki): Wygeneruj i sprawdź

import random
from re import search as s
p=''
while not all([s("\d",p),s("[a-z]",p),s("[A-Z]",p),s("[\W_]",p)]):
 p=str(map(chr,[random.choice(list(range(33,127))) for i in range(15)]))
print(p)
  • Dzięki MvG, który mi to powiedział \ui \lnie istnieje w wyrażeniu regularnym Python.
  • Dzięki grc, który powiedział mi, że random.samplenie ma zamiany, aby uzyskać każde możliwe dozwolone hasło, musimy pobrać próbkę z wymianą.

Wykorzystanie błędu w opisie problemu

Obecnie opis problemu nie wymaga, aby każdy symbol / cyfra pojawiał się z takim samym prawdopodobieństwem. Dzięki poniższemu rozwiązaniu nie można zakładać żadnego pojedynczego symbolu i / lub pozycji. Ale możesz to zrobić za pomocą wielu.

Python 2.X + 3.X (62 znaki)

from random import sample
print(sample("0123abcdABCD-+/<",15))

Dzięki Daniero za pomysł użycia próbki.


Bardzo płynne znalezienie wady! Podłączyłem ten, ale punkty bonusowe za jego identyfikację. :-)
— Hand-E-Food

Twój gen i czek jest podobny do mojego podejścia. Z ciekawości: gdzie to jest \ludokumentowane dla wyrażeń regularnych w Pythonie? Nie widzę tego w referencji . Mój Python 3.3.3 nawet nie zaakceptuje "\u". str(…)Nie łączy litery w obu 3.3.3 lub 2.7.6. Jedna sugestia dla optmization: all(s("\\"+i,p)for i in "dluW").
— MvG

random.samplewybiera elementy bez zamiany, więc nie wszystkie hasła są możliwe.
— grc

@MvG: Dziękuję. Właśnie to widziałem \ui \ljest to tylko vim.
— Martin Thoma,

7

Bash na * nix (109)

while ! grep -Pq [A-Z].*[a-z].*[0-9].*[\\W_]<<<$a$a$a$a
do a=`tr -dc !-~</dev/urandom|head -c15`
done
echo $a

Aby działać poprawnie, $anie może być ustawione na prawidłowe, ale nieprzypadkowe hasło z góry. Jeśli chcesz dołączyć a=i linię z przodu, to trzy kolejne znaki, ale pozwala ci to powtarzać. Oczywiście możesz również zastąpić wszystkie nowe wiersze, ;aby mieć linijkę, którą możesz wykonywać tak często, jak chcesz.

Ponadto powinno być ustawione LC_ALL=Cczy nie ustawić jakieś zmienne środowiskowe locale specyficzne ( LANGa LC_CTYPEzwłaszcza), ponieważ zakresy znaków zależą kolejność sortowania jest równa kolejności ASCII.

/dev/urandomjest źródłem losowych bajtów. !-~to zakres wszystkich dopuszczalnych znaków, jak określono w pytaniu. tr -dcusuwa wszystkie znaki niewymienione w następnym argumencie. headbierze 15 pozostałych postaci. grepsprawdza, czy każdy z wymaganych rodzajów występuje przynajmniej raz. Jego dane wejściowe składają się z czterech kopii kandydata, więc kolejność symboli nie ma znaczenia, dlatego wszystkie możliwe hasła mają szansę zostać wybranymi. Opcja -qgrep tłumi wyjście.

Z nieznanych przyczyn /dev/randomzamiast na /dev/urandomwieki. Wygląda na to, że entropia dość szybko się wyczerpała. Jeśli cdw /dev, można uniknąć jeszcze kilka bajtów, ale czuje się trochę jak oszustwo.

Python 2 (138)

import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
 a=''.join(random.sample(map(chr,range(33,127))*15,15))
print a

Aby kod był czytelny, dodałem nowy wiersz i wcięcie po pętli, które nie są konieczne i których nie policzyłem.

Jest to zasadniczo ten sam pomysł, co w wersji bash. Tutaj jest losowe źródło random.sample, które nie będzie powtarzać elementów. Aby temu zaradzić, używamy 15 kopii listy dozwolonych liter. W ten sposób każda kombinacja może nadal występować, chociaż te z powtarzającymi się literami będą występować rzadziej. Ale decyduję się uznać to za cechę, a nie za błąd, ponieważ pytanie nie wymagało jednakowego prawdopodobieństwa dla wszystkich permutacji, tylko możliwość.

Python 3 (145)

import re,random
a=''
while not re.search('[A-Z].*[a-z].*[0-9].*[\W_]',a*4):
 a=''.join(random.sample(list(map(chr,range(33,127)))*15,15))
print(a)

Jeden nowy wiersz i jedno tiret ponownie nie są liczone. Oprócz pewnych narzutów składni specyficznych dla Python-3 jest to to samo rozwiązanie, co dla Python 2.

JavaScript (161)

a=[];for(i=33;i<127;)a.push(s=String.fromCharCode(i++));
while(!/[A-Z].*[a-z].*[0-9].*[\W_]/.test(s+s+s+s))
for(i=0,s="";i<15;++i)s+=a[Math.random()*94|0];alert(s)

Dodałem nowe wiersze dla czytelności, ale ich nie policzyłem.

R (114)

s<-""
while(!grepl("[A-Z].*[a-z].*[0-9].*(\\W|_)",paste(rep(s,4),collapse="")))
 s<-intToUtf8(sample(33:126,15,T))
s

Dodano przerwanie linii i wcięcie wewnątrz pętli, ale nie zostało zliczone. Jeśli masz na to ochotę, możesz ponownie przenieść to do pojedynczej ;linii.


Ha! Właśnie miałem wskazać, że mogłeś użyć greplw swoim kodzie R. Gdybym tylko pomyślał o powtórzeniu hasła testowego cztery razy, abyś mógł wykonać wszystkie kontrole za jednym razem. I wiesz, gdybym tylko pomyślał samplei intToUtf8. Musisz jednak dodać replace=TRUE(lub bardziej zwięźle, wystarczy dodać ,T) do przykładowej metody, aby upewnić się, że otrzymujesz wszystkie możliwe hasła.
— AmeliaBR

@AmeliaBR: Masz rację, naprawiłeś ten replace=Tbłąd, dziękuję za zwrócenie na to uwagi. Znalezienie intToUtf8zgadując prawdopodobne nazwiska z zakończeniem zakładce zajęło mi sporo czasu; Wiedziałem, że taka funkcja musi istnieć, ale chrnie używano bardziej popularnych nazw takich jak i tak dalej.
— MvG

@MvG: Nie rozumiem, dlaczego Twój kod Python w ogóle się kończy. Dlaczego tego potrzebujesz *4? Myślałem, że twoje wyrażenie regularne będzie pasować do dowolnego łańcucha, w tej reklamie najpierw jedna wielka litera, potem cokolwiek, a potem jedna mała litera, niż cokolwiek ... co pomyliłem?
— Martin Thoma,

@moose: Jak już zauważyłeś, moje wyrażenie regularne sprawdza wymagane kategorie w określonej kolejności. Ale łącząc cztery kopie aktualnego kandydata, mogę upewnić się, że kolejność nie ma już znaczenia: nawet jeśli moje hasło to symbole, cyfry, małe litery i wielkie litery, to nadal będzie pasować. Jedynym sposobem, w jaki dopasowanie może się nie powieść, jest całkowite pominięcie kategorii. Zauważ też, że re.searchnie re.match, więc wyrażenie regularne może pasować w dowolnym miejscu w haśle kandydata. Czy to wyjaśnia, dlaczego ostatecznie wygasa?
— MvG

Ach, nie zauważyłem, że używasz re.searchzamiast re.match. To wyjaśnia to. Ale nadal uważam, że nie potrzebujesz *4. Dziękuję za wyjaśnienie (+1)
— Martin Thoma

7

C # ( 123 - 139 103 - 127 znaków zagęszczonych):

Korzystanie z idealnie odpowiedniej metody ramowej w System.Web.dll:

class P
{
    static void Main()
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, 1));
    }
}

Zagęszczony:

class P{static void Main()
{Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15,1));}}

Przykład:

b+m2ae0K:{dz7:A

Możesz też pobrać wartość drugiego parametru ( int numberOfNonAlphanumericCharacters) z wiersza poleceń:

class P
{
    static void Main(string[] a)
    {
        Console.WriteLine(System.Web.Security.Membership.GeneratePassword(15, int.Parse(a[0])));
    }
}

3
GeneratePasswordnie obsługuje pełnego zestawu symboli określonych w pytaniu. Nie znalazłem też żadnych gwarancji co do minimalnej liczby wystąpień każdej kategorii postaci.
— MvG

2
Możesz skompaktować dalej, używając class Pi string[] a.
— d3dave

@MvG, to interesujące. Wygląda na to, że wyklucza każdy symbol powszechnie używany do pisania znaków akcentowanych w językach takich jak francuski. Prawdopodobnie sprytny ruch. Wystarczy zmienić język klawiatury, aby uzupełnić hasło.
— Hand-E-Food

5

R (301 322 znaków)

Korekta zapomniała sprawdzić cyfry.

a='abcdefghijklmnopqrstuvwxyz';
f=as.factor(strsplit(paste(a,toupper(a),
    sep="0123456789`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./"),"")[[1]]);
g=gsub("(.):","\\1",levels(q:q:q:q:q:q:q:q:q:q:q:q:q:q:q));
repeat{p=g[runif(1)*length(g)]; 
    if(grepl("[A-Z]",p)&&grepl("[a-z]",p)&&grepl("[0-9]",p)&&grepl("[^A-Za-z0-9]",p))break;};
print(p);

(białe znaki dodano tylko dla jasności).

Generuje wszystkie możliwe 15-znakowe kombinacje 94 znaków. Następnie losowo wybiera jeden, dopóki nie spełni kryteriów.

Magia tkwi w q:qoperacji, która generuje nowy typ danych czynników, czyli interakcję wszystkich czynników z pierwszej qlisty ze wszystkimi czynnikami z drugiej listy , przy czym każda możliwa kombinacja tych dwóch list znajduje się na liście „ poziomy ”tego czynnika. Wejdź w interakcję z 15 kopiami listy dozwolonych postaci, a otrzymasz (94 ^ 15) możliwych poziomów.

Nie próbuj tego w domu. Kod zajmuje kilka sekund, aby dowiedzieć się o wszystkich 3-znakowych kombinacjach. Naprawdę nie wyobrażam sobie, ile czasu zajęłoby ustalenie wszystkich 15-znakowych kombinacji, jeśli komputerowi nie zabrakło pamięci w międzyczasie. Kiedy uruchomiłem gotowy skrypt (hasło składające się z trzech znaków), aby to sprawdzić, pierwsze hasło, które wypluło, to „oO =”, co myślę o podsumowaniu reakcji na ten kod.


@MvG ma skrypt R, który jest zarówno bardziej praktyczny, jak i znacznie krótszy, choć o wiele mniej niesamowity: codegolf.stackexchange.com/a/17700/12413
— AmeliaBR

Niemniej jednak podoba mi się twój pomysł. Wiele fragmentów kodu do golfa, które widziałem, pozwoliło na to, by określone funkcje języka wykonały ciężką pracę. A twój kod z pewnością robi to dla R, z tymi interakcjami.
— MvG

4

Mathematica 170

r=RandomSample;f[i_]:=(FromCharacterCode/@Range@@i);
{t,A,a,n}=f/@{{33,126},{65,90},{97,122},{48,57}};
s=Complement[t,A,a,n];
""<>r[Join[RandomChoice/@{A,a,n,s},r[t,11]],15]

Przykłady

"<]} Pg3 / e? 3 + Z ~ Oz"
"X / 8jWe @ f (_x5P: ="
"2wz2VQhtJC? * R7 ^"


4

Python 2.7 (182)

import random as r,string as s
z=r.sample
j=list(z(s.ascii_lowercase,12)+z(s.ascii_uppercase,1)+z(s.digits,1)+z('`~!@#$%^&*()_+-={}|[]\\:";\'<>?,./',1))
r.shuffle(j)
print ''.join(j)

Możesz uzyskać 9 cyfr mniej, usuwając złączenie, ponieważ nie jest to wymagane w opisie problemu. Kolejne 2 mniej, usuwając spacje.
— Martin Thoma,

@moose Wyjąłem spacje tuż przed tym, jak skomentowałeś :-) Wydaje mi się, że coś takiego joinmusi być: Czy użytkownicy powinni rozumieć składnię listy python z wyjścia ['q', 'u', ...]:?
— Jonathon Reinhart

1
W ogóle pomyślałem o usunięciu wydruku. Gdy wielkość w bajtach jest ważna, mogą żyć w czasie karty dziurkacza. W ten sposób mogą być w stanie odczytać pamięć ... tylko patrząc na nią. Albo są „prawdziwymi programistami”: xkcd.com/378
— Martin Thoma,

1
Jeśli poprawnie czytam kod, nie spełnia to wszystkich wymagań dotyczących permutacji , zawsze będzie zawierał 12 małych liter, co uniemożliwia hasła dla więcej niż jednej innej grupy (jak aA$bc1111111111).
— IQAndreas,

1
W obronie Johnathona myślę, że reguła permutacji została dodana 5 minut po swoim stanowisku.
— Hand-E-Food

4

Golfscript (60)

Ponieważ obl. brakuje skryptu golfowego i i tak potrzebuję praktyki :)

[48 10{rand}:r~+65 26r+97 26r+33 15r+11,{;32 96r+}%~]{r}$''+

Po prostu buduje tablicę z 4 wymaganymi + 11 losowymi postaciami i sortuje w losowej kolejności.


+1 dla {r}$. To dość brudny sposób na przetasowanie listy - podoba mi się! ;-)
— Ilmari Karonen

... jednak nie sądzę, że może to kiedykolwiek wygenerować np 0Aa~~~~~~~~~~~~. :-(
— Ilmari Karonen

3

JavaScript 258 240 233 225

R=Math.random;a=b=>b[b.length*R()|0];for(x=[a(l="abcdefghijklmnopqrstuvwxyz"),a(u=l.toUpperCase()),a(n="0123456789"),a(s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./")];15>x.length;x.push(a(l+u+n+s)));alert(x.sort(y=>.5-R()).join(""))

Stosując regułę, w której:

function(x){return x*x}można ponownie zapisać jako function(x)x*x. Wydaje się, że działa tylko w przypadku funkcji zwracających wartość.

Następna iteracja, zmniejszona x.sort(function().5-R())dox.sort(y=>.5-R())

Kolejna iteracja, zmniejszona dodatkowo dzięki grubej notacji strzałek, która niestety działa tylko w przeglądarce Firefox 22 i nowszych.


Ładne zagęszczanie! : D
— IQAndreas

2

JavaScript (kompaktowane 269 znaków)

Dla jasności jest to kod, zanim go skompresowałem JS-Fiddle :

var lowerLetters = "abcdefghijklmnopqrstuvwxyz";
var upperLetters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
var numbers = "0123456789";
var symbols = "`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
var allCharacters = lowerLetters + upperLetters + numbers + symbols;

String.prototype.randomChar = function() {
    return this[Math.floor(this.length * Math.random())];
}

var minLength = 15;
var result = [];

// Start off by picking one random character from each group
result.push(lowerLetters.randomChar());
result.push(upperLetters.randomChar());
result.push(numbers.randomChar());
result.push(symbols.randomChar());
// Next, pick a random character from all groups until the desired length is met
while(result.length < minLength) {
    result.push(allCharacters.randomChar());
}
result.shuffle(); // Finally, shuffle the items (custom function; doesn't actually exist in JavaScript, but is very easy to add) -> http://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array
result.join("");

Tutaj jest spakowany do 269 znaków ( JS-Fiddle tego ):

l="abcdefghijklmnopqrstuvwxyz";
u=l.toUpperCase();
n="0123456789";
s="`~!@#$%^&*()_+-={}|[]\\:\";'<>?,./";
R=Math.random;

function r(t){
    return t[~~(t.length*R())]
}

for(x=[r(l),r(u),r(n),r(s)];x.length<15;x.push(r(l+u+n+s)));
x.sort(function(){return .5-R()});
alert(x.join(""));

Ponieważ kończę linie średnikami, wszystkie usuwalne białe znaki zostały zignorowane do zliczania znaków, ale pozostawiono je dla przejrzystości.
— IQAndreas,

Co masz na myśli mówiąc, shuffle()że jesteś „funkcją niestandardową”? Czy to część kodu JavaScript lub kodu, który musiałbyś napisać sam?
— Hand-E-Food

@ Hand-E-Food Miałem na myśli, że nie jest on wbudowany w JavaScript, a ponieważ każdy programista tutaj powinien wiedzieć, jak tasować tablicę, czułem, że włączenie funkcji w kodzie jest niepotrzebne. Jest on jednak dostępny w JS-Fiddle (linia 16).
— IQAndreas

1
Chodzi mi o to, że liczy się do twojej liczby bajtów. Ale widzę, że zaimplementowałeś go w wersji kompaktowej, więc proszę zignoruj ​​mnie. :-)
— Hand-E-Food

2

Clojure (63):

(->> (map char (range 33 127)) (shuffle) (take 15) (apply str))

Ale należy je poprawić, aby zawierały co najmniej 1 znak z każdej kategorii (górny, dolny, cyfra, symbol).


2

Na serwerze SQL

declare @a nvarchar(28)
set @a='abcdefghijklmnopqrstuvwxyz'
declare @b nvarchar(max)
set @b='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
declare @c nvarchar(max)
set @c='0123456789'
declare @d nvarchar(max)
set @d='~!@#$%^&*()_+-={}|[]\:";<>?,./'

select left(substring(@a,cast(rand()*10 as int),3)+substring(@b,cast(rand()*10 as int),6)+substring(@c,cast(rand()*10 as int),3)+substring(@d,cast(rand()*10 as int),5),15)

Zobacz to w akcji - 1

zobacz to w Akcji - 2


1
Mam problem z podążaniem za ostatnim wierszem, ale kod nie wydaje się spełniać wszystkich wymagań dotyczących permutacji .
— IQAndreas

Twój kod nigdy nie wygeneruje hasła zaczynającego się od ~0Aa, ani żadnego hasła, po którym bnastępuje a.
— Heinzi

@Heinzi: tak, zgadzam się, że wszystkie wymagane permutacje nie są brane pod uwagę, po prostu wyświetla 15 znaków.. znaków losowo wybranych z ... z, A..Z, 0..9,! ... + :(. ..
— vhadalgi

2

SAS (191)

%macro c(p);compress(p,,"&p")ne''%mend;data x;length p$15;do x=1by 1;do t=1to 15;substr(p,t,1)=byte(ranuni(7)*94+33);end;if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do;put p;stop;end;end;run;

*TQP,(f=h10*)S=

Skomentowane / wcięte:

%macro c(p); /*compress removes or keeps certain classes of characters*/
  compress(p,,"&p")ne''
%mend;
data x;
length p$15;
do x=1by 1;
    do t=1to 15;
        substr(p,t,1)=byte(ranuni(7)*94+33); /*give it a 33-126, byte discards the noninteger portion rounding down*/
    end;
    if %c(kd)and %c(kl)and %c(ku)and %c(ad)then do; /*k=keep d=digit l/u=lower/upper ad=remove digits and alphas*/
        put p;
        stop;  /*met our requirement, head home*/
    end;
end;
run;

2

PowerShell: 119

Kod Gofled

for(;!($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')){$x='';1..15|%{$x+=[char](33..126|random)}}$x

Nie grał w golfa i skomentował

# Start for loop definition.
for(
    # Skip variable initialization, start definition of run condition.
    ;
    # Loop runs if $x does not meet complexity requirements.
    # Length requirement is not tested here because it is enforced by the generator later.
    # Much thanks to @VasiliSyrakis for the RegEx help.
    !($x-cmatch'.*(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!-/:-@[-`{-~]).*')
)
{
    # Reset $x in case the script block has already run.
    $x='';
    # Use ForEach-Object, via the % alias, to run a loop 15 times.
    1..15|%{
        # Append a random ASCII character from 33-126 to $x.
        # Note: Use get-random instead of random for faster performance.
        $x+=[char](33..126|random)
    }
}
# Display $x.
$x
# Variable cleanup - not included in golfed code.
rv x

Myślę, że ten regex może uczynić go jeszcze trochę krótszym: ^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$możesz zrobić z nim jedno dopasowanie, które będzie pasować tylko wtedy, gdy będzie jeden górny, dolny, cyfrowy, symbol.
— Vasili Syrakis

@VasiliSyrakis Ok, może będziesz musiał przez to trochę mnie poprowadzić. Rozpocznij czat, jeśli uważasz, że zajmie to trochę czasu. Kilka rzeczy, na których jestem zdezorientowany: 1.) Widzę zawarty tam numer 15. Czy to ma upewnić się, że ciąg ma dokładnie 15 znaków? Jeśli tak, można to pominąć, ponieważ skrypt w naturalny sposób generuje jedynie ciągi 15 znaków. 2.) Co masz na myśli mówiąc „będzie pasować tylko wtedy, gdy będzie jeden górny, dolny, cyfrowy, symbol”? Czy to oznacza, że ​​będzie pasować tylko wtedy, gdy będzie dokładnie jeden lub przynajmniej jeden z nich? Pierwszy zepsuje wszystko.
— Iszi

Ponadto, czy Twój RegEx ignoruje kolejność znaków? Na przykład, jeśli obniżone, aby dopasować ciągi 4 znaków, czy oba 1aZ%i (p3Rpasują? Miałem trudności ze znalezieniem sposobów na zrobienie tego online.
— Iszi

Przetestowałem nowy RegEx pod kątem danych wyjściowych z mojego bieżącego skryptu. Nie wydaje się to całkiem wiarygodne. Kod: $x-cmatch'^.*(?=.{15,})(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!#$%&? "]).*$'Dobre mecze: C>suD1?hTwbDx(z j%4O]HyeG|u[U$5 O/rGeD0$hJk=GO/Nieudane mecze: 3evthX3_X^nBrR` .nA ~ uYzrR4YV-r.u-IjZE48ntQ;HxV
— Iszi

Jak otworzyć pokój czatu?
— Wasilij Syrakis

1

Python 2.7 (149)

from random import*
''.join(map(lambda x:chr(randint(*(x[1]or(32,126)))),sorted(map(None,sample(range(15),15),((48,57),(65,90),(97,122),(33,47))))))

Napisane w bardziej czytelny (i nie wykonywalny) sposób;

from random import *
''.join(                                          # Concatenate characters to string
  map(                                            # Map all characters using below lambda
    lambda x:chr(randint(*(x[1] or (32, 126)))),  # Map a single range to a random character
                                                  # within a specific range if supplied,
                                                  # otherwise the default "all" range.
    sorted(                                       # After distributing ranges, sort
      map(None,                                   # zip_longest alternative, distributes the
                                                  # required ranges over 4 random positions
        sample(range(15), 15),                    # 0-14 in random order
        ((48, 57), (65, 90), (97, 122), (33, 47)) # The 4 required ranges
      )
    )
  )
)

Dość prosta i zaskakująco niewiele dłuższa niż wersja „generuj, spróbuj ponownie po porażce”.


Czy na pewno może to wygenerować wszystkie kwalifikujące się hasła, w tym np. 0Aa~~~~~~~~~~~~? (Uwaga '~' == chr(126).)
— Ilmari Karonen

1

PSQL (189)

Wydaje się, że PSQL jest trochę gadatliwy ... :)

SELECT ARRAY_TO_STRING(ARRAY_AGG(CHR((TRUNC((b-a)*RANDOM()+a))::int)ORDER BY RANDOM()),'')FROM(SELECT 32 a,127 b FROM generate_series(1,11)UNION ALL VALUES(48,58),(65,91),(97,123),(33,48))a

Demo SQLfiddle .


1

PHP, 235 225

Ten skrypt tasuje znaki, a następnie jest sprawdzany przez RegEx, aby upewnić się, że hasło jest silne (lub zostało zregenerowane).

<?php
while(!preg_match('/^(?=.*[A-Z])(?=.*[^A-Za-z])(?=.*[0-9])(?=.*[a-z]).{15}$/',$p)){ $p = substr(str_shuffle('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789`~!@#$%^&*()_+-={}|[]\:";\'<>?,./'),0,15); }
echo $p;

1
Sprytne, ale nie zezwalają na powielanie znaków.
— Hand-E-Food

1
Zamiast tego while(true) ... if (condition) breakmożesz użyćwhile (!condition)
— exussum

1

JavaScript (209)

r=Math.random;function t(x,y){return String.fromCharCode(Math.floor(y*r()+x))};x=[t(33,14),t(48,10),t(65,26),t(97,26)];for(i=0;i<11;i++)x.push(t(32,95));console.log(x.sort(function(){return r()-0.5}).join(''))

Na wpół nieprzygotowany;

// Return a character in the range [x,x+y)
function t(x,y) { return String.fromCharCode(Math.floor(y*Math.random()+x)) }
// Prefill required ranges
x=[ t(33,14), t(48,10), t(65,26), t(97,26)]
// Push 11 totally random (valid) characters
for(i=0; i<11; i++)
  x.push(t(32,95))
// Shuffle and output as string
console.log(x.sort(function(){return Math.random()-0.5})
             .join(''))

1

Perl, 92

Nie tak zwięzłe jak odpowiedź Ruby, ale jestem pewien, że czarodziej Perla może to jeszcze skrócić ... Nie jestem zbyt zadowolony ze wszystkich m//s na końcu, ale wydaje się, że działa i powinien spełniać warunki, aby w końcu wygenerować wszystkie permutacje.

do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print

Przykładowe użycie:

perl -e 'do{$_=join"",map{(map{chr}33..127)[rand 94]}0..14}while!(/[A-Z]/&/[a-z]/&/\d/&/[\W_]/);print'

Edytowane, aby naprawić sprawdzanie poprawności i zmienić [[:punct:]]na [\W_]komentarze po MvG.


1
Część generująca jest ładna, ale twoje kryterium wyboru w stanie pętli jest po prostu błędne: np. Hasło aaaaaaaaaaaaaaspowoduje, że pętla się zakończy. Powinieneś przetestować kryteria przy użyciu nieprzypadkowych haseł, aby upewnić się, że robią to, co chcesz.
— MvG

Rzeczywiście masz rację, naprawiłem to i zapisałem kilka bajtów! Dzięki!
— Dom Hastings

1
Jesteś tego pewien [[:punct:]]? Chyba wolałbym , which is shorter and of which I'm even more sure that it is correct, at least combined with your zasięg „[\ W_] 33..127”.
— MvG

Dobrze, myślę, że martwiłem się , że \Wnie uwzględniono _, ale masz absolutną rację, nie jest to konieczne: gist.github.com/anonymous/8301237 . Dziękuję Ci!
— Dom Hastings

1

Java 7 ( 270 234 znaków)

Ta sama zasada jest używana przez @assylias z java 8 (generuj losowe hasła do prawidłowego hasła). Jednak zamiast używać lambdas, hasło jest generowane przez iterację tablicy char i sprawdzane przez dopasowanie wyrażenia regularnego.

class A {
  public static void main(String [] a) {
    byte[] b = new byte[15];
    String s;
    do {
      new java.util.Random().nextBytes(b);
      s = new String(b);
    } while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));
    System.out.println(s);
  }
}

Kod minimalny:

class A {public static void main(String[] a){byte[] b=new byte[15];String s;do{new java.util.Random().nextBytes(b);s=new String(b);}while(!s.matches("(?=.*?[a-z])(?=.*?[A-Z])(?=.*?\\d)(?=.*?[!-/:-@\\[-`]).*"));System.out.println(s);}}

1

PowerShell


Wersja One Liner (143 bajty)

sal g random;1..11|%{$P+=[char](33..126|g)};(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)};$P

Wersja mini (146 bajtów)

sal g random
1..11|%{$P+=[char](33..126|g)}
(65..90|g),(97..122|g),(48..57|g),(33..47+58..64+123..126|g)|%{$P=$P.insert((1..11|g),[char]$_)}
$P

Wersja do odczytu (860 bajtów)

function pwgen {

    # Fulfill Upper,Lower,Digit,Symbol requirement by predefining ASCII ranges for each
    # These will be added into the string beginning at line 24

    [array[]]$symbolrange = (33..47),(58..64),(123..126)

    [char]$upper = (get-random (65..90))
    [char]$lower = (get-random (97..122))
    [char]$digit = (get-random (48..57))
    [char]$symbol = $symbolrange | get-random

    [char[]]$requirement = $upper + $lower + $digit + $symbol

    # Create the first 11 characters using any ASCII character between 32 - 126

    foreach ($number in (1..11)) {
        [string]$pass += [char](get-random (33..126))
    }

    # Insert each requirement character at a random position in the string

    foreach ($char in $requirement) {
        [string]$pass = $pass.insert((Get-Random (1..11)),$char)
    }

    return $pass
}

Podziękowania dla Iszi za różne wskazówki dotyczące skrócenia kodu.


1
Nie obejmuje to wszystkich permutacji. Jako przykład abcd1234ABCD{|}~nigdy nie pojawi się, ponieważ $symbolzmusza co najmniej jeden z symboli do umieszczenia między ASCII 33 a 47.
— Hand-E-Food

Cholera! Czy musisz wskazać moje lenistwo !? Żartuję ... Zredagowałem to teraz. Zmusiłem też każdy znak „wymagania” do osobnego indeksu w ciągu, zamiast zlepiać cztery razem pod tym samym indeksem. Teraz gdybym tylko mógł to skrócić ...
— Wasilij Syrakis

Czy jest jakiś powód, dla którego nie możesz ogolić jeszcze kilku postaci, skracając się $SRdo $Q?
— Iszi

Powinieneś także być w stanie wyciąć takie rzeczy, jak „ foreach”, (g(65..90))aby 65..90|g'. And change the wypowiadać instrukcje do foreach-objectpętli za pomocą %aliasu. Przykład: foreach($N in (1..11)){... }powinno być wykonalne jak 1..11|%{... }. Jestem pewien, że istnieją inne optymalizacje, które są możliwe, ale tak naprawdę mam zupełnie inną implementację, którą zamierzam wypróbować później.
— Iszi

Fajne wskazówki :) Skróciłem go do 213 bajtów, jeśli wyjmę zwrot karetki i zastąpię średnikami.
— Vasili Syrakis

1

Współczynnik, 196 znaków

Ten sam algorytm jak MvG i łoś. Nie jest najkrótszy, ale powinien spełniać wszystkie (obecne) kryteria w pytaniu:

USING: io kernel math pcre random sequences sequences.repeating ;
[ 15 94 random-integers [ 33 + ] "" map-as dup 60 cycle
"[A-Z].*[a-z].*[0-9].*[\\W_]" findall { } = not ] [ drop ] until print

Być może błędnie interpretuje wyrażenie regularne, ale myślę, że coś takiego ~{}|1234abcdABCDzawiedzie wyrażenie regularne.
— Hand-E-Food

1
Nie, to zadziała:"~{}|1234abcdABCD" 60 cycle "[A-Z].*[a-z].*[0-9].*[\\W_]" findall empty? not => t
— Björn Lindqvist

Wierzę ci na słowo. :-)
— Hand-E-Food

1

C - 154 znaków

char p[16],c,f,w;main(){srand(time());while(f^15){c=p[15]=f=0;while(c^15){w=33+rand()%94;f|=w
>96&&w<123?1:w>47&&w<59?2:w>64&&w<91?4:8;p[c++]=w;}}puts(p);}

Jak nienawidzę srand()? Pozwól mi policzyć drogi.


1

Haskell, 192

import System.Random
main=getStdGen>>= \g->(print.(take 15))$until((\x->all(any(`elem`x))[['a'..'z'],['A'..'Z'],['0'..'9'],['!'..'/']++":;<=>?@[\\]^_`{|}~"]).(take 15))tail$randomRs('"','~')g

Wydrukowany ciąg ma wokół siebie cudzysłowy i ucieka przed odwrotnym ukośnikiem i znakami cudzysłowu; jeśli to niedopuszczalne, printmożna je zastąpićputStrLn przez 3 kolejne bajty. Oto bardziej czytelna wersja:

import System.Random

main = do
    g <- getStdGen
    let chars = randomRs ('"', '~') g
    let password = take 15 $ until (hasChars.(take 15)) tail chars
    print password

hasChars :: String -> Bool
hasChars x = all (any (`elem` x)) $
    [ ['a'..'z']
    , ['A'..'Z']
    , ['0'..'9']
    , "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
    ]

Jest to dość proste, to po prostu tworzy nieskończoną / lazy listę losowych znaków ASCII w przedziale '!'do '~', a następnie rzuca się pierwszy element aż 15 pierwszych znaków mieć co najmniej jeden znak z każdej struny wymaganych znaków.


1

Excel VBA, 209 bajtów

For i = 1 To 15
x = x + Chr(Int(90 * Rnd + 33))
Next
p = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*(_|[^\w])).+$"
With New RegExp
.Pattern = p
Set m = .Execute(x)
If m.Count = 0 Then
MsgBox "redo"
Else
MsgBox x
End If
End With

Generuje losowo 15 znaków ASCII, dzięki czemu możliwe są wszystkie możliwe kombinacje. Następnie używa wzorca wyrażenia regularnego, aby sprawdzić, czy zawiera on przynajmniej jedno z każdego kryterium.

Jeśli tak, pojawi się hasło, jeśli nie, pojawi się „ponów”.

Podziękowania dla Barta Kiersa za wzór wyrażeń regularnych: https://stackoverflow.com/questions/1559751/regex-to-make-sure-that-the-string-contains-at-least-one-lower-case-char- górny


0

AutoHotkey 352

global o:={}
loop 4
o[c()]:=o(A_index-1)
loop 11
o[c()]:=o(m(r(),4))
loop 15
s.=o[A_index-1]
msgbox % s
r(){
Random,z
return z
}
m(z,r){
return mod(z,r)
}
c(){
while o[t:=m(r(),15)]!=""
j++
return t
}
o(f){
r0:=48,l0:=10,r1:=97,l1:=l2:=26,r2:=65
r := chr(r%f%+m(r(),l%f%))
if f=3
r:=Substr("``~!@#$%^&*()_+-={}|[]\:"";'<>?,./",m(r(),32)+1,1)
return r
}

Korzystanie - wystarczy uruchomić skrypt


0

Python (121 znaków)

Wykorzystuje fakt, że możesz pomnożyć listy w Pythonie [1,2,3] * 2 daje [1,2,3,1,2,3]. Importuje losowo. Liczby na liście pomnożone przez trzy są granicami między zakresami w tabeli ascii dla potrzebnych znaków, np. [65, 90] odwzorowuje na wielkie litery.

print "".join([random.choice([chr(i) for i in range(z[0],z[1])]) for z in [[33,48],[48,58],[58,65],[65,90],[90,123]]* 3])

1
„Musi być w stanie wygenerować wszystkie permutacje wszystkich dozwolonych znaków.”. Nie sądzę, żeby tak było, ponieważ zakresy są zawsze stosowane w tej samej kolejności ...?
— Joachim Isaksson

Masz rację, dziękuję. Rzeczywiście nie zauważyłem, że zakresy powinny być stosowane w losowej kolejności, powinny być tasowane, za chwilę to wyedytuję.
— Pawelmhm

To musi faktycznie zawierać się import randomw kodzie.
— Mego

0

PHP 5.5 (230 bajtów)

echo preg_replace_callback('/./', function ($a)
{
  return chr([rand(33, 126), rand(48, 57), rand(65, 90), rand(97, 122), ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);
}
, str_shuffle(str_pad('1234', 15, 0)));

Lub w jednym wierszu (211 bajtów)

echo preg_replace_callback('/./',function($a){return chr([rand(33,126),rand(48,57),rand(65,90),rand(97,122),ord(str_shuffle('`~!@#$%^&*()_+-={}|[]\:";\'<>?,./')[0])][$a[0]]);},str_shuffle(str_pad('1234',15,0)));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.