Example #1
0
def decrypt_c(rw, c):
    """
    Cette méthode va dechiffrer c
    :param rw: la clé qui va permettre de dériver les autres clé
    :param c: le texte chiffré séparé par une , avec son mac
    :return: le texte c déchiffré
    """
    values = c.split(",")
    data = values[0]
    mac = values[1]

    # KDF on calcule une fois avec 0 et une fois avec 1. Pour le sel la documentation
    # conseille quelque chose d'une longueur de 16bytes qui n'a pas besoin d'être secret
    # c'est pourquoi j'ai choisi de prendre le SSID car le client doit aussi connaitre le sel
    key_aes = scrypt('\x00'.encode() + rw, SSID, 32, N=2 ** 14, r=8, p=1)
    key_hmac = scrypt('\x01'.encode() + rw, SSID, 32, N=2 ** 14, r=8, p=1)

    h = HMAC.new(key_hmac, digestmod=SHA256)
    h.update(a2b_hex(data))
    try:
        h.hexverify(mac)
        cipher = AES.new(key_aes, AES.MODE_CTR, nonce=bytearray(1))
        plaintext = cipher.decrypt(a2b_hex(data))
        return plaintext.decode()
    except ValueError as e:
        raise e
Example #2
0
    def test3(self):
        ref = scrypt(b("password"), b("salt"), 12, 16, 1, 1)

        # Same output, but this time split over 2 keys
        key1, key2 = scrypt(b("password"), b("salt"), 6, 16, 1, 1, 2)
        self.assertEqual((ref[:6], ref[6:]), (key1, key2))

        # Same output, but this time split over 3 keys
        key1, key2, key3 = scrypt(b("password"), b("salt"), 4, 16, 1, 1, 3)
        self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3))
Example #3
0
    def test3(self):
        ref = scrypt(b("password"), b("salt"), 12, 16, 1, 1)

        # Same output, but this time split over 2 keys
        key1, key2 = scrypt(b("password"), b("salt"), 6, 16, 1, 1, 2)
        self.assertEqual((ref[:6], ref[6:]), (key1, key2))

        # Same output, but this time split over 3 keys
        key1, key2, key3 = scrypt(b("password"), b("salt"), 4, 16, 1, 1, 3)
        self.assertEqual((ref[:4], ref[4:8], ref[8:]), (key1, key2, key3))
Example #4
0
def benchmark():
    iters = 2**16
    start_time = timeit.default_timer()
    scrypt(password='******', salt=secrets.token_bytes(32), key_len=32, N=iters, r=r, p=p)
    elapsed = timeit.default_timer() - start_time
    predicted = elapsed * N / iters

    print("Key derivation will take about {} seconds ({} per second).".format(
        round(predicted, 2), round(1/predicted, 3)
        ))
Example #5
0
def hashed_password_verify(hashed_password: str, password: str):
    if ':' not in hashed_password:  # pragma: no cover
        return False
    salt_hex, h_hex = hashed_password.split(':', 2)
    salt = bytes.fromhex(salt_hex)
    h = bytes.fromhex(h_hex)
    return secrets.compare_digest(scrypt(password, salt, 16, N=2**14, r=8, p=1), h)  # type: ignore
Example #6
0
 def _hash(self, password):
     return scrypt(password,
                   salt=self.hash_salt,
                   key_len=32,
                   N=2**12,
                   r=8,
                   p=1)
Example #7
0
def Encrypt_AES():
    Plaintext = InputText.get("1.0", "end").rstrip()
    Plaintext_Byte = Plaintext.encode()
    Plaintext_Byte_Pad = pad(Plaintext_Byte, AES.block_size)
    # The encoded input data is padded to fit the AES block size (16-Byte).

    OutputProgress["value"] = 25
    Root.update_idletasks()
    time.sleep(0.05)

    # ------------------------------------------------------
    # KDF:
    if SelectedAlgorithm.get() == "AES-128":
        KeyLength = 16
    elif SelectedAlgorithm.get() == "AES-192":
        KeyLength = 24
    elif SelectedAlgorithm.get() == "AES-256":
        KeyLength = 32

    OutputProgress["value"] = 50
    Root.update_idletasks()
    time.sleep(0.05)

    Password = PasswordEntry.get().rstrip()
    Password_Encode = Password.encode()
    Salt = get_random_bytes(16)
    Key = scrypt(Password, Salt, KeyLength, N=2**20, r=8, p=1)
    # - ( 2¹⁴, 8, 1 ) for interactive logins (≤100ms)
    # - ( 2²⁰, 8, 1 ) for file encryption (≤5s)
    # ------------------------------------------------------

    # IV: An "initialization vector" is a 16-Byte randomly generated string that randomizes the digest for ciphertext generation, similar to a seed.
    # 16-Byte Key (128-bit)
    # 24-Byte Key (192-bit)
    # 32-Byte Key (256-bit)

    OutputProgress["value"] = 75
    Root.update_idletasks()
    time.sleep(0.05)

    Cipher = AES.new(Key, AES.MODE_CBC)

    Ciphertext = Cipher.encrypt(Plaintext_Byte_Pad)

    SaltEntry.delete(0, "end")
    SaltEntry.insert(0, base64.encodebytes(Salt))

    VectorEntry.delete(0, "end")
    VectorEntry.insert(0, base64.encodebytes(Cipher.iv))

    OutputText.delete(1.0, "end")
    OutputText.insert(1.0, base64.encodebytes(Ciphertext))
    OutputText.bind("<Key>", lambda a: "break")

    OutputProgress["value"] = 100
    Root.update_idletasks()
    time.sleep(0.05)

    OutputProgress["value"] = 0
    Root.update_idletasks()
