Ejemplo n.º 1
0
 def extract_attributes(self, policy_str):
     util = SecretUtil(self.abe.group)
     policy = util.createPolicy(policy_str)
     return [
         util.strip_index(policy_attr)
         for policy_attr in util.getAttributeList(policy)
     ]
class MAABE(object):
    def __init__(self, groupObj):
        self.util = SecretUtil(groupObj,
                               verbose=False)  #Create Secret Sharing Scheme
        self.group = groupObj  #:Prime order group

    def setup(self):
        '''Global Setup (executed by CA)'''
        #:In global setup, a bilinear group G of prime order p is chosen
        #:The global public parameters, GP and p, and a generator g of G. A random oracle H maps global identities GID to elements of G

        #:group contains
        #:the prime order p is contained somewhere within the group object
        g = self.group.random(G1)
        #: The oracle that maps global identities GID onto elements of G
        #:H = lambda str: g** group.hash(str)
        H = lambda x: self.group.hash(x, G1)
        a = self.group.random()
        b = self.group.random()
        g_a = g**a
        g_b = g**b
        GPP = {'g': g, 'g_a': g_a, 'g_b': g_b, 'H': H}
        GMK = {'a': a, 'b': b}

        return (GPP, GMK)

    def registerUser(self, GPP):
        '''Generate user keys (executed by the user).'''
        g = GPP['g']
        ugsk1 = self.group.random()
        ugsk2 = self.group.random()
        ugpk1 = g**ugsk1
        ugpk2 = g**ugsk2

        return ((ugpk1, ugsk2), {
            'pk': ugpk2,
            'sk': ugsk1
        })  # (private, public)

    def setupAuthority(self, GPP, authorityid, attributes, authorities):
        '''Generate attribute authority keys (executed by attribute authority)'''
        if authorityid not in authorities:
            alpha = self.group.random()
            beta = self.group.random()
            gamma = self.group.random()
            SK = {'alpha': alpha, 'beta': beta, 'gamma': gamma}
            PK = {
                'e_alpha': pair(GPP['g'], GPP['g'])**alpha,
                'g_beta': GPP['g']**beta,
                'g_beta_inv': GPP['g']**~beta
            }
            authAttrs = {}
            authorities[authorityid] = (SK, PK, authAttrs)
        else:
            SK, PK, authAttrs = authorities[authorityid]
        for attrib in attributes:
            if attrib in authAttrs:
                continue
            versionKey = self.group.random()  # random or really 'choose' ?
            h = GPP['H'](attrib)
            pk = h**versionKey
            authAttrs[attrib] = {
                'VK': versionKey,  #secret
                'PK1': pk,  #public
                'PK2': pk**SK['gamma']  #public
            }
        return (SK, PK, authAttrs)

    def keygen(self, GPP, authority, attribute, userObj, USK=None):
        '''Generate user keys for a specific attribute (executed on attribute authority)'''
        if 't' not in userObj:
            userObj['t'] = self.group.random()  #private to AA
        t = userObj['t']

        ASK, APK, authAttrs = authority
        u = userObj
        if USK is None:
            USK = {}
        if 'K' not in USK or 'KS' not in USK or 'AK' not in USK:
            USK['K'] = \
                (GPP['g'] ** ASK['alpha']) * \
                (GPP['g_a'] ** u['sk']) * \
                (GPP['g_b'] ** t)
            USK['KS'] = GPP['g']**t
            USK['AK'] = {}
        AK = (u['pk'] ** (t * ASK['beta'])) * \
            ((authAttrs[attribute]['PK1'] ** ASK['beta']) ** (u['sk'] + ASK['gamma']))
        USK['AK'][attribute] = AK
        return USK

    def encrypt(self, GPP, policy_str, k, authority):
        '''Generate the cipher-text from the content(-key) and a policy (executed by the content owner)'''
        #GPP are global parameters
        #k is the content key (group element based on AES key)
        #policy_str is the policy string
        #authority is the authority tuple

        _, APK, authAttrs = authority

        policy = self.util.createPolicy(policy_str)
        secret = self.group.random()
        shares = self.util.calculateSharesList(secret, policy)
        shares = dict([(x[0].getAttributeAndIndex(), x[1]) for x in shares])

        C1 = k * (APK['e_alpha']**secret)
        C2 = GPP['g']**secret
        C3 = GPP['g_b']**secret
        C = {}
        CS = {}
        D = {}
        DS = {}

        for attr, s_share in shares.items():
            k_attr = self.util.strip_index(attr)
            r_i = self.group.random()
            attrPK = authAttrs[attr]
            C[attr] = (GPP['g_a']**s_share) * ~(attrPK['PK1']**r_i)
            CS[attr] = GPP['g']**r_i
            D[attr] = APK['g_beta_inv']**r_i
            DS[attr] = attrPK['PK2']**r_i

        return {
            'C1': C1,
            'C2': C2,
            'C3': C3,
            'C': C,
            'CS': CS,
            'D': D,
            'DS': DS,
            'policy': policy_str
        }

    def decrypt(self, GPP, CT, user):
        '''Decrypts the content(-key) from the cipher-text (executed by user/content consumer)'''
        UASK = user['authoritySecretKeys']
        USK = user['keys']
        usr_attribs = list(UASK['AK'].keys())
        policy = self.util.createPolicy(CT['policy'])
        pruned = self.util.prune(policy, usr_attribs)
        if pruned == False:
            return False
        coeffs = self.util.getCoefficients(policy)

        first = pair(CT['C2'], UASK['K']) * ~pair(CT['C3'], UASK['KS'])
        n_a = 1

        ugpk1, ugsk2 = USK
        e_gg_auns = 1

        for attr in pruned:
            x = attr.getAttributeAndIndex()
            y = attr.getAttribute()
            temp = \
                pair(CT['C'][y], ugpk1) * \
                pair(CT['D'][y], UASK['AK'][y]) * \
                pair(CT['CS'][y], ~(UASK['KS'] ** ugsk2)) * \
                ~pair(GPP['g'], CT['DS'][y])
            e_gg_auns *= temp**(coeffs[x] * n_a)
        return CT['C1'] / (first / e_gg_auns)

    def ukeygen(self, GPP, authority, attribute, userObj):
        '''Generate update keys for users and cloud provider (executed by attribute authority?)'''
        ASK, _, authAttrs = authority
        oldVersionKey = authAttrs[attribute]['VK']
        newVersionKey = oldVersionKey
        while oldVersionKey == newVersionKey:
            newVersionKey = self.group.random()
        authAttrs[attribute]['VK'] = newVersionKey

        u_uid = userObj['sk']
        UKs = GPP['H'](attribute)**(ASK['beta'] *
                                    (newVersionKey - oldVersionKey) *
                                    (u_uid + ASK['gamma']))
        UKc = (newVersionKey / oldVersionKey, (oldVersionKey - newVersionKey) /
               (oldVersionKey * ASK['gamma']))

        authAttrs[attribute]['PK1'] = authAttrs[attribute]['PK1']**UKc[0]
        authAttrs[attribute]['PK2'] = authAttrs[attribute]['PK2']**UKc[0]

        return {'UKs': UKs, 'UKc': UKc}

    def skupdate(self, USK, attribute, UKs):
        '''Updates the user attribute secret key for the specified attribute (executed by non-revoked user)'''
        USK['AK'][attribute] = USK['AK'][attribute] * UKs

    def ctupdate(self, GPP, CT, attribute, UKc):
        '''Updates the cipher-text using the update key, because of the revoked attribute (executed by cloud provider)'''
        CT['C'][attribute] = CT['C'][attribute] * (CT['DS'][attribute]**UKc[1])
        CT['DS'][attribute] = CT['DS'][attribute]**UKc[0]
