mirror of
https://github.com/monero-project/monero-gui.git
synced 2025-01-10 20:02:04 +02:00
282 lines
9.6 KiB
C
282 lines
9.6 KiB
C
/**********************************************************************************
|
|
* Program to test the C implementation of the zxcvbn password strength estimator.
|
|
* Copyright (c) 2015, Tony Evans
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification, are
|
|
* permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list
|
|
* of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this
|
|
* list of conditions and the following disclaimer in the documentation and/or other
|
|
* materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software without specific
|
|
* prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
|
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
|
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
|
* DAMAGE.
|
|
*
|
|
**********************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/time.h>
|
|
#include <zxcvbn.h>
|
|
|
|
const char *UsrDict[] =
|
|
{
|
|
"Onename.Twoname@example.com", "Onename", "Twoname", "example.com", "example",
|
|
0
|
|
};
|
|
|
|
static void CalcPass(const char *Pwd, int Quiet)
|
|
{
|
|
double e;
|
|
if (!Quiet)
|
|
{
|
|
/* Output the details of how the entropy figure was calculated */
|
|
int Len, ChkLen;
|
|
struct timeval t1, t2;
|
|
ZxcMatch_t *Info, *p;
|
|
double m = 0.0;
|
|
|
|
gettimeofday(&t1, 0);
|
|
e = ZxcvbnMatch(Pwd, UsrDict, &Info);
|
|
gettimeofday(&t2, 0);
|
|
for(p = Info; p; p = p->Next)
|
|
m += p->Entrpy;
|
|
|
|
Len = strlen(Pwd);
|
|
m = e - m;
|
|
printf("Pass %s \tLength %d\tEntropy bits=%.3f log10=%.3f\tMulti-word extra bits=%.1f\n", Pwd, Len, e, e * 0.301029996, m);
|
|
p = Info;
|
|
ChkLen = 0;
|
|
while(p)
|
|
{
|
|
int n;
|
|
switch((int)p->Type)
|
|
{
|
|
case BRUTE_MATCH: printf(" Type: Bruteforce "); break;
|
|
case DICTIONARY_MATCH: printf(" Type: Dictionary "); break;
|
|
case DICT_LEET_MATCH: printf(" Type: Dict+Leet "); break;
|
|
case USER_MATCH: printf(" Type: User Words "); break;
|
|
case USER_LEET_MATCH: printf(" Type: User+Leet "); break;
|
|
case REPEATS_MATCH: printf(" Type: Repeated "); break;
|
|
case SEQUENCE_MATCH: printf(" Type: Sequence "); break;
|
|
case SPATIAL_MATCH: printf(" Type: Spatial "); break;
|
|
case DATE_MATCH: printf(" Type: Date "); break;
|
|
case BRUTE_MATCH+MULTIPLE_MATCH: printf(" Type: Bruteforce(Rep)"); break;
|
|
case DICTIONARY_MATCH+MULTIPLE_MATCH: printf(" Type: Dictionary(Rep)"); break;
|
|
case DICT_LEET_MATCH+MULTIPLE_MATCH: printf(" Type: Dict+Leet(Rep) "); break;
|
|
case USER_MATCH+MULTIPLE_MATCH: printf(" Type: User Words(Rep)"); break;
|
|
case USER_LEET_MATCH+MULTIPLE_MATCH: printf(" Type: User+Leet(Rep) "); break;
|
|
case REPEATS_MATCH+MULTIPLE_MATCH: printf(" Type: Repeated(Rep) "); break;
|
|
case SEQUENCE_MATCH+MULTIPLE_MATCH: printf(" Type: Sequence(Rep) "); break;
|
|
case SPATIAL_MATCH+MULTIPLE_MATCH: printf(" Type: Spatial(Rep) "); break;
|
|
case DATE_MATCH+MULTIPLE_MATCH: printf(" Type: Date(Rep) "); break;
|
|
|
|
default: printf(" Type: Unknown%d ", p->Type); break;
|
|
}
|
|
ChkLen += p->Length;
|
|
printf(" Length %d Entropy %6.3f (%.2f) ", p->Length, p->Entrpy, p->Entrpy * 0.301029996);
|
|
for(n = 0; n < p->Length; ++n, ++Pwd)
|
|
printf("%c", *Pwd);
|
|
printf("\n");
|
|
p = p->Next;
|
|
}
|
|
ZxcvbnFreeInfo(Info);
|
|
t2.tv_sec -= t1.tv_sec;
|
|
t2.tv_usec -= t1.tv_usec;
|
|
t2.tv_usec += t2.tv_sec * 1000000;
|
|
printf(" Calculation Time %.2fms\n", t2.tv_usec/1000.0);
|
|
if (ChkLen != Len)
|
|
printf("*** Password length (%d) != sum of length of parts (%d) ***\n", Len, ChkLen);
|
|
}
|
|
else
|
|
{
|
|
/* Only get the final entropy figure */
|
|
e = ZxcvbnMatch(Pwd, UsrDict, 0);
|
|
printf("Pass %s \tEntropy %.3f\n", Pwd, e);
|
|
}
|
|
}
|
|
|
|
int DoChecks(char *file)
|
|
{
|
|
char Line[500];
|
|
int y = 0;
|
|
int w = 0;
|
|
int r = 0;
|
|
FILE *f = fopen(file, "r");
|
|
if (f == NULL)
|
|
{
|
|
printf("Failed to open %s\n", file);
|
|
return 1;
|
|
}
|
|
memset(Line, 0, sizeof Line);
|
|
while(fgets(Line, sizeof Line - 4, f))
|
|
{
|
|
/* Line is password + whitespace + expected entropy */
|
|
char *Pwd, *s, *t;
|
|
double Ent, e, x;
|
|
unsigned int i;
|
|
++y;
|
|
for(i = 0; i < sizeof Line - 5; ++i)
|
|
{
|
|
if (!Line[i] || (Line[i] == '\n'))
|
|
break;
|
|
}
|
|
/* Skip blank lines or those starting with # */
|
|
if ((i < 3) || (Line[0] == '#'))
|
|
continue;
|
|
memset(Line + i, 0, 4);
|
|
Pwd = Line;
|
|
/* Skip leading whitespace */
|
|
while(*Pwd && (*Pwd <= ' '))
|
|
++Pwd;
|
|
|
|
/* Make password null termnated */
|
|
s = Pwd;
|
|
t = strchr(s, '\t');
|
|
if (t == NULL)
|
|
t = strstr(s, " ");
|
|
if (t == NULL)
|
|
{
|
|
printf("Bad test condition on line %d\n", y);
|
|
r = 1;
|
|
break;
|
|
}
|
|
*t++ = 0;
|
|
|
|
/* Skip whitespace before entropy value */
|
|
while(*t && (*t <= ' '))
|
|
++t;
|
|
if (!*t)
|
|
{
|
|
printf("Bad test condition on line %d\n", y);
|
|
r = 1;
|
|
break;
|
|
}
|
|
|
|
Ent = atof(t);
|
|
if ((Ent < 0.0) || (Ent > 1000.0))
|
|
{
|
|
printf("Bad entropy value on line %d\n", y);
|
|
r = 1;
|
|
break;
|
|
}
|
|
e = ZxcvbnMatch(Pwd, UsrDict, 0);
|
|
x = e / Ent;
|
|
/* More than 1% difference is a fail. */
|
|
if ((x > 1.01) || (x < 1.0/1.01))
|
|
{
|
|
printf("Line %2d Calculated entropy %5.2f, expected %5.2f <%s>\n", y, e, Ent, Pwd);
|
|
r = 1;
|
|
break;
|
|
}
|
|
++w;
|
|
}
|
|
fclose(f);
|
|
if (!r)
|
|
printf("Tested %d words\n", w);
|
|
return r;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
int i, Quiet, Checks, White;
|
|
Quiet = 0;
|
|
Checks = 0;
|
|
White = 0;
|
|
if (!ZxcvbnInit("zxcvbn.dict"))
|
|
{
|
|
printf("Failed to open dictionary file\n");
|
|
return 1;
|
|
}
|
|
if ((argc > 1) && (argv[1][0] == '-'))
|
|
{
|
|
if (!strcmp(argv[1], "-qs") || !strcmp(argv[1], "-sq"))
|
|
Quiet = White = 1;
|
|
if (!strcmp(argv[1], "-t"))
|
|
Checks = 1;
|
|
if (!strcmp(argv[1], "-q"))
|
|
Quiet = 1;
|
|
if (!strcmp(argv[1], "-s"))
|
|
White = 1;
|
|
if ((Checks + Quiet + White) == 0)
|
|
{
|
|
char *s = strrchr(argv[0], '/');
|
|
if (s == NULL)
|
|
s = argv[0];
|
|
else
|
|
++s;
|
|
printf( "Usage: %s [ -q | -qs ] [ pwd1 pwd2 ... ]\n"
|
|
" Output entropy of given passwords. If no passwords on command line read\n"
|
|
" them from stdin.\n"
|
|
" -q option stops password analysis details from being output.\n"
|
|
" -s Ignore anything from space on a line when reading from stdin.\n"
|
|
" %s -t file\n"
|
|
" Read the file and check for correct results.\n", s, s);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
if (Checks)
|
|
{
|
|
for(i = 2; i < argc; ++i)
|
|
{
|
|
Checks = DoChecks(argv[i]);
|
|
if (Checks)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
i = 1+Quiet;
|
|
if (i >= argc)
|
|
{
|
|
/* No test passwords on command line, so get them from stdin */
|
|
char Line[500];
|
|
while(fgets(Line, sizeof Line, stdin))
|
|
{
|
|
/* Drop the trailing newline character */
|
|
for(i = 0; i < (int)(sizeof Line - 1); ++i)
|
|
{
|
|
if (Line[i] < ' ')
|
|
{
|
|
Line[i] = 0;
|
|
break;
|
|
}
|
|
if (White && (Line[i] == ' '))
|
|
{
|
|
Line[i] = 0;
|
|
break;
|
|
}
|
|
}
|
|
if (Line[0])
|
|
CalcPass(Line, Quiet);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Do the test passwords on the command line */
|
|
for(; i < argc; ++i)
|
|
{
|
|
CalcPass(argv[i], Quiet);
|
|
}
|
|
}
|
|
ZxcvbnUnInit();
|
|
return 0;
|
|
}
|