Example #8
0
    def encryptFile(self, file_in, file_out=''):
        try:
            # because server should never have access to plaintext file data
            with open(self.clientAddress + '/' + file_in, 'rb') as f:
                data = f.read()

            # derive file key from user password
            salt = get_random_bytes(16)
            fileKey = scrypt(self.filePassword.encode('utf-8'),
                             salt,
                             16,
                             N=2**20,
                             r=8,
                             p=1)

            # encrypt the data with the file key
            cipher_aes = AES.new(fileKey, AES.MODE_GCM)
            ciphertext, tag = cipher_aes.encrypt_and_digest(data)

            # if we want to write to another file
            if file_out != '':
                with open(self.clientAddress + '/' + file_out, 'wb') as f:
                    [
                        f.write(x)
                        for x in (salt, cipher_aes.nonce, tag, ciphertext)
                    ]
            return salt + cipher_aes.nonce + tag + ciphertext
        except:
            print("Encryption Failed")
            return None
Example #9
0
def encryptPayload(passwd: bytes, salt: bytes, iv: bytes, payload: bytes):
    key = scrypt(password=passwd, salt=salt, N=(2**14), key_len=32, r=8, p=1)
    #print(key, iv, salt)
    cipher = ChaCha20.new(key=key, nonce=iv)
    rv = cipher.encrypt(payload)
    print(rv)
    return rv
Example #10
0
def encrypt(inpath, outpath, password):
    filename = os.path.basename(inpath)
    salt = secrets.token_bytes(32)
    print("Deriving key.")
    key = scrypt(password=password, salt=salt, key_len=32, N=N, r=r, p=p)

    print("Reading file.")
    with open(inpath, 'rb') as inf:
        in_data = pad(inf.read(), 16)

    print("Encrypting.")
    e = AES.new(key, AES.MODE_ECB)
    out_data = e.encrypt(in_data)
    #EtM
    h = SHA3_512.new(key + out_data).digest()

    padded_filename = pad(filename.encode('utf-8')[:255], 256)
    e_filename = e.encrypt(padded_filename)

    print("Writing file.")
    with open(outpath, 'wb') as outf:
        outf.write(salt)
        outf.write(h)
        outf.write(e_filename)
        outf.write(out_data)
def generate_scrypt_key(password, salt=None):
    ##return bytes of keys, returns list in case of keys > 1
    ##returns hex encoded salt and key byte array
    if not salt:
        salt = os.urandom(16)
    keys = scrypt(password, salt, KEY_LENGTH, N, R, P, 1)
    return keys, salt.hex()
Example #12
0
 def kdf(self, salt):
     """
     Derives the actual aeskey from a given salt and the saved key.
     """
     # pylint: disable=C0415
     from Crypto.Protocol.KDF import scrypt
     return scrypt(self.key, salt, key_len=32, N=2**17, r=8, p=1)
Example #13
0
def encapsulado(id):
    #Importamos la libreria de kyber
    from pqcrypto.kem.kyber512 import generate_keypair, encrypt, decrypt
    #recibimos la public key
    public_key = sock.recv(800)
    #Se realiza el encapsulado y se obtenemos el CT y el PT
    ciphertext, plaintext_original = encrypt(public_key)
    #Enviamos el CT
    sock.sendall(ciphertext)
    #Concatenamos el CT con el ID del cliente
    ct_hash = ciphertext + id
    #Realizamos el hash al CT con el ID
    hash = SHA256.new()
    hash.update(ct_hash)
    ct_hash = hash.digest()
    #Enviamos el hash
    sock.sendall(ct_hash)
    #data = sock.recv(1024)
    #print(len(data))
    #print(compare_digest(plaintext_original, data))
    #time.sleep(1)
    #salt = b'1234567891123456'
    #con una funcion KDF se obtiene una llave a traves del PT y el hash
    key = scrypt(plaintext_original, ct_hash, 16, N=2**14, r=8, p=1)
    return key, ct_hash[0:16]
