52
52
/* Minimum number of characters in a incrementing/decrementing sequence match */
53
53
#define MIN_SEQUENCE_LEN 3
54
54
55
+ /* Maximum number of characters to perform full entropy calculation */
56
+ #ifndef ZXCVBN_DETAIL_LEN
57
+ #define ZXCVBN_DETAIL_LEN 100
58
+ #endif
59
+
55
60
/* Year range for data matching */
56
61
#define MIN_YEAR 1901
57
62
#define MAX_YEAR 2050
@@ -1574,15 +1579,20 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
1574
1579
ZxcMatch_t * Zp ;
1575
1580
Node_t * Np ;
1576
1581
double e ;
1577
- int Len = strlen (Pwd );
1582
+ int FullLen = strlen (Pwd );
1583
+ int Len = FullLen ;
1578
1584
const uint8_t * Passwd = (const uint8_t * )Pwd ;
1579
1585
uint8_t * RevPwd ;
1580
1586
/* 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 );
1583
1589
i = Cardinality (Passwd , Len );
1584
1590
e = log ((double )i );
1585
1591
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
+
1586
1596
/* Do matching for all parts of the password */
1587
1597
for (i = 0 ; i < Len ; ++ i )
1588
1598
{
@@ -1659,8 +1669,23 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
1659
1669
}
1660
1670
}
1661
1671
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
+ }
1662
1687
/* End node has infinite distance/entropy, start node has 0 distance */
1663
- Nodes [i ].Dist = DBL_MAX ;
1688
+ Nodes [Len ].Dist = DBL_MAX ;
1664
1689
Nodes [0 ].Dist = 0.0 ;
1665
1690
1666
1691
/* Reduce the paths using Dijkstra's algorithm */
@@ -1688,18 +1713,19 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
1688
1713
/* update if the new distance is smaller. */
1689
1714
for (Zp = Np -> Paths ; Zp ; Zp = Zp -> Next )
1690
1715
{
1691
- Node_t * Ep = Np + Zp -> Length ;
1716
+ Node_t * Ep ;
1692
1717
double d = e + Zp -> MltEnpy ;
1718
+ if (Zp -> Length >= 0 )
1719
+ Ep = Np + Zp -> Length ;
1720
+ else
1721
+ Ep = Np + 1 ;
1693
1722
if (!Ep -> Visit && (d < Ep -> Dist ))
1694
1723
{
1695
1724
/* Update as lower dist, also remember the 'from' node */
1696
1725
Ep -> Dist = d ;
1697
1726
Ep -> From = Zp ;
1698
1727
}
1699
1728
}
1700
- /* If we got to the end node stop early */
1701
- /*if (Nodes[Len].Dist < DBL_MAX/2.0) */
1702
- /* break; */
1703
1729
}
1704
1730
/* Make e hold entropy result and adjust to log base 2 */
1705
1731
e = Nodes [Len ].Dist / log (2.0 );
@@ -1724,6 +1750,8 @@ double ZxcvbnMatch(const char *Pwd, const char *UserDict[], ZxcMatch_t **Info)
1724
1750
/* Adjust the entropy to log to base 2 */
1725
1751
Xp -> Entrpy /= log (2.0 );
1726
1752
Xp -> MltEnpy /= log (2.0 );
1753
+ if (Xp -> Length < 0 )
1754
+ Xp -> Length = - Xp -> Length ;
1727
1755
1728
1756
/* Put previous part at head of info list */
1729
1757
Xp -> Next = * Info ;
0 commit comments