-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b4e8893
commit 9bf909a
Showing
6 changed files
with
1,002 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,242 @@ | ||
''' | ||
Shashank Agrawal, Melissa Chase | ||
| From: "FAME: Fast Attribute-based Message Encryption" | ||
| Published in: 2017 | ||
| Available from: https://eprint.iacr.org/2017/807 | ||
| Notes: Implemented the scheme in Section 3 | ||
| Security Assumption: a variant of k-linear, k>=2 | ||
| | ||
| type: ciphertext-policy attribute-based encryption | ||
| setting: Pairing | ||
:Authors: Shashank Agrawal | ||
:Date: 05/2016 | ||
''' | ||
|
||
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair | ||
from charm.toolbox.ABEnc import ABEnc | ||
from msp import MSP | ||
|
||
debug = False | ||
|
||
|
||
class AC17CPABE(ABEnc): | ||
def __init__(self, group_obj, assump_size, verbose=False): | ||
ABEnc.__init__(self) | ||
self.group = group_obj | ||
self.assump_size = assump_size # size of linear assumption, at least 2 | ||
self.util = MSP(self.group, verbose) | ||
|
||
def setup(self): | ||
""" | ||
Generates public key and master secret key. | ||
""" | ||
|
||
if debug: | ||
print('\nSetup algorithm:\n') | ||
|
||
# generate two instances of the k-linear assumption | ||
A = [] | ||
B = [] | ||
for i in range(self.assump_size): | ||
A.append(self.group.random(ZR)) | ||
B.append(self.group.random(ZR)) # note that A, B are vectors here | ||
|
||
# vector | ||
k = [] | ||
for i in range(self.assump_size + 1): | ||
k.append(self.group.random(ZR)) | ||
|
||
# pick a random element from the two source groups and pair them | ||
g = self.group.random(G1) | ||
h = self.group.random(G2) | ||
e_gh = pair(g, h) | ||
|
||
# now compute various parts of the public parameters | ||
|
||
# compute the [A]_2 term | ||
h_A = [] | ||
for i in range(self.assump_size): | ||
h_A.append(h ** A[i]) | ||
h_A.append(h) | ||
|
||
# compute the e([k]_1, [A]_2) term | ||
g_k = [] | ||
for i in range(self.assump_size + 1): | ||
g_k.append(g ** k[i]) | ||
|
||
e_gh_kA = [] | ||
for i in range(self.assump_size): | ||
e_gh_kA.append(e_gh ** (k[i] * A[i] + k[self.assump_size])) | ||
|
||
# the public key | ||
pk = {'h_A': h_A, 'e_gh_kA': e_gh_kA} | ||
|
||
# the master secret key | ||
msk = {'g': g, 'h': h, 'g_k': g_k, 'A': A, 'B': B} | ||
|
||
return pk, msk | ||
|
||
def keygen(self, pk, msk, attr_list): | ||
""" | ||
Generate a key for a list of attributes. | ||
""" | ||
|
||
if debug: | ||
print('\nKey generation algorithm:\n') | ||
|
||
# pick randomness | ||
r = [] | ||
sum = 0 | ||
for i in range(self.assump_size): | ||
rand = self.group.random(ZR) | ||
r.append(rand) | ||
sum += rand | ||
|
||
# compute the [Br]_2 term | ||
|
||
# first compute just Br as it will be used later too | ||
Br = [] | ||
for i in range(self.assump_size): | ||
Br.append(msk['B'][i] * r[i]) | ||
Br.append(sum) | ||
|
||
# now compute [Br]_2 | ||
K_0 = [] | ||
for i in range(self.assump_size + 1): | ||
K_0.append(msk['h'] ** Br[i]) | ||
|
||
# compute [W_1 Br]_1, ... | ||
K = {} | ||
A = msk['A'] | ||
g = msk['g'] | ||
for attr in attr_list: | ||
key = [] | ||
sigma_attr = self.group.random(ZR) | ||
for t in range(self.assump_size): | ||
prod = 1 | ||
a_t = A[t] | ||
for l in range(self.assump_size + 1): | ||
input_for_hash = attr + str(l) + str(t) | ||
prod *= (self.group.hash(input_for_hash, G1) ** (Br[l]/a_t)) | ||
prod *= (g ** (sigma_attr/a_t)) | ||
key.append(prod) | ||
key.append(g ** (-sigma_attr)) | ||
K[attr] = key | ||
|
||
# compute [k + VBr]_1 | ||
Kp = [] | ||
g_k = msk['g_k'] | ||
sigma = self.group.random(ZR) | ||
for t in range(self.assump_size): | ||
prod = g_k[t] | ||
a_t = A[t] | ||
for l in range(self.assump_size + 1): | ||
input_for_hash = '01' + str(l) + str(t) | ||
prod *= (self.group.hash(input_for_hash, G1) ** (Br[l] / a_t)) | ||
prod *= (g ** (sigma / a_t)) | ||
Kp.append(prod) | ||
Kp.append(g_k[self.assump_size] * (g ** (-sigma))) | ||
|
||
return {'attr_list': attr_list, 'K_0': K_0, 'K': K, 'Kp': Kp} | ||
|
||
def encrypt(self, pk, msg, policy_str): | ||
""" | ||
Encrypt a message msg under a policy string. | ||
""" | ||
|
||
if debug: | ||
print('\nEncryption algorithm:\n') | ||
|
||
policy = self.util.createPolicy(policy_str) | ||
mono_span_prog = self.util.convert_policy_to_msp(policy) | ||
num_cols = self.util.len_longest_row | ||
|
||
# pick randomness | ||
s = [] | ||
sum = 0 | ||
for i in range(self.assump_size): | ||
rand = self.group.random(ZR) | ||
s.append(rand) | ||
sum += rand | ||
|
||
# compute the [As]_2 term | ||
C_0 = [] | ||
h_A = pk['h_A'] | ||
for i in range(self.assump_size): | ||
C_0.append(h_A[i] ** s[i]) | ||
C_0.append(h_A[self.assump_size] ** sum) | ||
|
||
# compute the [(V^T As||U^T_2 As||...) M^T_i + W^T_i As]_1 terms | ||
|
||
# pre-compute hashes | ||
hash_table = [] | ||
for j in range(num_cols): | ||
x = [] | ||
input_for_hash1 = '0' + str(j + 1) | ||
for l in range(self.assump_size + 1): | ||
y = [] | ||
input_for_hash2 = input_for_hash1 + str(l) | ||
for t in range(self.assump_size): | ||
input_for_hash3 = input_for_hash2 + str(t) | ||
hashed_value = self.group.hash(input_for_hash3, G1) | ||
y.append(hashed_value) | ||
# if debug: print ('Hash of', i+2, ',', j2, ',', j1, 'is', hashed_value) | ||
x.append(y) | ||
hash_table.append(x) | ||
|
||
C = {} | ||
for attr, row in mono_span_prog.items(): | ||
ct = [] | ||
attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed | ||
for l in range(self.assump_size + 1): | ||
prod = 1 | ||
cols = len(row) | ||
for t in range(self.assump_size): | ||
input_for_hash = attr_stripped + str(l) + str(t) | ||
prod1 = self.group.hash(input_for_hash, G1) | ||
for j in range(cols): | ||
# input_for_hash = '0' + str(j+1) + str(l) + str(t) | ||
prod1 *= (hash_table[j][l][t] ** row[j]) | ||
prod *= (prod1 ** s[t]) | ||
ct.append(prod) | ||
C[attr] = ct | ||
|
||
# compute the e(g, h)^(k^T As) . m term | ||
Cp = 1 | ||
for i in range(self.assump_size): | ||
Cp = Cp * (pk['e_gh_kA'][i] ** s[i]) | ||
Cp = Cp * msg | ||
|
||
return {'policy': policy, 'C_0': C_0, 'C': C, 'Cp': Cp} | ||
|
||
def decrypt(self, pk, ctxt, key): | ||
""" | ||
Decrypt ciphertext ctxt with key key. | ||
""" | ||
|
||
if debug: | ||
print('\nDecryption algorithm:\n') | ||
|
||
nodes = self.util.prune(ctxt['policy'], key['attr_list']) | ||
if not nodes: | ||
print ("Policy not satisfied.") | ||
return None | ||
|
||
prod1_GT = 1 | ||
prod2_GT = 1 | ||
for i in range(self.assump_size + 1): | ||
prod_H = 1 | ||
prod_G = 1 | ||
for node in nodes: | ||
attr = node.getAttributeAndIndex() | ||
attr_stripped = self.util.strip_index(attr) # no need, re-use not allowed | ||
# prod_H *= key['K'][attr_stripped][i] ** coeff[attr] | ||
# prod_G *= ctxt['C'][attr][i] ** coeff[attr] | ||
prod_H *= key['K'][attr_stripped][i] | ||
prod_G *= ctxt['C'][attr][i] | ||
prod1_GT *= pair(key['Kp'][i] * prod_H, ctxt['C_0'][i]) | ||
prod2_GT *= pair(prod_G, key['K_0'][i]) | ||
|
||
return ctxt['Cp'] * prod2_GT / prod1_GT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
''' | ||
John Bethencourt, Amit Sahai, Brent Waters | ||
| From: "Ciphertext-Policy Attribute-Based Encryption" | ||
| Published in: 2007 | ||
| Available from: https://doi.org/10.1109/SP.2007.11 | ||
| Notes: Implemented an asymmetric version of the scheme in Section 4.2 | ||
| Security Assumption: Generic group model | ||
| | ||
| type: ciphertext-policy attribute-based encryption | ||
| setting: Pairing | ||
:Authors: Shashank Agrawal | ||
:Date: 05/2016 | ||
''' | ||
|
||
from charm.toolbox.pairinggroup import PairingGroup, ZR, G1, G2, GT, pair | ||
from charm.toolbox.ABEnc import ABEnc | ||
from msp import MSP | ||
|
||
debug = False | ||
|
||
|
||
class BSW07(ABEnc): | ||
|
||
def __init__(self, group_obj, verbose=False): | ||
ABEnc.__init__(self) | ||
self.group = group_obj | ||
self.util = MSP(self.group, verbose) | ||
|
||
def setup(self): | ||
""" | ||
Generates public key and master secret key. | ||
""" | ||
|
||
if debug: | ||
print('Setup algorithm:\n') | ||
|
||
# pick a random element each from two source groups | ||
g1 = self.group.random(G1) | ||
g2 = self.group.random(G2) | ||
|
||
beta = self.group.random(ZR) | ||
h = g2 ** beta | ||
f = g2 ** (1/beta) | ||
|
||
alpha = self.group.random(ZR) | ||
g1_alpha = g1 ** alpha | ||
e_gg_alpha = pair (g1_alpha, g2) | ||
|
||
pk = {'g1': g1, 'g2': g2, 'h': h, 'f': f, 'e_gg_alpha': e_gg_alpha} | ||
msk = {'beta': beta, 'g1_alpha': g1_alpha} | ||
return pk, msk | ||
|
||
def keygen(self, pk, msk, attr_list): | ||
""" | ||
Generate a key for a set of attributes. | ||
""" | ||
|
||
if debug: | ||
print('Key generation algorithm:\n') | ||
|
||
r = self.group.random(ZR) | ||
g1_r = pk['g1'] ** r | ||
beta_inverse = 1 / msk['beta'] | ||
k0 = (msk['g1_alpha'] * g1_r) ** beta_inverse | ||
|
||
K = {} | ||
for attr in attr_list: | ||
r_attr = self.group.random(ZR) | ||
k_attr1 = g1_r * (self.group.hash(str(attr), G1) ** r_attr) | ||
k_attr2 = pk['g2'] ** r_attr | ||
K[attr] = (k_attr1, k_attr2) | ||
|
||
return {'attr_list': attr_list, 'k0': k0, 'K': K} | ||
|
||
def encrypt(self, pk, msg, policy_str): | ||
""" | ||
Encrypt a message M under a policy string. | ||
""" | ||
|
||
if debug: | ||
print('Encryption algorithm:\n') | ||
|
||
policy = self.util.createPolicy(policy_str) | ||
mono_span_prog = self.util.convert_policy_to_msp(policy) | ||
num_cols = self.util.len_longest_row | ||
|
||
# pick randomness | ||
u = [] | ||
for i in range(num_cols): | ||
rand = self.group.random(ZR) | ||
u.append(rand) | ||
s = u[0] # shared secret | ||
|
||
c0 = pk['h'] ** s | ||
|
||
C = {} | ||
for attr, row in mono_span_prog.items(): | ||
cols = len(row) | ||
sum = 0 | ||
for i in range(cols): | ||
sum += row[i] * u[i] | ||
attr_stripped = self.util.strip_index(attr) | ||
c_i1 = pk['g2'] ** sum | ||
c_i2 = self.group.hash(str(attr_stripped), G1) ** sum | ||
C[attr] = (c_i1, c_i2) | ||
|
||
c_m = (pk['e_gg_alpha'] ** s) * msg | ||
|
||
return {'policy': policy, 'c0': c0, 'C': C, 'c_m': c_m} | ||
|
||
def decrypt(self, pk, ctxt, key): | ||
""" | ||
Decrypt ciphertext ctxt with key key. | ||
""" | ||
|
||
if debug: | ||
print('Decryption algorithm:\n') | ||
|
||
nodes = self.util.prune(ctxt['policy'], key['attr_list']) | ||
if not nodes: | ||
print ("Policy not satisfied.") | ||
return None | ||
|
||
prod = 1 | ||
|
||
for node in nodes: | ||
attr = node.getAttributeAndIndex() | ||
attr_stripped = self.util.strip_index(attr) | ||
(c_attr1, c_attr2) = ctxt['C'][attr] | ||
(k_attr1, k_attr2) = key['K'][attr_stripped] | ||
prod *= (pair(k_attr1, c_attr1) / pair(c_attr2, k_attr2)) | ||
|
||
return (ctxt['c_m'] * prod) / (pair(key['k0'], ctxt['c0'])) |
Oops, something went wrong.