Example #14
0
 def _password_expansion(salt_ghid, password, hardness=None):
     ''' Expands the author's ghid and password into a master key for
     use in generating specific keys.
     
     Hardness allows you to modify the scrypt inflation parameter. It
     defaults to something resembling a reasonable general-purpose 
     value for 2016.
     '''
     # Use 2**14 for t<=100ms, 2**20 for t<=5s.
     if hardness is None:
         hardness = _DEFAULT_SCRYPT_HARDNESS
     else:
         hardness = int(hardness)
     
     # Scrypt the password. Salt against the author GHID.
     combined = scrypt(
         password = password, 
         salt = bytes(salt_ghid),
         key_len = 48,
         N = hardness,
         r = 8,
         p = 1
     )
     key = combined[0:32]
     seed = combined[32:48]
     master_secret = Secret(
         cipher = 1, 
         version = 'latest',
         key = key,
         seed = seed
     )
     return master_secret
Example #15
0
def decryptPayload(passwd: bytes, salt: bytes, iv: bytes, payload: bytes):
    key = scrypt(password=passwd, salt=salt, N=(2**14), key_len=32, r=8, p=1)
    cipher = ChaCha20.new(key=key, nonce=iv)
    rv = cipher.decrypt(payload)
    print(payload)
    # print(rv)
    return rv.decode(encoding='UTF-8')
Example #16
0
    def _password_expansion(salt_ghid, password, hardness=None):
        ''' Expands the author's ghid and password into a master key for
        use in generating specific keys.
        
        Hardness allows you to modify the scrypt inflation parameter. It
        defaults to something resembling a reasonable general-purpose 
        value for 2016.
        '''
        # Use 2**14 for t<=100ms, 2**20 for t<=5s.
        if hardness is None:
            hardness = _DEFAULT_SCRYPT_HARDNESS
        else:
            hardness = int(hardness)

        # Scrypt the password. Salt against the author GHID.
        combined = scrypt(password=password,
                          salt=bytes(salt_ghid),
                          key_len=48,
                          N=hardness,
                          r=8,
                          p=1)
        key = combined[0:32]
        seed = combined[32:48]
        master_secret = Secret(cipher=1, version='latest', key=key, seed=seed)
        return master_secret
Example #17
0
    def decryptFile(self, path, data=None):
        path = self.clientAddress + '/' + path

        # parse a given file if data is empty
        if data == None:
            file_in = open(path, 'rb')
            salt, nonce, tag, ciphertext = \
                [file_in.read(x)
                 for x in (16, 16, 16, -1)]
            file_in.close()

        # read in data if given
        else:
            salt, nonce, tag, ciphertext = \
                [data[x:x+16]
                 for x in (0, 16, 32, -1)]
            ciphertext = data[48:]

        # Generate file key from given filePassword
        fileKey = scrypt(self.filePassword.encode('utf-8'),
                         salt,
                         16,
                         N=2**20,
                         r=8,
                         p=1)

        # Decrypt the data with the file key
        cipher_aes = AES.new(fileKey, AES.MODE_GCM, nonce)
        data = cipher_aes.decrypt_and_verify(ciphertext, tag)
        with open(path, 'wb') as f:
            f.write(data)
Example #18
0
    def Scrypt(password: Union[bytes, str], salt: Union[bytes, str],
               key_len: int, n: int, r: int, p: int) -> bytes:
        """
        Compute the scrypt of the specified password, using the specified parameters.

        Args:
            password (str or bytes): Password
            salt (str or bytes)    : Salt
            key_len (int)          : Length of the derived key
            n (int)                : CPU/Memory cost parameter
            r (int)                : Block size parameter
            p (int)                : Parallelization parameter

        Returns:
            bytes: Computed scrypt
        """

        # Type for password and salt should be Union[bytes, str] in pycryptodome but it's only str,
        # so we ignore the mypy warning
        return scrypt(
            AlgoUtils.Encode(password),  # type: ignore
            AlgoUtils.Encode(salt),  # type: ignore
            key_len=key_len,
            N=n,
            r=r,
            p=p)
