Пример #1
0
 def test_performance_scalability(self):
     """
     Theory: If you run with 100 iterations, it should take 100
     times as long as running with 1 iteration.
     """
     n1, n2 = 100, 10000
     elapsed = lambda f: timeit.timeit(f, number=1)
     t1 = elapsed(lambda: pbkdf2("password", "salt", iterations=n1))
     t2 = elapsed(lambda: pbkdf2("password", "salt", iterations=n2))
     measured_scale_exponent = math.log(t2 / t1, n2 / n1)
     self.assertLess(measured_scale_exponent, 1.1)
Пример #2
0
    def test_locked_hashes(self):

        # Forcefully lock the context and flush everything related to
        # accounts
        self.hasher.update(secret=None,
                           thresholdlesskey=None,
                           is_unlocked=False)
        cache.clear()

        password1 = make_share('password1')  # get an account

        algorithm, sharenumber, iterations, salt, passhash = \
                password1.split('$',4)
        passhash = passhash.encode('ascii').strip()

        iterations = int(iterations)

        self.assertTrue('pph' == algorithm)
        self.assertTrue(sharenumber.startswith('-'))

        # now let's do a plain pbkdf2 hash and compare the results
        proposed_hash = pbkdf2('password1', salt, iterations, digest=sha256)
        proposed_hash = b64encode(proposed_hash)

        self.assertTrue(proposed_hash == passhash)
Пример #3
0
 def encode(self, password, salt, iterations=None):
     assert password is not None
     assert salt and '$' not in salt
     iterations = iterations or self.iterations
     hash = pbkdf2(password, salt, iterations, digest=self.digest)
     hash = base64.b64encode(hash).decode('ascii').strip()
     return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
Пример #4
0
def change_pw(request):
    if request.method == 'POST' and request.user.is_authenticated:
        if 'cipherKey' not in request.session:
            return redirect('verify_pw')
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)
            data = Passwords.objects.filter(user=request.user)
            _, _, salt, _ = user.password.split('$')
            pw = form.cleaned_data['new_password1']
            key = pbkdf2(pw, salt, 50000, 48)
            key, iv = key[16:], key[0:16]
            for obj in data:
                encryption_suite = AES.new(
                    bytes.fromhex(request.session.get('cipherKey')),
                    AES.MODE_CFB, bytes.fromhex(request.session.get('iv')))
                obj.pw = encryption_suite.decrypt(bytes.fromhex(
                    obj.pw)).decode('utf-8')
                new_encryption_suite = AES.new(key, AES.MODE_CFB, iv)
                obj.pw = new_encryption_suite.encrypt(
                    obj.pw.encode('utf-8')).hex()
                obj.save()
            logout(request)
            return redirect('login')
        else:
            return render(request, 'password/change_pw.html',
                          {'password_change_form': form})

    else:
        form = PasswordChangeForm(request.user)
        return render(request, 'password/change_pw.html',
                      {'password_change_form': form})
Пример #5
0
    def test_update_hash_threshold(self):

        # we will remove the $ because we are going to create the entry
        # artificially
        salt = get_random_string(6).strip('$')

        password = '******'
        iterations = 12000

        pbkdf2_encoded_password = pbkdf2(password,
                                         salt,
                                         iterations,
                                         digest=sha256)

        pbkdf2_encoded_password = b64encode(pbkdf2_encoded_password)

        polyhash, sharenumber = self.hasher.update_hash_threshold(
            pbkdf2_encoded_password)

        password_string = "{0}${1}${2}${3}${4}".format('pph', sharenumber,
                                                       iterations, salt,
                                                       polyhash)

        # TODO we should cehck whether they can provide partial verification
        self.assertTrue(check(password, password_string))
    def post(self, request):
        user_id = str(self.request.data.get('user_id', '')).strip()

        if not user_id:
            return Response({'error': 'Missing user_id'})

        try:
            login_user = User.objects.filter(id=user_id).get()
        except User.DoesNotExist:
            return Response({'error': 'Unknown user_id'})

        # Remove existing tokens on user
        RatatoskrAdminLoginToken.objects.filter(login_user_id=user_id).delete()

        # Create a new token
        token_str = RatatoskrAdminLoginToken.generate_token()
        salt = crypto.get_random_string()
        iterations = randint(10000, 10100)
        encrypted_token = crypto.pbkdf2(token_str, salt, iterations)

        RatatoskrAdminLoginToken.objects.create(
            token=encrypted_token,
            salt=salt,
            iterations=iterations,
            login_user=login_user,
            admin_user=request.user,
        )

        return Response({'token': token_str})