Ejemplo n.º 3
0
class YLLC15(ABEnc):
    """
    Possibly a subclass of BSW07?
    """
    def __init__(self, group):
        ABEnc.__init__(self)
        self.group = group
        self.util = SecretUtil(self.group)

    @Output(params_t, msk_t)
    def setup(self):
        g, gp = self.group.random(G1), self.group.random(G2)
        alpha, beta = self.group.random(ZR), self.group.random(ZR)
        # initialize pre-processing for generators
        g.initPP()
        gp.initPP()

        h = g**beta
        e_gg_alpha = pair(g, gp**alpha)

        params = {'g': g, 'g2': gp, 'h': h, 'e_gg_alpha': e_gg_alpha}
        msk = {'beta': beta, 'alpha': alpha}
        return params, msk

    @Input(params_t)
    @Output(pku_t, sku_t)
    def ukgen(self, params):
        g2 = params['g2']
        x = self.group.random(ZR)
        pku = g2**x
        sku = x
        return pku, sku

    @Input(params_t, msk_t, pku_t, pku_t, [str])
    # @Output(pxku_t)
    def proxy_keygen(self, params, msk, pkcs, pku, attribute_list):
        """
        attributes specified in the `attribute_list` are converted to uppercase
        """
        r1 = self.group.random(ZR)
        r2 = self.group.random(ZR)
        g = params['g']
        g2 = params['g2']

        k = ((pkcs**r1) * (pku**msk['alpha']) * (g2**r2))**~msk['beta']
        k_prime = g2**r1
        k_attrs = {}
        for attr in attribute_list:
            attr_caps = attr.upper()
            r_attr = self.group.random(ZR)
            k_attr1 = (g2**r2) * (self.group.hash(str(attr_caps), G2)**r_attr)
            k_attr2 = g**r_attr
            k_attrs[attr_caps] = (k_attr1, k_attr2)

        proxy_key_user = {'k': k, 'k_prime': k_prime, 'k_attrs': k_attrs}
        return proxy_key_user

    @Input(params_t, GT, str)
    # @Output(ct_t)
    def encrypt(self, params, msg, policy_str):
        """
         Encrypt a message M under a policy string.

         attributes specified in policy_str are converted to uppercase
         policy_str must use parentheses e.g. (A) and (B)
        """
        policy = self.util.createPolicy(policy_str)
        s = self.group.random(ZR)
        shares = self.util.calculateSharesDict(s, policy)

        C = (params['e_gg_alpha']**s) * msg
        c_prime = params['h']**s
        c_prime_prime = params['g']**s

        c_attrs = {}
        for attr in shares.keys():
            attr_stripped = self.util.strip_index(attr)
            c_i1 = params['g']**shares[attr]
            c_i2 = self.group.hash(attr_stripped, G1)**shares[attr]
            c_attrs[attr] = (c_i1, c_i2)

        ciphertext = {
            'policy_str': policy_str,
            'C': C,
            'C_prime': c_prime,
            'C_prime_prime': c_prime_prime,
            'c_attrs': c_attrs
        }
        return ciphertext

    # @Input(sku_t, pxku_t, ct_t)
    @Output(v_t)
    def proxy_decrypt(self, skcs, proxy_key_user, ciphertext):
        policy_root_node = ciphertext['policy_str']
        k = proxy_key_user['k']
        k_prime = proxy_key_user['k_prime']
        c_prime = ciphertext['C_prime']
        c_prime_prime = ciphertext['C_prime_prime']
        c_attrs = ciphertext['c_attrs']
        k_attrs = proxy_key_user['k_attrs']

        policy = self.util.createPolicy(policy_root_node)
        attributes = proxy_key_user['k_attrs'].keys()
        pruned_list = self.util.prune(policy, attributes)
        if not pruned_list:
            return None
        z = self.util.getCoefficients(policy)
        # reconstitute the policy random secret (A) which was used to encrypt the message
        A = 1
        for i in pruned_list:
            attr_idx = i.getAttributeAndIndex()
            attr = i.getAttribute()
            A *= (pair(c_attrs[attr_idx][0], k_attrs[attr][0]) /
                  pair(k_attrs[attr][1], c_attrs[attr_idx][1]))**z[attr_idx]

        e_k_c_prime = pair(k, c_prime)
        denominator = (pair(k_prime, c_prime_prime)**skcs) * A
        encrypted_element_for_user_pkenc_scheme = e_k_c_prime / denominator

        intermediate_value = {
            'C': ciphertext['C'],
            'e_term': encrypted_element_for_user_pkenc_scheme
        }

        return intermediate_value

    @Input(type(None), sku_t, v_t)
    @Output(GT)
    def decrypt(self, params, sku, intermediate_value):
        """
        :param params: Not required - pass None instead. For interface compatibility only.
        :param sku: the secret key of the user as generated by `ukgen()`.
        :param intermediate_value: the partially decrypted ciphertext returned by `proxy_decrypt()`.
        :return: the plaintext message
        """
        ciphertext = intermediate_value['C']
        e_term = intermediate_value['e_term']
        denominator = e_term**(sku**-1)
        msg = ciphertext / denominator
        return msg
