Skip to content

Commit 0745d23

Browse files
committed
Limit full entropy estimation to the first 100 characters of a password to limit
the processing time of very long passwords. Use a simple low entropy estimation for the remaining characters of a longer password.
1 parent 248b59f commit 0745d23

File tree

2 files changed

+37
-8
lines changed

2 files changed

+37
-8
lines changed

zxcvbn.c

+36-8
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@
5252
/* Minimum number of characters in a incrementing/decrementing sequence match */
5353
#define MIN_SEQUENCE_LEN 3
5454

55+
/* Maximum number of characters to perform full entropy calculation */
56+
#ifndef ZXCVBN_DETAIL_LEN
57+
#define ZXCVBN_DETAIL_LEN 100
58+
#endif
59+
5560
/* Year range for data matching */
5661
#define MIN_YEAR 1901
5762
#define MAX_YEAR 2050
@@ -1574,15 +1579,20 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
15741579
ZxcMatch_t *Zp;
15751580
Node_t *Np;
15761581
double e;
1577-
int Len = strlen(Pwd);
1582+
int FullLen = strlen(Pwd);
1583+
int Len = FullLen;
15781584
const uint8_t *Passwd = (const uint8_t *)Pwd;
15791585
uint8_t *RevPwd;
15801586
/* Create the paths */
1581-
Node_t *Nodes = MallocFn(Node_t, Len+1);
1582-
memset(Nodes, 0, (Len+1) * sizeof *Nodes);
1587+
Node_t *Nodes = MallocFn(Node_t, Len+2);
1588+
memset(Nodes, 0, (Len+2) * sizeof *Nodes);
15831589
i = Cardinality(Passwd, Len);
15841590
e = log((double)i);
15851591

1592+
/* Limit length used to full entropy estimation to prevent excessive calculation time */
1593+
if (Len > ZXCVBN_DETAIL_LEN)
1594+
Len = ZXCVBN_DETAIL_LEN;
1595+
15861596
/* Do matching for all parts of the password */
15871597
for(i = 0; i < Len; ++i)
15881598
{
@@ -1659,8 +1669,23 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
16591669
}
16601670
}
16611671
FreeFn(RevPwd);
1672+
if (FullLen > Len)
1673+
{
1674+
/* Only the first MAX_DETAIL_LEN characters are used for full entropy estimation, for */
1675+
/* very long passwords the remainding characters are treated as being a incrementing */
1676+
/* sequence. This will give a low (and safe) entropy value for them. */
1677+
Nodes[Len].Dist = DBL_MAX;
1678+
Zp = AllocMatch();
1679+
Zp->Type = LONG_PWD_MATCH;
1680+
Zp->Begin = Len;
1681+
/* Length is negative as only one extra node to represent many extra characters */
1682+
Zp->Length = Len - FullLen;
1683+
Zp->Entrpy = log(2 * (FullLen - Len));
1684+
AddResult(&(Nodes[i].Paths), Zp, FullLen - Len);
1685+
++Len;
1686+
}
16621687
/* End node has infinite distance/entropy, start node has 0 distance */
1663-
Nodes[i].Dist = DBL_MAX;
1688+
Nodes[Len].Dist = DBL_MAX;
16641689
Nodes[0].Dist = 0.0;
16651690

16661691
/* Reduce the paths using Dijkstra's algorithm */
@@ -1688,18 +1713,19 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
16881713
/* update if the new distance is smaller. */
16891714
for(Zp = Np->Paths; Zp; Zp = Zp->Next)
16901715
{
1691-
Node_t *Ep = Np + Zp->Length;
1716+
Node_t *Ep;
16921717
double d = e + Zp->MltEnpy;
1718+
if (Zp->Length >= 0)
1719+
Ep = Np + Zp->Length;
1720+
else
1721+
Ep = Np + 1;
16931722
if (!Ep->Visit && (d < Ep->Dist))
16941723
{
16951724
/* Update as lower dist, also remember the 'from' node */
16961725
Ep->Dist = d;
16971726
Ep->From = Zp;
16981727
}
16991728
}
1700-
/* If we got to the end node stop early */
1701-
/*if (Nodes[Len].Dist < DBL_MAX/2.0) */
1702-
/* break; */
17031729
}
17041730
/* Make e hold entropy result and adjust to log base 2 */
17051731
e = Nodes[Len].Dist / log(2.0);
@@ -1724,6 +1750,8 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
17241750
/* Adjust the entropy to log to base 2 */
17251751
Xp->Entrpy /= log(2.0);
17261752
Xp->MltEnpy /= log(2.0);
1753+
if (Xp->Length < 0)
1754+
Xp->Length = -Xp->Length;
17271755

17281756
/* Put previous part at head of info list */
17291757
Xp->Next = *Info;

zxcvbn.h

+1
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ typedef enum
6262
SPATIAL_MATCH, /* 8 */
6363
DATE_MATCH, /* 9 */
6464
YEAR_MATCH, /* 10 */
65+
LONG_PWD_MATCH, /* 11 */
6566
MULTIPLE_MATCH = 32 /* Added to above to indicate matching part has been repeated */
6667
} ZxcTypeMatch_t;
6768

0 commit comments

Comments
 (0)