Пример #7
0
def get_revocation_key(user):
    """
    When the value returned by this method changes, this revocates tokens.

    It is derived from the hashed password so that changing the password
    revokes tokens.

    For one-time tokens, it also contains the last login datetime so that
    logging in revokes existing tokens.

    """
    data = ""
    if settings.INVALIDATE_ON_PASSWORD_CHANGE:
        data += user.password
    if settings.ONE_TIME:
        data += str(user.last_login)
    # The password is expected to be a secure hash but we hash it again
    # for additional safety. We default to MD5 to minimize the length of
    # the token. (Remember, if an attacker obtains the URL, he can already
    # log in. This isn't high security.)
    return crypto.pbkdf2(
        data,
        settings.SALT,
        settings.ITERATIONS,
        digest=settings.DIGEST,
    )
Пример #8
0
    def post(self, request):
        phone_number = str(self.request.data.get('phone_number', '')).strip()
        users = lookup_users_by_phone(phone_number)
        users += self.lookup_local_users_by_phone(phone_number)
        if not len(users):
            return Response({'error': 'not found'}, status=403)

        SMSAuthCode.objects.filter(phone_number=phone_number).delete()

        auth_code = SMSAuthCode.generate_code()
        salt = crypto.get_random_string()
        iterations = randint(10000, 10100)
        encrypted_code = crypto.pbkdf2(auth_code, salt, iterations)

        code = SMSAuthCode.objects.create(
            phone_number=phone_number,
            code=encrypted_code,
            salt=salt,
            iterations=iterations
        )
        for user in users:
            code.users.add(user)

        try:
            send_sms(phone_number, 'Din innloggingskode er: %s' % auth_code)
        except SMSGatewayDeliveryError:
            return Response({'error': 'unable to send sms'}, 503)
        except Exception:
            return Response({'error': 'server error'}, 503)

        return Response({'status': 'ok'})
    def save(self):

        invitation_code = self.cleaned_data['invitation_code']
        # make the invitation a invalid/spent.
        invite = UserRegisterCode.objects.get(
            code=str(invitation_code), used=False)

        new_user = User.objects.create_user(
            username=self.cleaned_data['username'],
            first_name=self.cleaned_data['first_name'],
            last_name=self.cleaned_data['last_name'],
            password=self.cleaned_data['password1'],
            email=self.cleaned_data['email'],
            is_active=False)

        UserProfile.objects.create(user=new_user,
                                   user_type="BEN",
                                   create_applications=False,
                                   )

        # TODO: Add Crosswalk Create.
        Crosswalk.objects.create(user=new_user,
                                 user_id_hash=binascii.hexlify(pbkdf2(self.cleaned_data['id_number'],
                                                                      settings.USER_ID_SALT,
                                                                      settings.USER_ID_ITERATIONS)).decode("ascii"))
        #
        group = Group.objects.get(name='BlueButton')
        new_user.groups.add(group)

        # Send a verification email
        create_activation_key(new_user)

        invite.used = True
        invite.save()
        return new_user
def encrypt_match_report(apps, schema_editor):
    db_alias = schema_editor.connection.alias
    MatchReport = apps.get_model('delivery', 'MatchReport')
    for match_report in MatchReport.objects.using(db_alias).all():
        match_report_content = MatchReportContent(
            identifier=match_report.identifier,
            perp_name=match_report.name,
            email=match_report.contact_email,
            phone=match_report.contact_phone,
            contact_name=match_report.contact_name,
            voicemail=match_report.contact_voicemail,
            notes=match_report.contact_notes)
        match_report.salt = get_random_string()
        stretched_identifier = pbkdf2(
            match_report.identifier,
            match_report.salt,
            settings.ORIGINAL_KEY_ITERATIONS,
            digest=hashlib.sha256)
        encrypted_match_report = security.pepper(
            security.encrypt_report(
                stretched_key=stretched_identifier,
                report_text=json.dumps(
                    match_report_content.__dict__)))
        match_report.encrypted = encrypted_match_report
        if match_report.seen:
            match_report.identifier = None
        match_report.save()
Пример #11
0
    def test_update_hash_thresholdless(self):

        # we will strip $ to avoid creating a threshold account by accident
        salt = get_random_string(6).strip('$')

        password = '******'
        iterations = 12000

        pbkdf2_encoded_password = pbkdf2(password,
                                         salt,
                                         iterations,
                                         digest=sha256)

        pbkdf2_encoded_password = b64encode(pbkdf2_encoded_password)

        password_normally = make_password(password, salt, hasher='pph')
        password_normally = password_normally.split('$', 4)[4]

        password_through_update = self.hasher.update_hash_thresholdless(
            pbkdf2_encoded_password)

        self.assertTrue(
            constant_time_compare(password_normally, password_through_update))

        # finally, try to log in with our updated password
        pass_string = "{0}${1}${2}${3}${4}".format('pph', 0, iterations, salt,
                                                   password_through_update)

        # TODO we should cehck whether they can provide partial verification
        self.assertTrue(check(password, pass_string))
