def test_invalid_n(self, backend): # n is less than 2 with pytest.raises(ValueError): Scrypt(b"NaCl", 64, 1, 8, 16, backend) # n is not a power of 2 with pytest.raises(ValueError): Scrypt(b"NaCl", 64, 3, 8, 16, backend)
def enterFolderPwd(self, folder_path): #user has to enter folder password #compared to stored hash #repeated until the correct password was entered while True: folder_pwd = input( "This is your first access to this folder. Please enter the folder password: "******"salt"], length=32, n=2**4, r=8, p=1, backend=default_backend()) try: kdf.verify(folder_pwd.encode(), self.pwd_db[folder_path]) except InvalidKey: print("The password is wrong.") continue else: break print("Folder password will be stored for access in the future.") #get correct user password to encrypt the folder password for this user while True: pwd = input("Please enter the user password: "******"salt"], length=32, n=2**4, r=8, p=1, backend=default_backend()) try: kdf.verify(pwd.encode(), self.users[self.currentUser]["pwd"]) except InvalidKey: print("The password is wrong.") continue else: break #encrypt the folder password using the user password and store it kdf = PBKDF2HMAC(algorithm=hashes.SHA256(), length=32, salt=self.users[self.currentUser]["salt"], iterations=100000, backend=default_backend()) pwd_key = kdf.derive(pwd.encode()) f = Fernet(urlsafe_b64encode(pwd_key)) encrypted_folder_pwd = f.encrypt(folder_pwd.encode()) self.users[self.currentUser]["folders"].update( {folder_path: encrypted_folder_pwd})
def scrypt(self): cost = 14 backend = default_backend() salt = os.urandom(16) start_time = time.time() while True: print('--- %s seconds ---' % (time.time() - start_time), "cpu/memory cost factor", cost) if ((time.time() - start_time) < self.running_time): start_time = time.time() kdf = Scrypt(salt=salt, length=32, n=2**cost, r=8, p=1, backend=backend) key = kdf.derive(str.encode(self.password)) else: if ((time.time() - start_time) > self.threshold ): # Check if its way more than acceptable print('--- %s seconds ---' % (time.time() - start_time), "cpu/memory cost factor", cost - 1) else: print('--- %s seconds ---' % (time.time() - start_time), "cpu/memory cost factor", cost) break cost = cost + 1
def get_key(verbose_pass=False): print("Please write your password") password1 = stdiomask.getpass() password1 = password1.encode() # Okey for this application, if this application is used for storring multiple users data or something like that # A non static salt should be used to avoid rainbow-table vulnerbilities salt = b'u\xcf(\n\xd5\x9c\x05\xffy\x97\x96\xb1@\x1f\rn' time1 = time.time() kdf = Scrypt(salt=salt, length=32, n=2**20, r=8, p=1) #key = base64.urlsafe_b64encode(kdf.derive(password1)) key = kdf.derive(password1) print("It took ", time.time() - time1, " seconds to generate the key") print("Please verify your password") password2 = stdiomask.getpass() password2 = password2.encode() if password2 != password1: print("Passwords didn't match") exit(-1) return key
def test_hand_shake_verify_password_return_true_if_given_password_is_correct_and_role_is_server( ): # Given password_to_verify = b"test_password" password_to_derive = b"test_password" password_salt = os.urandom(16) expected_result = True # derive kdf = Scrypt( salt=password_salt, length=32, n=2**14, r=8, p=1, ) derived_password = kdf.derive(password_to_derive) authentication_information_server = { "password": { Handshake.PASSWORD_AUTH_METHOD_DERIVED_PASSWORD_KEY: derived_password, Handshake.PASSWORD_AUTH_METHOD_SALT_KEY: password_salt } } allowed_authentication_methods = ["password"] server = Handshake( role=Handshake.SERVER, authentication_information=authentication_information_server, allowed_authentication_methods=allowed_authentication_methods) # When result = server._verify_password(password_to_verify=password_to_verify) # Then assert result == expected_result
def _verify_password(self, password, derived_password, salt): """ :param password: clear text received from the user that wants to be authenticated :param password: str :return: true if password received matches the one stored :rtype: bool """ derived_password = b64decode(derived_password) salt = b64decode(salt) password = bytes(password, "utf-8") kdf = Scrypt( salt = salt, length = 32, n = 2**14, r = 8, p = 1, backend = default_backend() ) try: kdf.verify(password, derived_password) return True except InvalidKey: return False
def derive(master_password: str, domain: str, user: str, counter: int, length: int, charset: str) -> str: if counter < 0 or counter > 255: raise ValueError( f'Counter {counter} cannot be represented by a single byte') master_password = ensure_bytes(master_password) domain = ensure_bytes(domain) user = ensure_bytes(user) salt = domain + b'\0' + user + b'\0' + bytes([counter]) hash_bytes: bytes = Scrypt(salt=salt, length=NUM_OCTATS, n=N, r=R, p=P, backend=BACKEND).derive(master_password) hash_int = bytes_to_big_endian_large_int(hash_bytes) result = [None] * length for i in range(length): if not hash_int: raise ValueError( f'Entropy exhausted. Requested derived password too long (len={length}).' ) hash_int, residue = divmod(hash_int, len(charset)) result[i] = charset[residue] return ''.join(result)
def encrypt_file(plainpath, cipherpath, password): salt = os.urandom(16) kdf = Scrypt(salt=salt, length=32, n=2**14, r=8, p=1, backend=default_backend()) key = kdf.derive(password) iv = os.urandom(12) encryptor = Cipher(algorithms.AES(key), modes.GCM(iv), backend=default_backend()).encryptor() associated_data = iv + salt encryptor.authenticate_additional_data(associated_data) with open(cipherpath, "wb+") as fcipher: fcipher.write(b"\x00" * (12 + 16 + 16)) with open(plainpath, "rb") as fplain: for plaintext in iter(lambda: fplain.read(READ_SIZE), b""): ciphertext = encryptor.update(plaintext) fcipher.write(ciphertext) ciphertext = encryptor.finalize() fcipher.write(ciphertext) header = associated_data + encryptor.tag fcipher.seek(0, 0) fcipher.write(header)
def kdf(cls, kdf, key, salt=None, dklen=None, verbose=False): assert (isinstance(key, bytes)) if salt is None: salt = os.urandom(32) if dklen is None: dklen = kdf["dklen"] meta = { "name": kdf["name"], "salt": salt.hex(), "dklen": dklen, } t0 = time.time() if kdf["name"] == "scrypt": N = kdf.get("N", 1024 * 1024) r = kdf.get("r", 8) p = kdf.get("p", 1) meta.update({ "N": N, "r": r, "p": p, }) scrypt = Scrypt(salt=salt, length=dklen, n=N, r=r, p=p, backend=_backend) dkey = scrypt.derive(key) else: raise NotImplementedError(kdf["name"]) t1 = time.time() if verbose: print("Key derivation took %.3f sec" % (t1 - t0)) return (meta, dkey)
def hash_function(p, hashfunc="bcrypt", salt=None): """Generate hash from input string. Arguments: p {str, bytes} -- The input to be hashed. Keyword Arguments: hashfunc {str} -- Hashing algorithm to use. Options are "sha1" and "scrypt". (default: {"sha1"}) Returns: bytes -- Hash of the input """ if isinstance(p, str): # Convert str to bytes if necessary p = p.encode() hashfunc = hashfunc.lower() # Ensure the input will match the conditional case. if hashfunc == "sha1": return hashlib.sha1(p).hexdigest().encode() elif hashfunc == "scrypt": if not salt: salt = b"salt" instance = Scrypt( salt=b"salt", length=32, n=2 ** 14, r=8, p=1, backend=default_backend() ) return instance.derive(p) elif hashfunc == "bcrypt": if not salt: salt = bcrypt.gensalt() return bcrypt.hashpw(p, salt) else: raise ValueError
def decrypt_file(cipherpath, plainpath, password): with open(cipherpath, "rb") as fcipher: # read the IV (12 bytes) and the salt (16 bytes) associated_data = fcipher.read(12+16) iv = associated_data[0:12] salt = associated_data[12:28] # derive the same key from the password + salt kdf = Scrypt(salt=salt, length=32, n=2**14, r=8, p=1, backend=default_backend()) key = kdf.derive(password) # get the tag. GCM tags are always 16 bytes tag = fcipher.read(16) # Construct an AES-GCM Cipher object with the given key and IV # For decryption, the tag is passed in as a parameter decryptor = Cipher( algorithms.AES(key), modes.GCM(iv, tag), backend=default_backend()).decryptor() decryptor.authenticate_additional_data(associated_data) with open(plainpath, "wb+") as fplain: for ciphertext in iter(lambda: fcipher.read(READ_SIZE),b''): plaintext = decryptor.update(ciphertext) fplain.write(plaintext)
def _set_client_secret(self, client_secret): if self._salt: salt = b64decode(self._salt.encode('utf-8')) else: try: if not oauth2_settings('salt'): raise ValueError( 'oauth2_provider.salt configuration required.' ) salt = b64decode(oauth2_settings('salt').encode('utf-8')) except AttributeError: return kdf = Scrypt( salt=salt, length=64, n=2 ** 14, r=8, p=1, backend=backend ) try: client_secret = bytes(client_secret, 'utf-8') except TypeError: pass self._client_secret = kdf.derive(client_secret)
def query(ctxt): global r, passwords if REMOTE: menu(3) print("Query") print(r.recvline()) r.sendline(ctxt) print(r.recvline()) s = r.recvline() print("s:", s) if b"ERROR" in s: return 0 print(r.recvline()) r.recvline() return 1 else: nonce, ciphertext = ctxt.split(b",") nonce = b64decode(nonce) ciphertext = b64decode(ciphertext) kdf = Scrypt(salt=b'', length=16, n=2**4, r=8, p=1, backend=default_backend()) key = kdf.derive(passwords[cur_idx]) try: cipher = AESGCM(key) plaintext = cipher.decrypt(nonce, ciphertext, associated_data=None) return 1 except: return 0
def read(args, action): # read the file with contextlib.closing(FileDecryptor(args.archive, None)) as fd: # no decryptor yet # parse the header header = HEADER.parse(fd.read_aad(HEADER.sizeof())) # setup encryption kdf_params = header['kdf_params'] kdf = Scrypt(salt=kdf_params['salt'], length=32, n=kdf_params['n'], r=kdf_params['r'], p=kdf_params['p'], backend=BACKEND) key = kdf.derive(get_password().encode('utf-8')) logging.debug(f'[read()] key={key.hex()}') cipher_params = header['cipher_params'] cipher = Cipher(algorithms.ChaCha20(key, cipher_params['nonce']), modes.Poly1305(), backend=BACKEND) fd.init(cipher.decryptor()) # read the tag fd.read_tag() # read the archive tar = tarfile.open(fileobj=fd, mode='r|*') action(tar)
def test_verify_password_scrypt_return_true_if_given_password_is_correct_and_derived_with_scrypt( ): # Given password_to_verify = b"test_password" password_to_derive = b"test_password" password_salt = os.urandom(16) expected_result = True # derive kdf = Scrypt( salt=password_salt, length=32, n=2**14, r=8, p=1, ) derived_password = kdf.derive(password_to_derive) # When result = verify_password_scrypt(password_to_verify=password_to_verify, derived_password=derived_password, password_salt=password_salt) # Then assert result == expected_result
def aesDecrypt(iv, salt, password, payload): """ Decrypt AndSafe payload Keyword arguments: :param iv: IV for AES in CBC mode. In hexdecimal string format :param salt: salt for scrypt key derivation. In hexdecimal string format :param password: password for decryption. In string format :param payload: payload to decrypt. In hexdecimal string format :return: bytes of decrypted content """ unpadder = padding.PKCS7(128).unpadder() backend = default_backend() kdf = Scrypt(salt=bytes.fromhex(salt), length=32, n=2**14, r=8, p=1, backend=backend) key = kdf.derive(password.encode()) cipher = Cipher(algorithms.AES(key), modes.CBC(bytes.fromhex(iv)), backend=backend) decryptor = cipher.decryptor() return unpadder.update( decryptor.update(bytes.fromhex(payload)) + decryptor.finalize()) + unpadder.finalize()
def keyeststep10(): received = ast.literal_eval(pkt1.smsg.actMsg) salt = received["salt"] aesgcm = AESGCM(temp_known_users[addr]["Sab"]) try: u2_pubkey = int( aesgcm.decrypt(received["nonceforu2pubkey"], received["enc_u2pubkey"], None)) ssAB = pow(u2_pubkey, keyeststep8.u1_prikey, keyeststep8.s_p) backend = default_backend() # derive kdf = Scrypt(salt=salt, length=32, n=2**14, r=8, p=1, backend=backend) kAB = kdf.derive(bytes(ssAB)) known_users[temp_known_users[addr]["name"]] = { "ssAB": kAB, "addr": addr } aesgcm = AESGCM(kAB) nonceformsg = os.urandom(12) message = aesgcm.encrypt(nonceformsg, keyestfunction.smsg, None) msgtosend = {"nonceformsg": nonceformsg, "msg": message} fillauthpacket(pkt1, "Data", 0, bytes(msgtosend)) sendpacket(pkt1.SerializeToString(), addr[0], addr[1]) except cryptography.exceptions.InvalidTag: print "Decrypt not okay"
def decrypt_file(cipherpath, plainpath, password): with open(cipherpath, "rb") as fcipher: associated_data = fcipher.read(12 + 16) iv = associated_data[0:12] salt = associated_data[12:28] # Derive the same password with salt kdf = Scrypt(salt=salt, length=32, n=2**14, r=8, p=1, backend=default_backend()) key = kdf.derive(password) # GCM tags are always 16 bytes tag = fcipher.read(16) decryptor = Cipher(algorithms.AES(key), modes.GCM(iv, tag), backend=default_backend()).decryptor() decryptor.authenticate_additional_data(associated_data) with open(plainpath, "wb+") as fplain: for ciphertext in iter(lambda: fcipher.read(READ_SIZE), b""): plaintext = decryptor.update(ciphertext) fplain.write(plaintext)
def from_bytes(cls, key_bytes: bytes, password: Optional[bytes] = None, _scrypt_cost: int = 20) -> 'UmbralKeyingMaterial': """ Loads an UmbralKeyingMaterial from a urlsafe base64 encoded string. Optionally, if a password is provided it will decrypt the key using nacl's Salsa20-Poly1305 and Scrypt key derivation. WARNING: RFC7914 recommends that you use a 2^20 cost value for sensitive files. Unless you changed this when you called `to_bytes`, you should not change it here. It is NOT recommended to change the `_scrypt_cost` value unless you know what you're doing. """ if password: salt = key_bytes[-16:] key_bytes = key_bytes[:-16] key = Scrypt(salt=salt, length=SecretBox.KEY_SIZE, n=2**_scrypt_cost, r=8, p=1, backend=default_backend()).derive(password) key_bytes = SecretBox(key).decrypt(key_bytes) return cls(key_bytes)
def _derive_password(self, password): """ Derives a password with a salt :param password: clear text password :type password: str :return: derived password and salt used encoded in base64 :rtype: (str, str) """ salt = urandom(SALT_SIZE) password = bytes(password, "utf-8") kdf = Scrypt( salt = salt, length = 32, n = 2**14, r = 8, p = 1, backend = default_backend() ) derived_password = kdf.derive(password) return b64encode(derived_password), b64encode(salt)
def decrypt_key_with_password(key, password): """Turns a key and password into a scrypt key :param bytes key: The key bytes, containing the salt and encrypted key :param str password: The password in plaintext to derive the key from :returns: The decrypted key contained in ``key`` :rtype: bytes """ # get the salt and encrypted key salt, encryptedKey = key[0:SALT_SIZE], key[SALT_SIZE:] # re-create the file's key with the provided password and salt derivedKey = Scrypt( salt, backend=default_backend(), # key length for AES length=32, # The cost parameter n=32 * 1024, # same values as go-config-yourself r=8, p=1, ).derive(bytes(password, "utf-8")) # Return the decrypted key using the derived key return DataKeyService(derivedKey).decrypt(encryptedKey)
def api_token(): user = request.form["user"] password = request.form["password"].encode("utf8") conn = sqlite3.connect("user.db") c = conn.cursor() result = c.execute( "SELECT salt, pass, admin from users where user=?", [user] ).fetchone() conn.close() if result is None: abort(403) salt, spass, admin = result kdf = Scrypt( salt=salt, length=32, n=2**14, r=8, p=1, backend=default_backend() ) try: kdf.verify(password, spass) except InvalidKey: print("invalid password") abort(403) payload = json.dumps({"admin": admin, "user": user}, sort_keys=True) # encrypt the payload return _encrypt(payload)
def __fernetKey(self, salt, password): backend = default_backend() kdf = Scrypt(salt=salt, length=32, n=2**14, r=8, p=1, backend=backend) key = base64.urlsafe_b64encode(kdf.derive(b"%a" % password)) return Fernet(key)
def to_bytes(self, password: bytes = None, _scrypt_cost: int = 20, encoder: Callable = None): """ Returns an Umbral private key as bytes optional symmetric encryption via nacl's Salsa20-Poly1305 and Scrypt key derivation. If a password is provided, the user must encode it to bytes. Optionally, allows an encoder to be passed in as a param to encode the data before returning it. WARNING: RFC7914 recommends that you use a 2^20 cost value for sensitive files. It is NOT recommended to change the `_scrypt_cost` value unless you know what you are doing. """ umbral_privkey = self.bn_key.to_bytes() if password: salt = os.urandom(16) key = Scrypt(salt=salt, length=SecretBox.KEY_SIZE, n=2**_scrypt_cost, r=8, p=1, backend=default_backend()).derive(password) umbral_privkey = SecretBox(key).encrypt(umbral_privkey) umbral_privkey += salt if encoder: umbral_privkey = encoder(umbral_privkey) return umbral_privkey
def aesEncrypt(iv, salt, password, plain): """ Encrypt AndSafe plaintext Keyword arguments: :param iv: IV for AES in CBC mode. In hexdecimal string format :param salt: salt for scrypt key derivation. In hexdecimal string format :param password: password for encryption. In string format :param plain: plaintext to encrypt :return: bytes of encrypted content """ padder = padding.PKCS7(128).padder() backend = default_backend() kdf = Scrypt(salt=bytes.fromhex(salt), length=32, n=2**14, r=8, p=1, backend=backend) key = kdf.derive(password.encode()) cipher = Cipher(algorithms.AES(key), modes.CBC(bytes.fromhex(iv)), backend=backend) encryptor = cipher.encryptor() return encryptor.update( padder.update(str.encode(plain)) + padder.finalize()) + encryptor.finalize()
def to_bytes(self, password: bytes=None, _scrypt_cost: int=20): """ Returns an Umbral private key as a urlsafe base64 encoded string with optional symmetric encryption via nacl's Salsa20-Poly1305 and Scrypt key derivation. If a password is provided, the user must encode it to bytes. WARNING: RFC7914 recommends that you use a 2^20 cost value for sensitive files. It is NOT recommended to change the `_scrypt_cost` value unless you know what you are doing. """ umbral_priv_key = self.bn_key.to_bytes() if password: salt = os.urandom(16) key = Scrypt( salt=salt, length=SecretBox.KEY_SIZE, n=2**_scrypt_cost, r=8, p=1, backend=default_backend() ).derive(password) umbral_priv_key = SecretBox(key).encrypt(umbral_priv_key) umbral_priv_key += salt encoded_key = base64.urlsafe_b64encode(umbral_priv_key) return encoded_key
def verify_password_scrypt(password_to_verify: bytes, derived_password: bytes, password_salt: bytes): """Check if the input password correspond to the instance derived password and salt. :param password_to_verify: The password to verify as bytes. :param derived_password: The derived password used to verify the given password as bytes. :param password_salt: The salt used to derive the password as bytes. :return: True if is verified, else False. """ password_correct = False kdf = Scrypt( salt=password_salt, length=32, n=2**14, r=8, p=1, ) try: kdf.verify(password_to_verify, derived_password) password_correct = True except InvalidKey: pass except AlreadyFinalized: pass return password_correct
def _derive_key_material_from_passphrase(salt: bytes, passphrase: str) -> bytes: """ Uses Scrypt derivation to derive a key for encrypting key material. See RFC 7914 for n, r, and p value selections. This takes around ~5 seconds to perform. """ try: key_material = Scrypt(salt=salt, length=__WRAPPING_KEY_LENGTH, n=2**20, r=8, p=1, backend=default_backend()).derive( passphrase.encode()) except InternalError as e: # OpenSSL Attempts to malloc 1 GB of mem for scrypt key derivation if e.err_code[0].reason == 65: raise MemoryError( "Key Derivation requires 1GB of memory: Please free up some memory and try again." ) else: raise e else: return key_material
def from_bytes(cls, key_data: bytes, params: UmbralParameters=None, password: bytes=None, _scrypt_cost: int=20): """ Loads an Umbral private key from a urlsafe base64 encoded string. Optionally, if a password is provided it will decrypt the key using nacl's Salsa20-Poly1305 and Scrypt key derivation. WARNING: RFC7914 recommends that you use a 2^20 cost value for sensitive files. Unless you changed this when you called `to_bytes`, you should not change it here. It is NOT recommended to change the `_scrypt_cost` value unless you know what you're doing. """ if params is None: params = default_params() key_bytes = base64.urlsafe_b64decode(key_data) if password: salt = key_bytes[-16:] key_bytes = key_bytes[:-16] key = Scrypt( salt=salt, length=SecretBox.KEY_SIZE, n=2**_scrypt_cost, r=8, p=1, backend=default_backend() ).derive(password) key_bytes = SecretBox(key).decrypt(key_bytes) bn_key = BigNum.from_bytes(key_bytes, params.curve) return cls(bn_key, params)
def authlaststep(d, addr, aupkt1): # print d # print "cc:", d["clientcontri"] # print "secret:", d["secret"] # print "sc:", d["sumcontri"] session_key = pow( pow(long(d["clientcontri"]), long(d["b"]), p) * pow(long(d["secret"]), (d["b"] * d["u"]), p), 1, p) # print "sk:", session_key batch = ast.literal_eval(aupkt1.smsg.actMsg) # print "batch", batch ct = batch["Enc"] # print "ct", ct C3 = batch["C3"] # print 'c3', C3 nonce = batch["nonce"] # print "nonce", nonce salt = batch["salt"] # print "salt", salt c2 = d["C2"] backend = default_backend() # derive kdf = Scrypt(salt=salt, length=32, n=2**14, r=8, p=1, backend=backend) key = kdf.derive(bytes(session_key)) # print "key", key aesgcm = AESGCM(key) try: ct = long(aesgcm.decrypt(nonce, ct, None)) if c2 == ct: # print "values match" nonce2 = os.urandom(12) encc3 = aesgcm.encrypt(nonce2, bytes(C3), None) # print "enc okay" retd = {"encc3": encc3, "nonce2": nonce2} fillauthpacket(aupkt1, "Login", 6, bytes(retd)) # print "pf" sendpacket(aupkt1.SerializeToString(), addr[0], addr[1]) # print "6 sent" connected_users[addr] = { "uname": temp_values[addr]["uname"], "ipaddr": addr[0], "port": addr[1], "skey": key } currusers[temp_values[addr]["uname"]] = { "ipaddr": addr[0], "port": addr[1] } del temp_values[addr] except cryptography.exceptions.InvalidTag: print "Someone entered an incorrect password" fillauthpacket(aupkt1, "Login", 6, "Incorrect") sendpacket(aupkt1.SerializeToString(), addr[0], addr[1])