Example #19
0
def decrypt_AES(input_filename, password):
    # The decrypted file
    # output_filename = os.path.splitext(filename)[0]
    output_filename = input_filename.replace('.encrypted', '')

    # Open files
    file_in = open(input_filename, 'rb')
    file_out = open(output_filename, 'wb')

    # Read salt and generate key
    salt = file_in.read(32)  # The salt we generated was 32 bits long

    key = scrypt(password, salt, key_len=32, N=2**17, r=8,
                 p=1)  # Generate a key using the password and salt again

    # Read nonce and create cipher
    nonce = file_in.read(16)  # The nonce is 16 bytes long
    cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)

    # Identify how many bytes of encrypted there is
    # We know that the salt (32) + the nonce (16) + the data (?) + the tag (16) is in the file
    # So some basic algebra can tell us how much data we need to read to decrypt
    file_in_size = os.path.getsize(input_filename)
    encrypted_data_size = file_in_size - 32 - 16 - 16  # Total - salt - nonce - tag = encrypted data

    # Read, decrypt and write the data
    for _ in range(
            int(encrypted_data_size / BUFFER_SIZE)
    ):  # Identify how many loops of full buffer reads we need to do
        data = file_in.read(
            BUFFER_SIZE)  # Read in some data from the encrypted file
        decrypted_data = cipher.decrypt(data)  # Decrypt the data
        file_out.write(
            decrypted_data)  # Write the decrypted data to the output file

    data = file_in.read(
        int(encrypted_data_size % BUFFER_SIZE
            ))  # Read whatever we have calculated to be left of encrypted data

    decrypted_data = cipher.decrypt(data)  # Decrypt the data
    file_out.write(
        decrypted_data)  # Write the decrypted data to the output file

    # Verify encrypted file was not tampered with
    tag = file_in.read(16)

    try:
        cipher.verify(tag)
    except ValueError as e:
        # If we get a ValueError, there was an error when decrypting so we delete the file we created
        file_in.close()
        file_out.close()
        os.remove(output_filename)
        raise e

    # If everything is okay, we close the files

    file_in.close()
    file_out.close()