Пример #12
0
    def parse_token(self, token):
        """
        Obtain a user from a signed token.

        """
        try:
            data = self.unsign(token)
        except signing.SignatureExpired:
            logger.debug("Expired token: %s", token)
            return
        except signing.BadSignature:
            logger.debug("Bad token: %s", token)
            return
        except Exception:
            logger.exception(
                "Valid signature but unexpected token - if you changed "
                "django-sesame settings, you must regenerate tokens")
            return
        user_pk, data = self.packer.unpack_pk(data)
        user = self.get_user(user_pk)
        if user is None:
            logger.debug("Unknown or inactive user: %s", user_pk)
            return
        h = crypto.pbkdf2(
            self.get_revocation_key(user),
            self.salt,
            self.iterations,
            digest=self.digest,
        )
        if not crypto.constant_time_compare(data, h):
            logger.debug("Invalid token: %s", token)
            return
        logger.debug("Valid token for user %s: %s", user, token)
        return user
Пример #13
0
    def parse_token(self, token):
        """
        Obtain a user from a signed token.

        """
        try:
            data = self.unsign(token)
        except signing.SignatureExpired:
            logger.debug("Expired token: %s", token)
            return
        except signing.BadSignature:
            logger.debug("Bad token: %s", token)
            return
        except Exception:
            logger.exception(
                "Valid signature but unexpected token - if you changed "
                "django-sesame settings, you must regenerate tokens"
            )
            return
        user_pk, data = self.packer.unpack_pk(data)
        user = self.get_user(user_pk)
        if user is None:
            logger.debug("Unknown or inactive user: %s", user_pk)
            return
        h = crypto.pbkdf2(
            self.get_revocation_key(user),
            self.salt,
            self.iterations,
            digest=self.digest,
        )
        if not crypto.constant_time_compare(data, h):
            logger.debug("Invalid token: %s", token)
            return
        logger.debug("Valid token for user %s: %s", user, token)
        return user
Пример #14
0
    def parse_token(self, token):
        """
        Obtain a user from a signed token.

        """
        try:
            data = self.unsign(token)
        except signing.SignatureExpired:
            logger.debug("Expired token: %s", token)
            return
        except signing.BadSignature:
            logger.debug("Bad token: %s", token)
            return
        user = self.get_user(*struct.unpack(str('!i'), data[:4]))
        if user is None:
            logger.debug("Unknown token: %s", token)
            return
        h = crypto.pbkdf2(user.password,
                          self.salt,
                          self.iterations,
                          digest=self.digest)
        if not crypto.constant_time_compare(data[4:], h):
            logger.debug("Invalid token: %s", token)
            return
        logger.debug("Valid token for user %s: %s", user, token)
        return user
Пример #15
0
    def parse_token(self, token):
        """
        Obtain a user from a signed token.

        """
        try:
            data = self.unsign(token)
        except signing.SignatureExpired:
            logger.debug("Expired token: %s", token)
            return
        except signing.BadSignature:
            logger.debug("Bad token: %s", token)
            return
        pk_packer = self.pk_packer()
        user_pk = pk_packer.parse(data[:pk_packer.PACKED_SIZE])
        user = self.get_user(user_pk)
        if user is None:
            logger.debug("Unknown token: %s", token)
            return
        h = crypto.pbkdf2(user.password,
                          self.salt,
                          self.iterations,
                          digest=self.digest)
        if not crypto.constant_time_compare(data[pk_packer.PACKED_SIZE:], h):
            logger.debug("Invalid token: %s", token)
            return
        logger.debug("Valid token for user %s: %s", user, token)
        return user
Пример #16
0
 def encode(self, password, salt, iterations=None):
     assert password is not None
     assert salt and '$' not in salt
     iterations = iterations or self.iterations
     hash = pbkdf2(password, salt, iterations, digest=self.digest)
     hash = base64.b64encode(hash).decode('ascii').strip()
     return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