Ejemplo n.º 4
0
class DACMACS(object):
    def __init__(self, groupObj):
        self.util = SecretUtil(groupObj,
                               verbose=False)  #Create Secret Sharing Scheme
        self.group = groupObj  #:Prime order group

    def setup(self):
        '''Global Setup (executed by CA)'''
        #:In global setup, a bilinear group G of prime order p is chosen
        #:The global public parameters, GP and p, and a generator g of G. A random oracle H maps global identities GID to elements of G

        #:group contains
        #:the prime order p is contained somewhere within the group object
        g = self.group.random(G1)
        #: The oracle that maps global identities GID onto elements of G
        #:H = lambda str: g** group.hash(str)
        H = lambda x: self.group.hash(x, G1)
        a = self.group.random()
        g_a = g**a
        GPP = {'g': g, 'g_a': g_a, 'H': H}
        GMK = {'a': a}

        return (GPP, GMK)

    def registerUser(self, GPP):
        '''Generate user keys (executed by the user).'''
        g = GPP['g']
        u = self.group.random()
        z = self.group.random()
        g_u = g**u
        g_z = g**(1 / z)

        return ((g_u, z), {'g_z': g_z, 'u': u})  # (private, public)

    def setupAuthority(self, GPP, authorityid, attributes, authorities):
        '''Generate attribute authority keys (executed by attribute authority)'''
        if authorityid not in authorities:
            alpha = self.group.random()
            beta = self.group.random()
            gamma = self.group.random()
            SK = {'alpha': alpha, 'beta': beta, 'gamma': gamma}
            PK = {
                'e_alpha': pair(GPP['g'], GPP['g'])**alpha,
                'g_beta_inv': GPP['g']**(1 / beta),
                'g_beta_gamma': GPP['g']**(gamma / beta)
            }
            authAttrs = {}
            authorities[authorityid] = (SK, PK, authAttrs)
        else:
            SK, PK, authAttrs = authorities[authorityid]
        for attrib in attributes:
            if attrib in authAttrs:
                continue
            versionKey = self.group.random()  # random or really 'choose' ?
            h = GPP['H'](attrib)
            pk = ((GPP['g']**versionKey) * h)**SK['gamma']
            authAttrs[attrib] = {
                'VK': versionKey,  #secret
                'PK': pk,  #public
            }
        return (SK, PK, authAttrs)

    def keygen(self, GPP, authority, attribute, userObj, USK=None):
        '''Generate user keys for a specific attribute (executed on attribute authority)'''
        if 't' not in userObj:
            userObj['t'] = self.group.random()  #private to AA
        t = userObj['t']

        ASK, APK, authAttrs = authority
        u = userObj
        if USK is None:
            USK = {}
        if 'K' not in USK or 'L' not in USK or 'R' not in USK or 'AK' not in USK:
            USK['K'] = \
                (u['g_z'] ** ASK['alpha']) * \
                (GPP['g_a'] ** u['u']) * \
                (GPP['g_a'] ** (t / ASK['beta']))
            USK['L'] = u['g_z']**(ASK['beta'] * t)
            USK['R'] = GPP['g_a']**t
            USK['AK'] = {}
        AK = (u['g_z'] ** (ASK['beta'] * ASK['gamma'] * t)) * \
            (authAttrs[attribute]['PK'] ** (ASK['beta'] * u['u']))
        USK['AK'][attribute] = AK
        return USK

    def encrypt(self, GPP, policy_str, k, authority):
        '''Generate the cipher-text from the content(-key) and a policy (executed by the content owner)'''
        #GPP are global parameters
        #k is the content key (group element based on AES key)
        #policy_str is the policy string
        #authority is the authority tuple

        _, APK, authAttrs = authority

        policy = self.util.createPolicy(policy_str)
        secret = self.group.random()
        shares = self.util.calculateSharesList(secret, policy)
        shares = dict([(x[0].getAttributeAndIndex(), x[1]) for x in shares])

        C1 = k * (APK['e_alpha']**secret)
        C2 = GPP['g']**secret
        C3 = APK['g_beta_inv']**secret
        C = {}
        D = {}
        DS = {}

        for attr, s_share in shares.items():
            k_attr = self.util.strip_index(attr)
            r_i = self.group.random()
            attrPK = authAttrs[attr]
            C[attr] = (GPP['g_a']**s_share) * ~(attrPK['PK']**r_i)
            D[attr] = APK['g_beta_inv']**r_i
            DS[attr] = ~(APK['g_beta_gamma']**r_i)

        return {
            'C1': C1,
            'C2': C2,
            'C3': C3,
            'C': C,
            'D': D,
            'DS': DS,
            'policy': policy_str
        }

    def generateTK(self, GPP, CT, UASK, g_u):
        '''Generates a token using the user's attribute secret keys to offload the decryption process (executed by cloud provider)'''
        usr_attribs = list(UASK['AK'].keys())
        policy = self.util.createPolicy(CT['policy'])
        pruned = self.util.prune(policy, usr_attribs)
        if pruned == False:
            return False
        coeffs = self.util.getCoefficients(policy)

        dividend = pair(CT['C2'], UASK['K']) * ~pair(UASK['R'], CT['C3'])
        n_a = 1
        divisor = 1

        for attr in pruned:
            x = attr.getAttributeAndIndex()
            y = attr.getAttribute()
            temp = \
                pair(CT['C'][y], g_u) * \
                pair(CT['D'][y], UASK['AK'][y]) * \
                pair(CT['DS'][y], UASK['L'])
            divisor *= temp**(coeffs[x] * n_a)
        return dividend / divisor

    def decrypt(self, CT, TK, z):
        '''Decrypts the content(-key) from the cipher-text using the token and the user secret key (executed by user/content consumer)'''
        return CT['C1'] / (TK**z)

    def ukeygen(self, GPP, authority, attribute, userObj):
        '''Generate update keys for users and cloud provider (executed by attribute authority?)'''
        ASK, _, authAttrs = authority
        oldVersionKey = authAttrs[attribute]['VK']
        newVersionKey = oldVersionKey
        while oldVersionKey == newVersionKey:
            newVersionKey = self.group.random()
        authAttrs[attribute]['VK'] = newVersionKey

        u = userObj['u']

        AUK = ASK['gamma'] * (newVersionKey - oldVersionKey)
        KUK = GPP['g']**(u * ASK['beta'] * AUK)
        CUK = ASK['beta'] * AUK / ASK['gamma']

        authAttrs[attribute]['PK'] = authAttrs[attribute]['PK'] * (GPP['g']**
                                                                   AUK)

        return {'KUK': KUK, 'CUK': CUK}

    def skupdate(self, USK, attribute, KUK):
        '''Updates the user attribute secret key for the specified attribute (executed by non-revoked user)'''
        USK['AK'][attribute] = USK['AK'][attribute] * KUK

    def ctupdate(self, GPP, CT, attribute, CUK):
        '''Updates the cipher-text using the update key, because of the revoked attribute (executed by cloud provider)'''
        CT['C'][attribute] = CT['C'][attribute] * (CT['DS'][attribute]**CUK)
