aboutsummaryrefslogtreecommitdiffhomepage
path: root/test.c
diff options
context:
space:
mode:
authortony <tsyrogit@users.noreply.github.com>2015-01-03 00:16:04 +0000
committertony <tsyrogit@users.noreply.github.com>2015-01-03 00:16:04 +0000
commit38a981df53d53cc96ef47e15d62b7c9f0151315f (patch)
tree7059c14f2e43d7c5d3cbb48ce5ec4004c6a752ca /test.c
parent572ce633e134e53bd6a72220613feb82a5ef0a16 (diff)
downloadzxcvbn-c-38a981df53d53cc96ef47e15d62b7c9f0151315f.tar.gz
Initial commit.
Diffstat (limited to 'test.c')
-rw-r--r--test.c259
1 files changed, 259 insertions, 0 deletions
diff --git a/test.c b/test.c
new file mode 100644
index 0000000..9d74ce5
--- /dev/null
+++ b/test.c
@@ -0,0 +1,259 @@
+/**********************************************************************************
+ * 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"
+
+/* For pre-compiled headers under windows */
+#ifdef _WIN32
+#include "stdafx.h"
+#endif
+
+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;
+
+ gettimeofday(&t1, 0);
+ e = ZxcvbnMatch(Pwd, UsrDict, &Info);
+ gettimeofday(&t2, 0);
+
+ Len = strlen(Pwd);
+ printf("Pass %s \tLength %d\tEntropy %.3f\n", Pwd, Len, e);
+ p = Info;
+ ChkLen = 0;
+ while(p)
+ {
+ int n;
+ switch(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;
+ default: printf(" Type: Unknown%d ", p->Type); break;
+ }
+ ChkLen += p->Length;
+ printf(" Length %d Entropy %6.3f ", p->Length, p->Entrpy);
+ 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;
+ Quiet = 0;
+ Checks = 0;
+ if (!ZxcvbnInit("zxcvbn.dict"))
+ {
+ printf("Failed to open dictionary file\n");
+ return 1;
+ }
+ if ((argc > 1) && (argv[1][0] == '-'))
+ {
+ Checks = !strcmp(argv[1], "-t");
+ Quiet = !strcmp(argv[1], "-q");
+ if ((Checks + Quiet) == 0)
+ {
+ char *s = strrchr(argv[0], '/');
+ if (s == NULL)
+ s = argv[0];
+ else
+ ++s;
+ printf( "Usage: %s [ -q ] [ 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 -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 (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;
+}