Пример #17
0
def encrypt_match_report(apps, schema_editor):
    db_alias = schema_editor.connection.alias
    MatchReport = apps.get_model("delivery", "MatchReport")
    for match_report in MatchReport.objects.using(db_alias).all():
        match_report_content = MatchReportContent(
            identifier=match_report.identifier,
            perp_name=match_report.name,
            email=match_report.contact_email,
            phone=match_report.contact_phone,
            contact_name=match_report.contact_name,
            voicemail=match_report.contact_voicemail,
            notes=match_report.contact_notes,
        )
        match_report.salt = get_random_string()
        stretched_identifier = pbkdf2(
            match_report.identifier,
            match_report.salt,
            settings.ORIGINAL_KEY_ITERATIONS,
            digest=hashlib.sha256,
        )
        encrypted_match_report = security.pepper(
            security.encrypt_report(
                stretched_key=stretched_identifier,
                report_text=json.dumps(match_report_content.__dict__),
            ))
        match_report.encrypted = encrypted_match_report
        if match_report.seen:
            match_report.identifier = None
        match_report.save()
Пример #18
0
 def encode(self, password, salt, iterations=None):
     assert password
     assert salt and '$' not in salt
     if not iterations:
         iterations = self.iterations
     hash = pbkdf2(password, salt, iterations, digest=self.digest)
     hash = hash.encode('base64').strip()
     return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
Пример #19
0
def django_check_hash(password, hash):
    if not hash.startswith('pbkdf2_sha256'):
        raise ValueError('Invalid hash ' + hash)
    _type, iterations, salt, hashvalue = hash.split('$', 3)
    stored_hash = b64decode(hashvalue)

    given_hash = pbkdf2(password, salt, int(iterations))
    return constant_time_compare(given_hash, stored_hash)
Пример #20
0
    def check_password(self, raw_password):
        # Convert Play format to Django format
        iterations, salt, pbkdf2_hash = self.password.split(':')

        new_raw_hash = pbkdf2(raw_password, base64.b16decode(salt.upper()), iterations, 24, hashlib.sha1)
        new_hash = base64.b16encode(new_raw_hash).lower()

        return pbkdf2_hash == new_hash
Пример #21
0
 def encode(self, password, salt, iterations=None):
     assert password
     assert salt and '$' not in salt
     if not iterations:
         iterations = self.iterations
     hash = pbkdf2(password, salt, iterations, digest=self.digest)
     hash = hash.encode('base64').strip()
     return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
Пример #22
0
 def decrypted_report(self, key):
     stretched_key = pbkdf2(key,
                            self.salt,
                            settings.KEY_ITERATIONS,
                            digest=hashlib.sha256)
     box = nacl.secret.SecretBox(stretched_key)
     decrypted = box.decrypt(bytes(self.encrypted))
     return decrypted.decode('utf-8')
def makeCred(account, password):
    cred = Credential()
    cred.prf = "HMAC+SHA256"
    cred.salt = crypto.get_random_string()
    cred.iterations = 20000
    cred.hash = base64.b64encode(crypto.pbkdf2(password, cred.salt, iterations=cred.iterations))
    cred.account = account
    return cred
Пример #24
0
def django_check_hash(password, hash):
    if not hash.startswith('pbkdf2_sha256'):
        raise ValueError('Invalid hash ' + hash)
    _type, iterations, salt, hashvalue = hash.split('$', 3)
    stored_hash = b64decode(hashvalue)
    
    given_hash = pbkdf2(password, salt, int(iterations))
    return constant_time_compare(given_hash, stored_hash)
Пример #25
0
 def encode(self, password, salt, iterations=None):
     assert password is not None
     assert salt and "$" not in salt
     if not iterations:
         iterations = self.iterations
     hash = pbkdf2(password, "", iterations, digest=self.digest, dklen=40)
     hash = base64.b64encode(hash)
     return "%s" % hash
Пример #26
0
 def encode(self, password, salt, iterations=None):
     assert password
     assert salt and "$" not in salt
     if not iterations:
         iterations = self.iterations
     hash = pbkdf2(password, salt, iterations, digest=self.digest)
     hash = base64.b64encode(hash).decode("ascii").strip()
     return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash)
Пример #27
0
def hash_password(raw_password, salt, permutation, iterations=HASH_ITERATIONS):
    """
    Hash data of the form "<raw_password>$<comma sep permutations>"
    """
    permutation = ','.join(map(str, permutation))
    password = '******' % (raw_password, permutation)
    hashed = pbkdf2(password, salt, iterations)
    return base64.b64encode(hashed).decode('ascii').strip()
Пример #28
0
 def encode(self, password, salt, iterations=None):
     assert password is not None
     assert salt and '$' not in salt
     if not iterations:
         iterations = self.iterations
     hash = pbkdf2(password, salt, iterations, digest=sha256)
     hash = base64.b64encode(hash).decode('ascii').strip()
     return "%s$%d$%s$%s" % ("pbkdf2_sha256", iterations, salt, hash)