Example #20
0
	def encrypt_bytes(self, plain_text):
		salt = get_random_bytes(8);
		key = scrypt(self.password, salt=salt, key_len=self.key_len//8, N=16384, r=8, p=1);
		nonce = get_random_bytes(16);
		cipher = AES.new(key=key, mode=AES.MODE_GCM, nonce=nonce, mac_len=16);
		cipher.update(b'WozMit');
		ciphertext, tag = cipher.encrypt_and_digest(plain_text);
		return (self.key_len//64).to_bytes(1, byteorder='big') + salt + nonce + tag + ciphertext;
Example #21
0
    def encryption_key(self, salt=None):
        if not salt:
            self.salt = os.urandom(self.salt_size)
        else:
            self.salt = salt

        key = scrypt(self.password, self.salt, self.key_size, N=2**15, r=8, p=1)
        return key
def generate_scrypt_key(password, salt, key_length):
    ##return bytes of keys, returns list in case of keys > 1
    ##returns hex encoded salt and key byte array
    logger.debug(
        f"Generating scrypt key with {password} and salt {salt}, with keylength {N}, R {R} and p {P}"
    )

    keys = scrypt(password, salt, key_length, N, R, P, 1)
    return keys, salt
Example #23
0
def _utc_kdf_scrypt(pwd: bytes, kdf_params: Dict) -> bytes:
    """
    Derive key using Scrypt. Accept KDF params from Ether UTC file.
    """
    # Convert salt from HEX to binary data
    salt = binascii.unhexlify(kdf_params["salt"])
    dklen = kdf_params["dklen"]
    N, r, p = kdf_params["n"], kdf_params["r"], kdf_params["p"]
    # Get derived key
    return scrypt(pwd, salt, key_len=dklen, N=N, r=r, p=p, num_keys=1)
Example #24
0
    def test2(self):
        for tv in self.data:

            # TODO: add runtime flag to enable test vectors
            # with humongous memory usage
            if tv.N > 100000:
                continue

            output = scrypt(tv.P, tv.S, tv.dkLen, tv.N, tv.r, tv.p)
            self.assertEqual(output, tv.output)
Example #25
0
def getCrypter(keyRaw, kdfSalt, nonce):
    ''' (bytes, bytes, bytes) -> ChaCha20_Poly1305
    Derives the encryption key from provided parameters
    Sets up and returns a ChaCha20_Poly1305 instance
    '''

    keyDerived = scrypt(password = keyRaw, salt = kdfSalt, key_len = 32, \
    N = SCRYPT_ITER, r=8, p=1)

    return ChaCha20_Poly1305.new(key = keyDerived, nonce = nonce)
Example #26
0
def make_password(value, salt=None):
    salt = salt or get_random_string(32)
    password_hash = scrypt(password=value,
                           salt=salt,
                           key_len=32,
                           N=16384,
                           r=8,
                           p=1)
    password_encoded = base64.b64encode(password_hash)
    return f'{salt}${password_encoded.decode()}'
Example #27
0
def encrypt(pt, password):
    salt = get_random_bytes(32)
    key = scrypt(password, salt, key_len=32, N=2**20, r=8, p=1)
    nonce = get_random_bytes(12)
    cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)
    ct, tag = cipher.encrypt_and_digest(pt)
    json_k = ["nonce", "salt", "ct", "tag"]
    json_v = [b64encode(x).decode("utf-8") for x in (nonce, salt, ct, tag)]
    result = json.dumps(dict(zip(json_k, json_v)))

    return result
Example #28
0
 def getPrivateKey(self, path):
     with open(path, 'rb') as f:
         salt, nonce, tag, ciphertext = \
             [f.read(x)
              for x in (16, 16, 16, -1)]
     fileKey = scrypt(self.password.encode('utf-8'),
                     salt, 16, N=2**20, r=8, p=1)
     cipher_aes = AES.new(fileKey, AES.MODE_GCM, nonce)
     rsaKey = cipher_aes.decrypt_and_verify(ciphertext, tag)
     self.serverRSAprivate = RSA.import_key(rsaKey)
     print("Key Loaded")
Example #29
0
def get_data_key(shared_secret, server_random) -> str:

    d_key_length = 64
    #based on Colin Percival suggested choice of Parameters for scrypt in 2009
    # since data key will be used for repo(file) encryption we use N = 2^20
    # print('Scripting...')
    data_key = scrypt(shared_secret, server_random, key_len=d_key_length, N=2**20, r=8, p=1)
    # print('Done Scripting....')
    dk_obj = SHA256.new(data_key)

    return dk_obj.hexdigest()
Example #30
0
def _scrypt_hash(password, salt, n, r, p, buflen):
    derived_key = scrypt(
        password,
        salt=salt,
        key_len=buflen,
        N=n,
        r=r,
        p=p,
        num_keys=1,
    )
    return derived_key
Example #31
0
def encrypt(plaintext: str, key: str) -> str:
    """
    encrypt text using AES256 GCM and return output in base64
    """
    salt = get_random_bytes(16)
    secret_key = scrypt(key, str(salt), key_len=32, N=2**17, r=8, p=1)
    cipher = AES.new(secret_key, AES.MODE_GCM)
    cipher_text, auth_tag = cipher.encrypt_and_digest(
        bytes(plaintext, encoding="utf-8"))
    encrypted_bytes = b"".join([salt, cipher.nonce, auth_tag, cipher_text])

    return b64encode(encrypted_bytes).decode("utf-8")
Example #32
0
def compute_c(key, p_u, P_u, P_s):
    """
    Cette methode va concatener certaines infos généré pour un certain client puis le chiffrer.
    On utilise AES et HMAC, de ce fait il nous faut deux clés. On va donc utiliser une KDF.
    :param key: master key qui sera utilisé pour générer les autres clés
    :return: le text chiffré ainsi que le mac
    """

    # KDF on calcule une fois avec 0 et une fois avec 1. Pour le sel la documentation
    # conseille quelque chose d'une longueur de 16bytes qui n'a pas besoin d'être secret
    # c'est pourquoi j'ai choisi de prendre le SSID car le client doit aussi connaitre le sel
    key_aes = scrypt('\x00'.encode() + key, SSID, 32, N=2 ** 14, r=8, p=1)
    key_hmac = scrypt('\x01'.encode() + key, SSID, 32, N=2 ** 14, r=8, p=1)

    cipher = AES.new(key_aes, AES.MODE_CTR, nonce=bytearray(1))
    # On concatène avec des séparateurs les datas que on veut chiffrer pour pouvoir les récuperer après
    data = str(p_u) + ";" + str(P_u[0]) + "," + str(P_u[1]) + ";" + str(P_s[0]) + "," + str(P_s[1])
    c = cipher.encrypt(data.encode())
    h = HMAC.new(key_hmac, digestmod=SHA256)
    h.update(c)
    return b2a_hex(c), h.hexdigest()
Example #33
0
    def test2(self):

        for tv in self.data:
            try:
                output = scrypt(tv.P, tv.S, tv.dkLen, tv.N, tv.r, tv.p)
            except ValueError as e:
                if " 2 " in str(e) and tv.N >= 1048576:
                    import warnings
                    warnings.warn("Not enough memory to unit test scrypt() with N=1048576", RuntimeWarning)
                    continue
                else:
                    raise e
            self.assertEqual(output, tv.output)
Example #34
0
 def _make_password_validator(secret, hardness=None):
     ''' Re-scrypts the key (should be the scrypt expansion of the
     password) with hardness, and then compares the result against
     check_str. If wrong, raises ValueError for a bad password (and
     logs as such).
     '''
     if hardness is None:
         hardness = _DEFAULT_SCRYPT_HARDNESS
     else:
         hardness = int(hardness)
         
     checker = scrypt(
         password = secret.key,
         salt = bytes(_PASSWORD_VALIDATOR_LEN),
         key_len = _PASSWORD_VALIDATOR_LEN,
         N = hardness,
         r = 8,
         p = 1
     )
     return checker
Example #35
0
    def decrypt(data, passphrase):
        """Decrypt a piece of data using a passphrase and *PBES2*.

        The algorithm to use is automatically detected.

        :Parameters:
          data : byte string
            The piece of data to decrypt.
          passphrase : byte string
            The passphrase to use for decrypting the data.
        :Returns:
          The decrypted data, as a binary string.
        """

        enc_private_key_info = DerSequence().decode(data, nr_elements=2)
        enc_algo = DerSequence().decode(enc_private_key_info[0])
        encrypted_data = DerOctetString().decode(enc_private_key_info[1]).payload

        pbe_oid = DerObjectId().decode(enc_algo[0]).value
        if pbe_oid != _OID_PBES2:
            raise PbesError("Not a PBES2 object")

        pbes2_params = DerSequence().decode(enc_algo[1], nr_elements=2)

        ### Key Derivation Function selection
        kdf_info = DerSequence().decode(pbes2_params[0], nr_elements=2)
        kdf_oid = DerObjectId().decode(kdf_info[0]).value

        kdf_key_length = None

        # We only support PBKDF2 or scrypt
        if kdf_oid == _OID_PBKDF2:

            pbkdf2_params = DerSequence().decode(kdf_info[1], nr_elements=(2, 3, 4))
            salt = DerOctetString().decode(pbkdf2_params[0]).payload
            iteration_count = pbkdf2_params[1]

            left = len(pbkdf2_params) - 2
            idx = 2

            if left > 0:
                try:
                    kdf_key_length = pbkdf2_params[idx] - 0
                    left -= 1
                    idx += 1
                except TypeError:
                    pass

            # Default is HMAC-SHA1
            pbkdf2_prf_oid = "1.2.840.113549.2.7"
            if left > 0:
                pbkdf2_prf_algo_id = DerSequence().decode(pbkdf2_params[idx])
                pbkdf2_prf_oid = DerObjectId().decode(pbkdf2_prf_algo_id[0]).value

        elif kdf_oid == _OID_SCRYPT:

            scrypt_params = DerSequence().decode(kdf_info[1], nr_elements=(4, 5))
            salt = DerOctetString().decode(scrypt_params[0]).payload
            iteration_count, scrypt_r, scrypt_p = [scrypt_params[x]
                                                   for x in (1, 2, 3)]
            if len(scrypt_params) > 4:
                kdf_key_length = scrypt_params[4]
            else:
                kdf_key_length = None
        else:
            raise PbesError("Unsupported PBES2 KDF")

        ### Cipher selection
        enc_info = DerSequence().decode(pbes2_params[1])
        enc_oid = DerObjectId().decode(enc_info[0]).value

        if enc_oid == _OID_DES_EDE3_CBC:
            # DES_EDE3_CBC
            ciphermod = DES3
            key_size = 24
        elif enc_oid == _OID_AES128_CBC:
            # AES128_CBC
            ciphermod = AES
            key_size = 16
        elif enc_oid == _OID_AES192_CBC:
            # AES192_CBC
            ciphermod = AES
            key_size = 24
        elif enc_oid == _OID_AES256_CBC:
            # AES256_CBC
            ciphermod = AES
            key_size = 32
        else:
            raise PbesError("Unsupported PBES2 cipher")

        if kdf_key_length and kdf_key_length != key_size:
            raise PbesError("Mismatch between PBES2 KDF parameters"
                            " and selected cipher")

        IV = DerOctetString().decode(enc_info[1]).payload

        # Create cipher
        if kdf_oid == _OID_PBKDF2:
            if pbkdf2_prf_oid == _OID_HMAC_SHA1:
                hmac_hash_module = SHA1
            elif pbkdf2_prf_oid == _OID_HMAC_SHA224:
                hmac_hash_module = SHA224
            elif pbkdf2_prf_oid == _OID_HMAC_SHA256:
                hmac_hash_module = SHA256
            elif pbkdf2_prf_oid == _OID_HMAC_SHA384:
                hmac_hash_module = SHA384
            elif pbkdf2_prf_oid == _OID_HMAC_SHA512:
                hmac_hash_module = SHA512
            else:
                raise PbesError("Unsupported HMAC %s" % pbkdf2_prf_oid)

            key = PBKDF2(passphrase, salt, key_size, iteration_count,
                         hmac_hash_module=hmac_hash_module)
        else:
            key = scrypt(passphrase, salt, key_size, iteration_count,
                         scrypt_r, scrypt_p)
        cipher = ciphermod.new(key, ciphermod.MODE_CBC, IV)

        # Decrypt data
        pt = cipher.decrypt(encrypted_data)
        return unpad(pt, cipher.block_size)
Example #36
0
    def encrypt(data, passphrase, protection, prot_params=None, randfunc=None):
        """Encrypt a piece of data using a passphrase and *PBES2*.

        :Parameters:
          data : byte string
            The piece of data to encrypt.
          passphrase : byte string
            The passphrase to use for encrypting the data.
          protection : string
            The identifier of the encryption algorithm to use.
            The default value is '``PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC``'.
          prot_params : dictionary
            Parameters of the protection algorithm.

            +------------------+-----------------------------------------------+
            | Key              | Description                                   |
            +==================+===============================================+
            | iteration_count  | The KDF algorithm is repeated several times to|
            |                  | slow down brute force attacks on passwords    |
            |                  | (called *N* or CPU/memory cost in scrypt).    |
            |                  |                                               |
            |                  | The default value for PBKDF2 is 1 000.        |
            |                  | The default value for scrypt is 16 384.       |
            +------------------+-----------------------------------------------+
            | salt_size        | Salt is used to thwart dictionary and rainbow |
            |                  | attacks on passwords. The default value is 8  |
            |                  | bytes.                                        |
            +------------------+-----------------------------------------------+
            | block_size       | *(scrypt only)* Memory-cost (r). The default  |
            |                  | value is 8.                                   |
            +------------------+-----------------------------------------------+
            | parallelization  | *(scrypt only)* CPU-cost (p). The default     |
            |                  | value is 1.                                   |
            +------------------+-----------------------------------------------+


          randfunc : callable
            Random number generation function; it should accept
            a single integer N and return a string of random data,
            N bytes long. If not specified, a new RNG will be
            instantiated from ``Crypto.Random``.

        :Returns:
          The encrypted data, as a binary string.
        """

        if prot_params is None:
            prot_params = {}

        if randfunc is None:
            randfunc = Random.new().read

        if protection == 'PBKDF2WithHMAC-SHA1AndDES-EDE3-CBC':
            key_size = 24
            module = DES3
            cipher_mode = DES3.MODE_CBC
            enc_oid = "1.2.840.113549.3.7"
        elif protection in ('PBKDF2WithHMAC-SHA1AndAES128-CBC',
                'scryptAndAES128-CBC'):
            key_size = 16
            module = AES
            cipher_mode = AES.MODE_CBC
            enc_oid = "2.16.840.1.101.3.4.1.2"
        elif protection in ('PBKDF2WithHMAC-SHA1AndAES192-CBC',
                'scryptAndAES192-CBC'):
            key_size = 24
            module = AES
            cipher_mode = AES.MODE_CBC
            enc_oid = "2.16.840.1.101.3.4.1.22"
        elif protection in ('PBKDF2WithHMAC-SHA1AndAES256-CBC',
                'scryptAndAES256-CBC'):
            key_size = 32
            module = AES
            cipher_mode = AES.MODE_CBC
            enc_oid = "2.16.840.1.101.3.4.1.42"
        else:
            raise ValueError("Unknown PBES2 mode")

        # Get random data
        iv = randfunc(module.block_size)
        salt = randfunc(prot_params.get("salt_size", 8))

        # Derive key from password
        if protection.startswith('PBKDF2'):
            count = prot_params.get("iteration_count", 1000)
            key = PBKDF2(passphrase, salt, key_size, count)
            key_derivation_func = newDerSequence(
                    DerObjectId("1.2.840.113549.1.5.12"),   # PBKDF2
                    newDerSequence(
                        DerOctetString(salt),
                        DerInteger(count)
                    )
            )
        else:
            # It must be scrypt
            count = prot_params.get("iteration_count", 16384)
            scrypt_r = prot_params.get('block_size', 8)
            scrypt_p = prot_params.get('parallelization', 1)
            key = scrypt(passphrase, salt, key_size,
                         count, scrypt_r, scrypt_p)
            key_derivation_func = newDerSequence(
                    DerObjectId("1.3.6.1.4.1.11591.4.11"),  # scrypt
                    newDerSequence(
                        DerOctetString(salt),
                        DerInteger(count),
                        DerInteger(scrypt_r),
                        DerInteger(scrypt_p)
                    )
            )

        # Create cipher and use it
        cipher = module.new(key, cipher_mode, iv)
        encrypted_data = cipher.encrypt(pad(data, cipher.block_size))
        encryption_scheme = newDerSequence(
                DerObjectId(enc_oid),
                DerOctetString(iv)
        )

        # Result
        encrypted_private_key_info = newDerSequence(
            # encryptionAlgorithm
            newDerSequence(
                DerObjectId("1.2.840.113549.1.5.13"),   # PBES2
                newDerSequence(
                    key_derivation_func,
                    encryption_scheme
                ),
            ),
            DerOctetString(encrypted_data)
        )
        return encrypted_private_key_info.encode()
Example #37
0
    def decrypt(data, passphrase):
        """Decrypt a piece of data using a passphrase and *PBES2*.

        The algorithm to use is automatically detected.

        :Parameters:
          data : byte string
            The piece of data to decrypt.
          passphrase : byte string
            The passphrase to use for decrypting the data.
        :Returns:
          The decrypted data, as a binary string.
        """

        encrypted_private_key_info = decode_der(DerSequence, data)
        encryption_algorithm = decode_der(
                                DerSequence,
                                encrypted_private_key_info[0]
                                )
        encrypted_data = decode_der(
                            DerOctetString,
                            encrypted_private_key_info[1]
                            ).payload

        pbe_oid = decode_der(DerObjectId, encryption_algorithm[0]).value
        if pbe_oid != "1.2.840.113549.1.5.13":
            raise PbesError("Not a PBES2 object")

        pbes2_params = decode_der(DerSequence, encryption_algorithm[1])

        ### Key Derivation Function selection
        key_derivation_func = decode_der(DerSequence, pbes2_params[0])
        key_derivation_oid = decode_der(
                                DerObjectId,
                                key_derivation_func[0]
                                ).value

        # We only support PBKDF2 or scrypt
        if key_derivation_oid == "1.2.840.113549.1.5.12":

            pbkdf2_params = decode_der(DerSequence, key_derivation_func[1])
            salt = decode_der(DerOctetString, pbkdf2_params[0]).payload
            iteration_count = pbkdf2_params[1]
            if len(pbkdf2_params) > 2:
                kdf_key_length = pbkdf2_params[2]
            else:
                kdf_key_length = None
            if len(pbkdf2_params) > 3:
                raise PbesError("Unsupported PRF for PBKDF2")

        elif key_derivation_oid == "1.3.6.1.4.1.11591.4.11":

            scrypt_params = decode_der(DerSequence, key_derivation_func[1])
            salt = decode_der(DerOctetString, scrypt_params[0]).payload
            iteration_count, scrypt_r, scrypt_p = [scrypt_params[x]
                                                   for x in (1, 2, 3)]
            if len(scrypt_params) > 4:
                kdf_key_length = scrypt_params[4]
            else:
                kdf_key_length = None
        else:
            raise PbesError("Unsupported PBES2 KDF")

        ### Cipher selection
        encryption_scheme = decode_der(DerSequence, pbes2_params[1])
        encryption_oid = decode_der(
                            DerObjectId,
                            encryption_scheme[0]
                            ).value

        if encryption_oid == "1.2.840.113549.3.7":
            # DES_EDE3_CBC
            ciphermod = DES3
            key_size = 24
        elif encryption_oid == "2.16.840.1.101.3.4.1.2":
            # AES128_CBC
            ciphermod = AES
            key_size = 16
        elif encryption_oid == "2.16.840.1.101.3.4.1.22":
            # AES192_CBC
            ciphermod = AES
            key_size = 24
        elif encryption_oid == "2.16.840.1.101.3.4.1.42":
            # AES256_CBC
            ciphermod = AES
            key_size = 32
        else:
            raise PbesError("Unsupported PBES2 cipher")

        if kdf_key_length and kdf_key_length != key_size:
            raise PbesError("Mismatch between PBES2 KDF parameters"
                            " and selected cipher")

        IV = decode_der(DerOctetString, encryption_scheme[1]).payload

        # Create cipher
        if key_derivation_oid == "1.2.840.113549.1.5.12": # PBKDF2
            key = PBKDF2(passphrase, salt, key_size, iteration_count)
        else:
            key = scrypt(passphrase, salt, key_size, iteration_count,
                         scrypt_r, scrypt_p)
        cipher = ciphermod.new(key, ciphermod.MODE_CBC, IV)

        # Decrypt data
        pt = cipher.decrypt(encrypted_data)
        return unpad(pt, cipher.block_size)