aboutsummaryrefslogtreecommitdiffstats
path: root/passcheck.py
diff options
context:
space:
mode:
authorMattias Andrée <maandree@operamail.com>2015-11-27 01:49:29 +0100
committerMattias Andrée <maandree@operamail.com>2015-11-27 01:49:29 +0100
commit41ec0c4a28f2c8899097a3d36f0f99ea5c09df4e (patch)
tree7e37a7da2e825c2ba7adcf0bbec106e6a2c5f096 /passcheck.py
parenttypo (diff)
downloadpasscheck-41ec0c4a28f2c8899097a3d36f0f99ea5c09df4e.tar.gz
passcheck-41ec0c4a28f2c8899097a3d36f0f99ea5c09df4e.tar.bz2
passcheck-41ec0c4a28f2c8899097a3d36f0f99ea5c09df4e.tar.xz
improve makefile add file structure
Signed-off-by: Mattias Andrée <maandree@operamail.com>
Diffstat (limited to 'passcheck.py')
-rwxr-xr-xpasscheck.py262
1 files changed, 0 insertions, 262 deletions
diff --git a/passcheck.py b/passcheck.py
deleted file mode 100755
index ab3f323..0000000
--- a/passcheck.py
+++ /dev/null
@@ -1,262 +0,0 @@
-#!/usr/bin/env python
-#
-# passcheck – passphrase strenght evaluator
-#
-# Copyright © 2013, 2015 Mattias Andrée (maandree@member.fsf.org)
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version, or under the terms of the New BSD
-# License as published by the Regents of the University of California.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU Affero General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-
-import sys
-import os
-
-
-def _class(char):
- char = ord(char)
- if ord('0') <= char <= ord('9'):
- return 1
- elif ord('a') <= char <= ord('z'):
- return 2
- elif ord('A') <= char <= ord('Z'):
- return 2.5
- elif char < (1 << 7):
- return 3
- elif char < (1 << 8):
- return 3.5
- elif char < (1 << 10):
- return 4
- elif char < (1 << 14):
- return 5
- elif char < (1 << 16):
- return 6
- elif char < (1 << 18):
- return 7
- elif char < (1 << 22):
- return 8
- elif char < (1 << 26):
- return 9
- else:
- return 10
-
-
-def distance(a, b):
- a, b = a.lower(), b.lower()
- if a == b:
- return 0
- L1 = '1234567890'
- L2 = 'qwertyuiop'
- L3 = 'asdfghjkl'
- L4 = 'zxcvbnm'
- keys = {}
- for x in range(len(L1)):
- keys[L1[x]] = (x, 0)
- for x in range(len(L2)):
- keys[L2[x]] = (x + 0.5, 1)
- for x in range(len(L3)):
- keys[L3[x]] = (x + 0.75, 2)
- for x in range(len(L4)):
- keys[L4[x]] = (x + 1, 3)
- for c in (a, b):
- if c not in keys:
- return 15
- return ((keys[a][0] - keys[b][0]) ** 2 + (keys[a][1] - keys[b][1]) ** 2) ** 0.5
-
-
-def search_cmp(haystack, needle):
- haystack = haystack + [10]
- h, n = 0, 0
- too_low = False
- too_high = False
- while True:
- while True:
- hh, nn = haystack[h], needle[n]
- if (hh == 10) or (nn == 10):
- if hh == nn:
- return 0
- break
- else:
- d = hh - nn
- if d != 0:
- if d < 0:
- too_low = True
- break
- else:
- return None if too_low else 1
- h, n = h + 1, n + 1
- h, n = h + haystack[h:].index(10) + 1, 0
- too_low = too_low or (hh == 10)
- too_high = too_high or (nn == 10)
- if h == len(haystack):
- return None if (too_low and too_high) else (-1 if too_low else 1)
-
-def pread_full(fd, bs, offset, output):
- got_total = 0
- while got_total < bs:
- got = list(os.pread(fd, bs - got_total, offset + got_total))
- if len(got) == 0:
- break
- got_total += len(got)
- output.extend(got)
-
-def search_file(fd, filesize, passphrase):
- blocksize = 4096
- minimum = 0
- maximum = filesize - 1
- passphrase = passphrase + [10]
- while minimum <= maximum:
- middle = (minimum + maximum) // 2
- middle -= middle % blocksize
- middle_low = None
- continues = 0
- data = []
- while True:
- pread_full(fd, blocksize, middle + continues * blocksize, data)
- if middle_low is None:
- middle_low = 0
- if middle > 0:
- try:
- middle_low = data.index(10)
- except ValueError:
- middle_low = None
- continue
- if middle + len(data) >= filesize:
- middle_high = len(data)
- else:
- middle_high = len(data) - 1
- while (middle_high > middle_low) and (data[middle_high] != 10):
- middle_high -= 1
- if middle_high <= middle_low:
- continue
- if middle > 0:
- middle_low += 1
- break
- v = search_cmp(data[middle_low : middle_high], passphrase)
- if v is None:
- return False
- elif v < 0:
- minimum = middle + middle_low + 1
- elif v > 0:
- maximum = middle + middle_high
- else:
- return True
- return False
-
-
-def evaluate(data):
- rc = 0
- last = None
- data = bytes(data).decode('utf-8', 'replace')
- used = {}
- classes = [0] * 12
- for c in data:
- r = _class(c)
- if c not in used:
- used[c] = 1
- else:
- used[c] += 1
- rc += r ** 2
- rc += 5 / used[c]
- if r >= 4:
- r += 2
- elif r > 3:
- r = 5
- elif r == 3:
- r = 4
- elif r > 2:
- r = 3
- classes[r - 1] += 1
- if last is not None:
- r = distance(c, last)
- rc += r ** 0.5
- last = c
- if rc >= 0:
- rc += 30
- (a, b, c, d) = classes[:4]
- if a + b + c + d == 0:
- rc += 30
- else:
- r = a ** 2 + b ** 2 + c ** 2 + d ** 2
- rc += 30 * len(data) / (r ** 0.5)
- return (rc + 0.5) // 1
-
-
-
-waste_ram = ('--waste-ram' in sys.argv[1:]) or ('-w' in sys.argv[1:])
-raw = ('--raw' in sys.argv[1:]) or ('-r' in sys.argv[1:])
-
-
-blacklist_files = []
-if waste_ram:
- try:
- with open('blacklist', 'rb') as file:
- blacklist = set(file.read().decode('utf-8', 'replace').split('\n'))
- except FileNotFoundError:
- sys.stderr.write('File "blacklist" from the git branch "large-files" is not present.\n');
- sys.exit(1)
-else:
- blacklist = set([])
- fd = os.open('blacklist', os.O_RDONLY)
- blacklist_files.append((fd, os.fstat(fd).st_size))
-for directory in ['/usr/share/dict/', '/usr/local/share/dict/']:
- dictionaries = None
- try:
- dictionaries = os.listdir(directory)
- except FileNotFoundError:
- pass
- if dictionaries is not None:
- for dictionary in dictionaries:
- if not os.path.isdir(directory + dictionary):
- with open(directory + dictionary, 'rb') as file:
- blacklist.update(set(file.read().decode('utf-8', 'replace').split('\n')))
-
-
-while True:
- line = []
- try:
- while True:
- c = sys.stdin.buffer.read(1)[0]
- if c == 10:
- break
- line.append(c)
- except:
- break
- passphrase = []
- if raw:
- passphrase = line
- else:
- escape = False
- for c in line:
- if escape:
- if (c == ord('~')) or (ord('a') <= c <= ord('z')) or (ord('A') <= c <= ord('Z')):
- escape = False
- elif c == ord('\033'):
- escape = True
- else:
- passphrase.append(c)
- rating = None
- if ''.join([chr(c) for c in passphrase]) in blacklist:
- rating = 0
- else:
- for fd, filesize in blacklist_files:
- if search_file(fd, filesize, passphrase):
- rating = 0
- break
- if rating is None:
- rating = evaluate(passphrase)
- sys.stdout.buffer.write(('%i \033[34m' % rating).encode('utf-8'))
- sys.stdout.buffer.write(bytes(line))
- sys.stdout.buffer.write('\033[00m\n'.encode('utf-8'))
- sys.stdout.buffer.flush()
-