Пример #29
0
 def encode(self, password, salt, iterations=None):
     # Override the standard encoding routine to encode the hash as hex rather than base64 and truncate at 40 chars
     # Alternately, this could run super().encode(), split the result by $, re-encode with hex, and reassemble
     assert password is not None
     assert salt and '$' not in salt
     iterations = iterations or self.iterations
     hash_ = pbkdf2(password, salt, iterations, digest=self.digest)
     hash_hex = hash_.hex()[:40]
     return "%s$%d$%s$%s" % (self.algorithm, iterations, salt, hash_hex)
Пример #30
0
 def create_token(self, user):
     """Create a signed token from an `auth.User`."""
     # Include a hash derived from the password so changing the password
     # revokes the token. Usually, user.password will be a secure hash
     # already, but we hash it again in case it isn't. We use MD5
     # to minimize the length of the token. (Remember, if an attacker
     # obtains the URL, he can already log in. This isn't high security.)
     h = crypto.pbkdf2(user.password, 'sesame', 10000, digest=hashlib.md5)
     return self.sign(struct.pack(str('!i'), user.pk) + h)
Пример #31
0
    def validate_authentication(self, username, password, handler):
        try:
            password_info = self.user_table[username]['pwd'].split('$')
            user_password = base64.b64encode(pbkdf2(password, password_info[2], int(password_info[1])))

            if user_password != password_info[3]:
                raise KeyError
        except KeyError:
            raise AuthenticationFailed
Пример #32
0
def hash_id_value(hicn):
    """
    Hashes an MBI or HICN to match fhir server logic:
    Both currently use the same hash salt ENV values.
    https://github.com/CMSgov/beneficiary-fhir-data/blob/master/apps/bfd-pipeline/bfd-pipeline-rif-load/src/main/java/gov/cms/bfd/pipeline/rif/load/RifLoader.java#L665-L706
    """
    return binascii.hexlify(
        pbkdf2(hicn, get_user_id_salt(),
               settings.USER_ID_ITERATIONS)).decode("ascii")
Пример #33
0
 def create_token(self, user):
     """Create a signed token from an `auth.User`."""
     # Include a hash derived from the password so changing the password
     # revokes the token. Usually, user.password will be a secure hash
     # already, but we hash it again in case it isn't. We use MD5
     # to minimize the length of the token. (Remember, if an attacker
     # obtains the URL, he can already log in. This isn't high security.)
     h = crypto.pbkdf2(user.password, 'sesame', 10000, digest=hashlib.md5)
     return self.sign(struct.pack(str('!i'), user.pk) + h)
Пример #34
0
 def _is_valid_token(self, token, token_str):
     test_token = crypto.pbkdf2(
         token_str,
         token.salt,
         token.iterations
     )
     if test_token == bytes(token.token):
         return True
     return False
Пример #35
0
 def __init__(self, key, block_size=32):
     self.bs = block_size
     key = key.encode('UTF-8', errors='replace')
     if len(key) >= block_size:
         self.key = key[:block_size]
     else:
         self.key = self._pad(key)
     self.key_hash = crypto.pbkdf2(key, key[:10], 10000, 0)
     if len(self.key_hash) < AES.block_size:
         self.key_hash += b'0' * (AES.block_size - len(self.key_hash))
Пример #36
0
    def generate_token(self):
        # Inspired by: https://github.com/aaugustin/django-sesame/

        raw_token = struct.pack(
            str("!i"), self.invited_user.pk) + crypto.pbkdf2(
                self.invited_user.email, "radiologo", 10000)
        url_ready_token = signing.TimestampSigner(salt="radiologo").sign(
            signing.b64_encode(raw_token).decode())
        self.sent_token = url_ready_token
        return url_ready_token
Пример #37
0
 def test_default_hmac_alg(self):
     kwargs = {
         'password': b'password',
         'salt': b'salt',
         'iterations': 1,
         'dklen': 20
     }
     self.assertEqual(
         pbkdf2(**kwargs),
         hashlib.pbkdf2_hmac(hash_name=hashlib.sha256().name, **kwargs))
Пример #38
0
def hexlify_pbkdf2(password, salt, iterations, length, digest=hashlib.sha1):
    """
    >>> hash = hexlify_pbkdf2("not secret", "a salt value", iterations=100, length=16)
    >>> hash == '0b919231515dde16f76364666cf07107'
    True
    """
    # log.debug("hexlify_pbkdf2 with iterations=%i", iterations)
    hash = crypto.pbkdf2(password, salt, iterations=iterations, dklen=length, digest=digest)
    hash = binascii.hexlify(hash)
    hash = six.text_type(hash, "ascii")
    return hash