class OMACPABE(object):
    def __init__(self, group_object):
        # initialize class object with secret sharing utility
        # and appropriate group object
        self.util = SecretUtil(group_object, verbose=False)
        self.group = group_object

    # certificate authority (CA) setup function
    def abenc_casetup(self):
        """
        Global setup function run by the CA to generate the
        Global Master Key (GMK) and the Global Public Parameters (GPP)

        :return: GMK, GPP
        """
        # initialize bilinear group G of prime p with generator g
        g = self.group.random(G1)
        # initialize hash function that maps to an element of G
        H = lambda x: self.group.hash(x, G1)
        # select random elements from Z_p
        a = self.group.random(ZR)
        b = self.group.random(ZR)

        g_a = g**a
        g_b = g**b

        # Global Public Parameters (GPP) = g, g_a, g_b, H
        GPP = {
            'g': g,
            'g_a': g_a,
            'g_b': g_b,
            'H': H,
        }

        # Global Master Key (GMK) = a, b
        GMK = {
            'a': a,
            'b': b,
        }
        #
        return (GPP, GMK)

    def abenc_userreg(self, GPP, entity='user'):
        """
        User registration by Certificate Authority (CA) to generate corresponding
        key pairs (i.e. Public and Private keys)

        :param GPP: Global Public Parameters (GPP)
        :param entity: the entity executing algorithm
        # :param registered_users: Dictionary of already registered users
        :return: User Global Secret and Public Keys (GSK_uid, GSK_uid_prime, GPK_uid, GPK_uid_prime)
        """
        # group generator from GPP
        g = GPP['g']
        # random numbers as user global secret keys
        u_uid = self.group.random(ZR)
        u_uid_prime = self.group.random(ZR)
        # user global public keys
        g_u_uid = g**u_uid
        g_u_uid_prime = g**(1 / u_uid_prime)

        # secret public key pair sent to user
        GSK_uid_prime = u_uid_prime
        GPK_uid = g_u_uid

        # secret public key pair to be sent to  registered Attribute Authorities (AAs)
        GSK_uid = u_uid
        GPK_uid_prime = g_u_uid_prime

        return (GPK_uid, GSK_uid_prime), {
            'GSK_uid': GSK_uid,
            'GPK_uid_prime': GPK_uid_prime,
            'u_uid': u_uid,
        }

    def abenc_aareg(self, GPP, authority_id, attributes,
                    registered_authorities):
        """
        Registration of Attribute Authorities (AA) by the Certificate Authority (CA)

        :param GPP: Global Public Parameters (GPP)
        :param authority_id: Unique ID for Attribute Authority
        :param attributes: Attributes managed by the authority
        :param registered_authorities: Dictionary of already registered authorities
        :return: Attribute Authority Secret and Public Key pairs with Version and Public keys for the attributes
        """
        # check if authority has already been registered
        if authority_id not in registered_authorities:
            # generate random values to serves as attribute authority secret key
            alpha_aid = self.group.random(ZR)
            beta_aid = self.group.random(ZR)
            gamma_aid = self.group.random(ZR)
            # attribute authority secret key values
            SK_aid = {
                'alpha_aid': alpha_aid,
                'beta_aid': beta_aid,
                'gamma_aid': gamma_aid
            }
            # attribute authority public key values
            PK_aid = {
                'e_alpha': pair(GPP['g'], GPP['g'])**alpha_aid,
                'g_beta_aid': GPP['g']**beta_aid,
                'g_beta_aid_inv': GPP['g']**(1 / beta_aid),
            }
            authority_attributes = {}
            registered_authorities[authority_id] = (SK_aid, PK_aid,
                                                    authority_attributes)
        else:
            SK_aid, PK_aid, authority_attributes = registered_authorities[
                authority_id]

        # generate version and public keys for attributes
        for attribute in attributes:
            # check if attributes already exist with public and version keys
            # if they do, skip generation process
            if attribute in authority_attributes:
                continue
            # generate random element as version key
            version_key = self.group.random(ZR)
            h = GPP['H'](attribute)
            PK_1_attribute = h**version_key
            PK_2_attribute = h**(version_key * SK_aid['gamma_aid'])
            PK_attribute_aid = [PK_1_attribute, PK_2_attribute]
            authority_attributes[attribute] = {
                'VK': version_key,
                'PK': PK_attribute_aid,
            }
        return (SK_aid, PK_aid, authority_attributes)

    def abenc_keygen(self, GPP, authority, attribute, user_object, USK=None):
        """
        Generate attribute authority related secret keys for users (executed by the corresponding attribute authority)

        :param GPP: Global Public Parameters
        :param authority: Attribute Authority Parameters
        :param attribute: Attribute for which secret key is being generated
        :param user_object: User
        :param USK: Generated attribute authority related user secret key
        :return: User Secret Key (USK)
        """
        # generate random integer to tie attribute secret key to user
        if 't' not in user_object:
            user_object['t'] = self.group.random(ZR)
        t = user_object['t']

        # assign corresponding attribute authority parameters
        ASK, APK, authority_attrs = authority

        u = user_object

        # create USK data set if none exists already
        if USK is None:
            USK = {}

        if 'K_uid_aid' not in USK or 'K_uid_aid_prime' not in USK or 'AK_uid_aid' not in USK:
            USK['K_uid_aid'] = (u['GPK_uid_prime']**ASK['alpha_aid']) * (
                GPP['g_a']**u['u_uid']) * (GPP['g_b']**t)
            USK['K_uid_aid_prime'] = GPP['g']**t
            USK['AK_uid_aid'] = {}

        # generate attribute specific secret key parameters
        AK_uid_aid = (GPP['g'] ** (t * ASK['beta_aid'])) * authority_attrs[attribute]['PK'][0] \
            ** (ASK['beta_aid'] * (u['u_uid'] + ASK['gamma_aid']))
        USK['AK_uid_aid'][attribute] = AK_uid_aid

        return USK

    def abenc_encrypt(self, GPP, policy_string, k, authority):
        """
        Encryption algorithm which encrypts the message given, based on the policy

        :param GPP: Global Public Parameters
        :param policy_string: Policy
        :param k: Content Key (i.e group element based on AES key)
        :param authority: Attribute Authority Parameters
        :return: Ciphertext
        """
        APK = {}
        authority_attributes = {}
        authority_g_beta_inv = {}

        # extract the APK for the different authorities
        for authority_temp in authority.keys():
            APK[authority_temp] = authority[authority_temp][1]

            # extract the PK values of the attributes of the attribute authorities
            # extract the corresponding g_beta_inverse values for the attribute authorities
            for item in authority[authority_temp][2].keys():
                authority_attributes[item] = authority[authority_temp][2][item]
                authority_g_beta_inv[item] = APK[authority_temp][
                    'g_beta_aid_inv']

        # extract policy and use policy elements to slit the secret
        # into their corresponding shares for encryption
        policy = self.util.createPolicy(policy_string)

        # generate secret through random element
        secret = self.group.random(ZR)

        # split secret into shares (this returns a list)
        shares = self.util.calculateSharesList(secret, policy)

        # process shares list to create a dict with attribute as key
        # and corresponding shares as value
        shares = dict([(x[0].getAttributeAndIndex(), x[1]) for x in shares])

        # initialize blinding factor to hide key
        blinding_factor = 1

        for authority_temp in authority.keys():
            blinding_factor *= APK[authority_temp]['e_alpha']

        # create C elements of encrypted file
        C = k * (blinding_factor**secret)
        C_prime = GPP['g']**secret
        C_prime_prime = GPP['g_b']**secret

        # create structure (dict) to hold the C_i and D_i elements of the encrypted file
        # these are the components related to the attributes
        C_i = {}
        C_i_prime = {}
        D_i = {}
        D_i_prime = {}

        # generate C_i and D_i elements
        for attribute, secret_share in shares.items():
            # attribute_temp = self.util.strip_index(attribute)
            # generate random r_i element
            k_attr = self.util.strip_index(attribute)
            r_i = self.group.random(ZR)
            attribute_PK = authority_attributes[attribute]

            C_i[attribute] = (GPP['g_a']**
                              secret_share) * ~(attribute_PK['PK'][0]**r_i)
            C_i_prime[attribute] = GPP['g']**r_i
            D_i[attribute] = authority_g_beta_inv[attribute]**r_i
            D_i_prime[attribute] = attribute_PK['PK'][1]**r_i

        return {
            'C': C,
            'C_prime': C_prime,
            'C_prime_prime': C_prime_prime,
            'C_i': C_i,
            'C_i_prime': C_i_prime,
            'D_i': D_i,
            'D_i_prime': D_i_prime,
            'policy': policy_string,
        }

    def abenc_generatetoken(self, GPP, CT, UASK, user_keys):
        """
        Partial decryption of the ciphertext

        :param GPP: Global Public Parameters
        :param CT: Ciphertext elements
        :param UASK: Secret Keys for user gotten from Attribute Authorities
        :param user_keys: User global keys
        :return: Partially decrypted ciphertext
        """

        # list to hold corresponding attributes possessed by the user
        user_attributes = []

        for authority in UASK.keys():
            user_attributes.extend(UASK[authority]['AK_uid_aid'].keys())

        # access ciphertext policy
        encryption_policy = self.util.createPolicy(CT['policy'])

        # generate list of minimum policy elements needed for encryption
        # returns False if user fails policy assessment
        minimal_policy_list = self.util.prune(encryption_policy,
                                              user_attributes)

        # print(minimal_policy_list)

        # this is an error handling implementation that should be fixed later
        if not minimal_policy_list:
            return False

        # get attribute coefficients to be able to access their share of the secret
        coefficients = self.util.getCoefficients(encryption_policy)
        # initialize the dividend value for the token generation computation
        dividend = 1

        for authority in UASK.keys():
            dividend *= (
                pair(CT['C_prime'], UASK[authority]['K_uid_aid']) *
                ~pair(CT['C_prime_prime'], UASK[authority]['K_uid_aid_prime']))

        # attribute authority index?
        n_a = 1

        # initialize divisor value for token generation computation
        divisor = 1

        # create dict to hold attributes for the authorities and their corresponding secret keys
        attribute_keys = {}

        # create dict to hold attributes contained in the pruned list and their corresponding secret keys
        pruned_attribute_keys = {}

        # populate attribute with with corresponding key value pairs
        for authority in UASK.keys():
            attribute_keys.update(UASK[authority]['AK_uid_aid'])

        # populate pruned attribute with corresponding key value pairs
        # from attribute list
        for attribute in minimal_policy_list:
            pruned_attribute_keys[str(attribute)] = attribute_keys[str(
                attribute)]

        # compute divisor
        for authority in UASK.keys():

            temp_divisor = 1

            for attribute in minimal_policy_list:
                x = attribute.getAttributeAndIndex()
                y = attribute.getAttribute()

                temp_divisor *= (
                    (pair(CT['C_i'][y], user_keys) *
                     pair(CT['D_i'][y], pruned_attribute_keys[y]) *
                     ~pair(CT['C_i_prime'][y],
                           UASK[authority]['K_uid_aid_prime']) *
                     ~pair(GPP['g'], CT['D_i_prime'][y]))**(coefficients[x] *
                                                            n_a))

            divisor *= temp_divisor

        Token = dividend / divisor

        return (Token, CT['C'])

    def abenc_decrypt(self, CT, TK, user_keys):
        """
        Final decryption algorithm to reveal original message. To be run by the user

        :param CT: Original component of ciphertext that contains the encrypted message
        :param TK: Token generated during partial decryption of ciphertext
        :param user_keys: User global keys
        :return: Decrypted message
        """
        message = CT / (TK**user_keys[1])
        return message

    def abenc_ukeygen(self, GPP, authority, attribute, user_object):
        """
        Generate update keys used in the revocation process for users and the cloud service provider.

        This will be run by the Attribute Authority.

        :param GPP: Global Public Parameters
        :param authority: Attribute Authority
        :param attribute: Attribute to be updated
        :param user_object: User
        :return: User attribute update keys and ciphertext update keys
        """

        ASK, _, authAttrs = authority
        # attribute version key to be updated
        old_version_key = authAttrs[attribute]['VK']
        # set new version key to old value
        new_version_key = old_version_key
        # ensure that new version key is different from original version key
        while old_version_key == new_version_key:
            new_version_key = self.group.random()

        # update version key of the attribute in the dictionary
        authAttrs[attribute]['VK'] = new_version_key

        u_uid = user_object['u_uid']

        # create update key for users i.e to update the attribute involved
        KUK = GPP['H'](attribute)**(ASK['beta_aid'] *
                                    (new_version_key - old_version_key) *
                                    (u_uid + ASK['gamma_aid']))

        # create update key for ciphertexts encrypted with attribute involved
        CUK = (new_version_key / old_version_key,
               (old_version_key - new_version_key) /
               (old_version_key * ASK['gamma_aid']))

        # update the public parameters of the attribute involvedauthAttrs[attribute]['PK'][0] = authAttrs[attribute]['PK'][0] ** CUK[0]
        authAttrs[attribute]['PK'][1] = authAttrs[attribute]['PK'][1]**CUK[0]

        return {
            'KUK': KUK,
            'CUK': CUK,
        }

    def abenc_skupdate(self, USK, attribute, KUK):
        """
        Updates the attribute secret key for the specific attribute.

        This is executed by a non-revoked user.

        :param USK: User secret key
        :param attribute: Attribute whose secret key is to be updated
        :param KUK: Update key for users
        :return: NA
        """

        # update the secret key component of the affected attribute
        # print(USK)
        USK['AK_uid_aid'][attribute] = USK['AK_uid_aid'][attribute] * KUK

    def abenc_ctupdate(self, GPP, CT, attribute, CUK):
        """
        Updates the ciphertexts that contain the specific attribute (revoked attribute).

        This is executed by the cloud service provider.

        :param GPP: Global Public Parameters
        :param CT: The affected ciphertext
        :param attribute: Attribute that is affected by the revocation process
        :param CUK: The Ciphertext Update Key
        :return: NA
        """
        # update the corresponding components of the ciphertext that are related to the affected attribute
        CT['C_i'][attribute] = CT['C_i'][attribute] * (
            CT['D_i_prime'][attribute]**CUK[1])
        CT['D_i_prime'][attribute] = CT['D_i_prime'][attribute]**CUK[0]