Пример #39
0
 def test_default_hmac_alg(self):
     kwargs = {
         "password": b"password",
         "salt": b"salt",
         "iterations": 1,
         "dklen": 20,
     }
     self.assertEqual(
         pbkdf2(**kwargs),
         hashlib.pbkdf2_hmac(hash_name=hashlib.sha256().name, **kwargs),
     )
Пример #40
0
 def encrypt_report(self, report_text, key):
     if not self.salt:
         self.salt = get_random_string()
     else:
         self.last_edited = timezone.now()
     stretched_key = pbkdf2(key, self.salt, settings.KEY_ITERATIONS, digest=hashlib.sha256)
     box = nacl.secret.SecretBox(stretched_key)
     message = report_text.encode('utf-8')
     nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE)
     encrypted = box.encrypt(message, nonce)
     self.encrypted = encrypted
Пример #41
0
def verify_pw(request):
    if request.method == 'POST':
        if check_password(request.POST.get("Password"), request.user.password):
            _, _, salt, _ = request.user.password.split('$')
            key = pbkdf2(request.POST.get("Password"), salt, 50000, 48)
            request.session['iv'] = key[0:16].hex()
            request.session['cipherKey'] = key[16:].hex()
            return redirect('/password/')
        else:
            messages.error(request, 'Incorrect Password')
    return render(request, "password/verify_pw.html", {})
Пример #42
0
def hash_hicn(hicn):
    """
    Hashes a hicn to match fhir server logic:
    https://github.com/CMSgov/beneficiary-fhir-data/blob/master/apps/bfd-pipeline/bfd-pipeline-rif-load/src/main/java/gov/cms/bfd/pipeline/rif/load/RifLoader.java#L665-L706

    """
    assert hicn != "", "HICN cannot be the empty string"

    return binascii.hexlify(pbkdf2(hicn,
                            get_user_id_salt(),
                            settings.USER_ID_ITERATIONS)).decode("ascii")
Пример #43
0
    def _get_password_hash(self, password, fixed_salt=None):
        """ Return password after hash operation

        :param password: String with plain text password
        :param fixed_salt: If Set, use the given fixed_salt in pbkdf2 operation instead of computing a new one
        This is used to compare existing password
        :return: String with hashed password
        """
        if self.password_salt is not None:
            salt = self.password_salt
            if self.password_salt_position == 'begin':
                password = "******".format(salt, password)
            elif self.password_salt_position == 'end':
                password = "******".format(password, salt)

        hash_algo = self.password_hash_algo
        if not isinstance(password, bytes):
            password = str(password).encode('utf8')
        if hash_algo == 'plain':
            return password
        elif hash_algo == 'md5':
            return hashlib.md5(password).hexdigest()
        elif hash_algo == 'sha1':
            return hashlib.sha1(password).hexdigest()
        elif hash_algo == 'sha256':
            return hashlib.sha256(password).hexdigest()
        elif hash_algo == 'sha384':
            return hashlib.sha384(password).hexdigest()
        elif hash_algo == 'sha512':
            return hashlib.sha512(password).hexdigest()
        elif hash_algo == 'make_password':
            return make_password(password)
        elif hash_algo.startswith('pbkdf2'):
            args = hash_algo.split('-')
            hash = args[1]
            iter = args[2]

            for alg in hashlib.algorithms_available:
                if str(hash) in alg:
                    algo = getattr(hashlib, 'sha' + str(hash))
                    if not fixed_salt:
                        rdm_str = get_random_string()
                    else:
                        rdm_str = fixed_salt
                    pwd = base64.b64encode(
                        pbkdf2(password, rdm_str, int(iter),
                               digest=algo)).decode('utf8')
                    return "pbkdf2_sha" + str(hash) + '$' + str(
                        iter) + '$' + rdm_str + '$' + pwd

        else:
            raise NotImplemented("Password hash algorithm not implemented, "
                                 "algo: {}".format(hash_algo))
Пример #44
0
    def get_bucket_key(self, *args, **kwargs):
        ip_address = super(HashedRemoteIP,
                           self).get_bucket_key(*args, **kwargs)

        bucket_key = pbkdf2(ip_address,
                            self.get_salt(),
                            self.get_iterations(),
                            digest=hashlib.sha256)

        bucket_key = binascii.b2a_hex(bucket_key)

        return bucket_key
Пример #45
0
    def post(self, request):
        phone_number = str(self.request.data.get('phone_number', '')).strip()
        search_for_code = str(self.request.data.get('code', '')).strip()
        codes = SMSAuthCode.objects.filter(phone_number=phone_number).all()
        for code in codes:
            test_code = crypto.pbkdf2(
                search_for_code,
                code.salt,
                code.iterations
            )
            if test_code == bytes(code.code):
                if code.expires < datetime.now():
                    code.delete()
                    return Response({'error': 'code expired'}, status=403)

                auth_token = SMSAuthToken.generate_token()
                salt = crypto.get_random_string()
                iterations = randint(10000, 10100)
                encrypted = crypto.pbkdf2(auth_token, salt, iterations)

                token = SMSAuthToken.objects.create(
                    phone_number=phone_number,
                    token=encrypted,
                    salt=salt,
                    iterations=iterations
                )
                for user in code.users.all():
                    token.users.add(user)

                serialized_users = [
                    UserSerializer(u).data
                    for u
                    in code.users.all()
                ]
                code.delete()
                return Response({
                    'users': serialized_users,
                    'token': auth_token,
                })
        return Response({'error': 'invalid'}, status=403)
Пример #46
0
    def create_token(self, user):
        """
        Create a signed token from a user.

        """
        # Include a hash derived from the password so changing the password
        # revokes the token. Usually, user.password will be a secure hash
        # already, but we hash it again in case it isn't. We default to MD5
        # to minimize the length of the token. (Remember, if an attacker
        # obtains the URL, he can already log in. This isn't high security.)
        h = crypto.pbkdf2(
            user.password, self.salt, self.iterations, digest=self.digest)
        return self.sign(struct.pack(str('!i'), user.pk) + h)
Пример #47
0
    def begin_two_factor_authentication(self, session):
        # Generate a TFA key and salt, store them for later verification
        tfa_key = str(uuid.uuid4())
        tfa_salt = str(uuid.uuid4())
        session['tfa_key'] = tfa_key
        session['tfa_salt'] = tfa_salt

        # Generate the signature to send back to the user
        tfa_sig = base64.b16encode(pbkdf2(tfa_key + self.password, tfa_salt, 1000, 24))

        return {
            'status': 'tfa',
            'tfa_userid': self.id,
            'tfa_signature': tfa_sig
        }
Пример #48
0
    def create_token(self, user):
        """
        Create a signed token from a user.

        """
        # The password is expected to be a secure hash but we hash it again
        # for additional safety. We default to MD5 to minimize the length of
        # the token. (Remember, if an attacker obtains the URL, he can already
        # log in. This isn't high security.)
        h = crypto.pbkdf2(
            self.get_revocation_key(user),
            self.salt,
            self.iterations,
            digest=self.digest,
        )
        return self.sign(self.packer.pack_pk(user.pk) + h)
Пример #49
0
 def parse_token(self, token):
     """Obtain an `auth.User` from a signed token."""
     try:
         data = self.unsign(token)
     except signing.BadSignature:
         logger.debug("Invalid token: %s", token)
         return
     user = self.get_user(*struct.unpack(str('!i'), data[:4]))
     if user is None:
         logger.debug("Unknown token: %s", token)
         return
     h = crypto.pbkdf2(user.password, 'sesame', 10000, digest=hashlib.md5)
     if not crypto.constant_time_compare(data[4:], h):
         logger.debug("Expired token: %s", token)
         return
     logger.debug("Valid token for user %s: %s", user, token)
     return user
Пример #50
0
def _encrypt_report(salt, key, report_text):
    """Encrypts a report using the given secret key & salt. The secret key is stretched to 32 bytes using Django's
    PBKDF2+SHA256 implementation. The encryption uses PyNacl & Salsa20 stream cipher.

    Args:
      salt (str): cryptographic salt
      key (str): secret key
      report_text (str): full report as a string

    Returns:
      bytes: the encrypted bytes of the report

    """
    stretched_key = pbkdf2(key, salt, settings.KEY_ITERATIONS, digest=hashlib.sha256)
    box = nacl.secret.SecretBox(stretched_key)
    message = report_text.encode('utf-8')
    nonce = nacl.utils.random(nacl.secret.SecretBox.NONCE_SIZE)
    return box.encrypt(message, nonce)
Пример #51
0
def _decrypt_report(salt, key, encrypted):
    """Decrypts an encrypted report.

    Args:
      salt (str): cryptographic salt
      key (str): secret key
      encrypted (bytes): full report encrypted

    Returns:
      str: the decrypted report as a string

    Raises:
      CryptoError: If the key and salt fail to decrypt the record.

    """
    stretched_key = pbkdf2(key, salt, settings.KEY_ITERATIONS, digest=hashlib.sha256)
    box = nacl.secret.SecretBox(stretched_key)
    decrypted = box.decrypt(bytes(encrypted))  # need to force to bytes bc BinaryField can return as memoryview
    return decrypted.decode('utf-8')
Пример #52
0
 def _is_valid_token(self, request, token, password, user_id):
     test_token = crypto.pbkdf2(
         password,
         token.salt,
         token.iterations
     )
     if test_token == bytes(token.token):
         if token.expires < datetime.now():
             return False
         if token.users.count() == 1:
             request.user = token.users.all()[0]
             return True
         elif token.users.count() > 1:
             if not user_id:
                 return False
             user = [u for u in token.users.all() if u.id == user_id]
             if len(user) == 1:
                 request.user = user[0]
                 return True
             return False
Пример #53
0
def decrypt_secret(secret, password, username):
    """
    We will get passed in a 16 byte block of data
    that has been enrypted with AES using the PIN
    the first 10 bytes are the secret
    and the remaining 6 are padding

    :param secret: The secret.
    :type secret: str
    :param password: The password.
    :type password: str
    :param username: The user this is for.
    :type username: str
    :returns: str
    """

    secret = base64.b32decode(secret)
    pw_hash = pbkdf2(password.encode('ascii'), username.encode('ascii'), 10000)
    cipher = AES.new(pw_hash, AES.MODE_ECB, '')
    tmp = cipher.decrypt(secret)
    return tmp[:10]
Пример #54
0
Файл: totp.py Проект: 0x3a/crits
def decrypt_secret(secret, password, username):
    """
    We will get passed in a 16 byte block of data
    that has been enrypted with AES using the PIN
    the first 10 bytes are the secret
    and the remaining 6 are padding

    :param secret: The secret.
    :type secret: str
    :param password: The password.
    :type password: str
    :param username: The user this is for.
    :type username: str
    :returns: str
    """

    secret = base64.b32decode(secret)
    pw_hash = pbkdf2(password.encode('ascii'), username.encode('ascii'), 10000)
    crypt_object = EVP.Cipher('aes_128_ecb', pw_hash, '', 0, padding=0)
    tmp = crypt_object.update(secret)
    return tmp[:10]
Пример #55
0
    def authenticate(self, session=None, user_id=None, token=None, signature=None):
        # Ensure that we have TFA parameters
        if token is None or signature is None:
            return None

        # Fetch the user
        try:
            user = User.objects.get(pk=user_id)
        except:
            return None

        # Verify the signature from the user is the one we generated
        expected_tfa_sig = base64.b16encode(pbkdf2(session.get('tfa_key', '') + user.password, session.get('tfa_salt', ''), 1000, 24))
        if expected_tfa_sig != signature:
            return None

        # Verify the token from the user
        expected_token = str(get_totp_token(user.totp_secret.upper())).zfill(6)
        if expected_token == token:
            return user

        return None
Пример #56
0
def encrypt_secret(secret, password, username):
    """
    Pad the secret with 6 random bytes
    which makes the secret 16 bytes for ECB
    but also makes all encrypted secrets unique
    even if they have the same original value
    which is important for cases where we might allow
    a user to carry over an existing secret from
    another system

    :param secret: The secret.
    :type secret: str
    :param password: The password.
    :type password: str
    :param username: The user this is for.
    :type username: str
    :returns: str
    """

    secret += gen_random(6)
    pw_hash = pbkdf2(password.encode('ascii'), username.encode('ascii'), 10000)
    cipher = AES.new(pw_hash, AES.MODE_ECB, '')
    tmp = cipher.encrypt(secret)
    return tmp
Пример #57
0
Файл: totp.py Проект: 0x3a/crits
def encrypt_secret(secret, password, username):
    """
    Pad the secret with 6 random bytes
    which makes the secret 16 bytes for ECB
    but also makes all encrypted secrets unique
    even if they have the same oroginal value
    which is important for cases where we might allow
    a user to carry over an existing secret from
    another system

    :param secret: The secret.
    :type secret: str
    :param password: The password.
    :type password: str
    :param username: The user this is for.
    :type username: str
    :returns: str
    """

    secret += gen_random(6)
    pw_hash = pbkdf2(password.encode('ascii'), username.encode('ascii'), 10000)
    crypt_object = EVP.Cipher('aes_128_ecb', pw_hash, '', 1, padding=0)
    tmp = crypt_object.update(secret)
    return tmp