├── .gitignore
├── ABE.iml
├── a.properties
├── lib
├── jpbc-api-2.0.0 2.jar
└── jpbc-plaf-2.0.0 2.jar
├── src
├── AccessTree.java
├── CPABE.java
├── KPABE.java
└── Node.java
├── 密文策略属性基加密(CP-ABE).pdf
└── 秘钥策略属性基加密(KP-ABE).pdf
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | data/
3 | out/
4 |
--------------------------------------------------------------------------------
/ABE.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/a.properties:
--------------------------------------------------------------------------------
1 | type a
2 | q 8780710799663312522437781984754049815806883199414208211028653399266475630880222957078625179422662221423155858769582317459277713367317481324925129998224791
3 | h 12016012264891146079388821366740534204802954401251311822919615131047207289359704531102844802183906537786776
4 | r 730750818665451621361119245571504901405976559617
5 | exp2 159
6 | exp1 107
7 | sign1 1
8 | sign0 1
9 |
--------------------------------------------------------------------------------
/lib/jpbc-api-2.0.0 2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hjlpb/ABE/6fb99d4660d555c71918d206bfbe3a707d1d1c73/lib/jpbc-api-2.0.0 2.jar
--------------------------------------------------------------------------------
/lib/jpbc-plaf-2.0.0 2.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hjlpb/ABE/6fb99d4660d555c71918d206bfbe3a707d1d1c73/lib/jpbc-plaf-2.0.0 2.jar
--------------------------------------------------------------------------------
/src/AccessTree.java:
--------------------------------------------------------------------------------
1 | import it.unisa.dia.gas.jpbc.Element;
2 | import it.unisa.dia.gas.jpbc.Pairing;
3 | import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
4 |
5 | import java.util.ArrayList;
6 | import java.util.Arrays;
7 | import java.util.List;
8 | import java.util.stream.Collectors;
9 |
10 | import static java.lang.Integer.valueOf;
11 |
12 | public class AccessTree {
13 |
14 | //d-1次多项式表示为q(x)=coef[0] + coef[1]*x^1 + coef[2]*x^2 + coef[d-1]*x^(d-1)
15 | //多项式的系数的数据类型为Zr Element,从而是的后续相关计算全部在Zr群上进行
16 | //通过随机选取coef参数,来构造d-1次多项式q(x)。约束条件为q(0)=s。
17 | public static Element[] randomP(int d, Element s, Pairing bp) {
18 | Element[] coef = new Element[d];
19 | coef[0] = s;
20 | for (int i = 1; i < d; i++){
21 | coef[i] = bp.getZr().newRandomElement().getImmutable();
22 | }
23 | return coef;
24 | }
25 |
26 | //计算由coef为系数确定的多项式qx在点index处的值,注意多项式计算在群Zr上进行
27 | public static Element qx(Element index, Element[] coef, Pairing bp){
28 | Element res = coef[0].getImmutable();
29 | for (int i = 1; i < coef.length; i++){
30 | Element exp = bp.getZr().newElement(i).getImmutable();
31 | //index一定要使用duplicate复制使用,因为index在每一次循环中都要使用,如果不加duplicte,index的值会发生变化
32 | res = res.add(coef[i].mul(index.duplicate().powZn(exp)));
33 | }
34 | return res;
35 | }
36 |
37 | //拉格朗日因子计算 i是集合S中的某个元素,x是目标点的值
38 | public static Element lagrange(int i, int[] S, int x, Pairing bp) {
39 | Element res = bp.getZr().newOneElement().getImmutable();
40 | Element iElement = bp.getZr().newElement(i).getImmutable();
41 | Element xElement = bp.getZr().newElement(x).getImmutable();
42 | for (int j : S) {
43 | if (i != j) {
44 | //注意:在循环中重复使用的项一定要用duplicate复制出来使用
45 | //这儿xElement和iElement重复使用,但因为前面已经getImmutable所以可以不用duplicate
46 | Element numerator = xElement.sub(bp.getZr().newElement(j));
47 | Element denominator = iElement.sub(bp.getZr().newElement(j));
48 | res = res.mul(numerator.div(denominator));
49 | }
50 | }
51 | return res;
52 | }
53 |
54 | //没用递归的秘密共享过程
55 | // public static void rootShare(Node[] nodes, Element secret, Pairing bp){
56 | // nodes[0].secretShare = bp.getZr().newElement(10);
57 | // for (Node node : nodes) {
58 | // if (!node.isLeaf()) {
59 | // Element[] coef = randomP(node.gate[1], node.secretShare, bp);
60 | // for (Element e:coef){
61 | // System.out.println(e);
62 | // }
63 | // for (int i=0; i validChildrenList = new ArrayList();
93 | int[] validChildren;
94 | // 遍历每一个子节点
95 | for (int j=0; ji).toArray();
110 | // 利用拉格朗日差值恢复秘密
111 | Element secret = bp.getZr().newZeroElement().getImmutable();
112 | for (int i : validChildren) {
113 | Element delta = lagrange(i, validChildren, 0, bp); //计算拉个朗日插值因子
114 | secret = secret.add(nodes[i].secretShare.duplicate().mul(delta));
115 | }
116 | n.secretShare = secret;
117 | }
118 | }
119 | else {
120 | if (Arrays.stream(atts).boxed().collect(Collectors.toList()).contains(n.att)){
121 | n.valid = true;
122 | }
123 | }
124 | return n.valid;
125 | }
126 |
127 |
128 | public static void main(String[] args) {
129 |
130 | Pairing bp = PairingFactory.getPairing("a.properties");
131 |
132 | Node[] nodes = new Node[7];
133 | nodes[0] = new Node(new int[]{2,3}, new int[]{1,2,3});
134 | nodes[1] = new Node(1);
135 | nodes[2] = new Node(new int[]{2,3}, new int[]{4,5,6});
136 | nodes[3] = new Node(5);
137 | nodes[4] = new Node(2);
138 | nodes[5] = new Node(3);
139 | nodes[6] = new Node(4);
140 |
141 | nodes[0].secretShare = bp.getZr().newElement(10);
142 | nodeShare(nodes, nodes[0], bp);
143 | for (Node node:nodes){
144 | System.out.println(node);
145 | System.out.println(node.secretShare);
146 | }
147 | System.out.println("________________________________________________");
148 | System.out.println("________________________________________________");
149 |
150 | for (Node node:nodes){
151 | if (!node.isLeaf()){
152 | node.secretShare = null;
153 | }
154 | System.out.println(node);
155 | System.out.println(node.secretShare);
156 | }
157 |
158 | int[] AttList = {1, 2, 3, 5};
159 | boolean res = nodeRecover(nodes, nodes[0], AttList, bp);
160 |
161 | System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
162 | System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++");
163 |
164 | for (Node node:nodes){
165 | System.out.println(node);
166 | System.out.println(node.secretShare);
167 | }
168 | System.out.println(res);
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/CPABE.java:
--------------------------------------------------------------------------------
1 | import it.unisa.dia.gas.jpbc.Element;
2 | import it.unisa.dia.gas.jpbc.Pairing;
3 | import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
4 |
5 | import java.io.*;
6 | import java.security.MessageDigest;
7 | import java.security.NoSuchAlgorithmException;
8 | import java.util.*;
9 | import java.util.stream.Collectors;
10 |
11 | import static java.lang.Integer.valueOf;
12 |
13 | public class CPABE {
14 |
15 | public static void setup(String pairingParametersFileName, String pkFileName, String mskFileName) {
16 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
17 | Element g = bp.getG1().newRandomElement().getImmutable();
18 | Element alpha = bp.getZr().newRandomElement().getImmutable();
19 | Element beta = bp.getZr().newRandomElement().getImmutable();
20 |
21 | Element g_alpha = g.powZn(alpha).getImmutable();
22 | Element g_beta = g.powZn(beta).getImmutable();
23 | Element egg_alpha = bp.pairing(g,g).powZn(alpha).getImmutable();
24 |
25 | Properties mskProp = new Properties();
26 | mskProp.setProperty("g_alpha", Base64.getEncoder().withoutPadding().encodeToString(g_alpha.toBytes()));
27 |
28 | Properties pkProp = new Properties();
29 | pkProp.setProperty("g", Base64.getEncoder().withoutPadding().encodeToString(g.toBytes()));
30 | pkProp.setProperty("g_beta", Base64.getEncoder().withoutPadding().encodeToString(g_beta.toBytes()));
31 | pkProp.setProperty("egg_alpha", Base64.getEncoder().withoutPadding().encodeToString(egg_alpha.toBytes()));
32 |
33 | storePropToFile(mskProp, mskFileName);
34 | storePropToFile(pkProp, pkFileName);
35 | }
36 |
37 | public static void keygen(String pairingParametersFileName, int[] userAttList, String pkFileName, String mskFileName, String skFileName) throws NoSuchAlgorithmException {
38 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
39 |
40 | Properties pkProp = loadPropFromFile(pkFileName);
41 | String gString = pkProp.getProperty("g");
42 | Element g = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(gString)).getImmutable();
43 | String g_betaString = pkProp.getProperty("g_beta");
44 | Element g_beta = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(g_betaString)).getImmutable();
45 |
46 | Properties mskProp = loadPropFromFile(mskFileName);
47 | String g_alphaString = mskProp.getProperty("g_alpha");
48 | Element g_alpha = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(g_alphaString)).getImmutable();
49 |
50 | Properties skProp = new Properties();
51 |
52 | Element t = bp.getZr().newRandomElement().getImmutable();
53 | Element D = g_alpha.mul(g_beta.powZn(t)).getImmutable();
54 | Element D0 = g.powZn(t);
55 |
56 | skProp.setProperty("D", Base64.getEncoder().withoutPadding().encodeToString(D.toBytes()));
57 | skProp.setProperty("D0", Base64.getEncoder().withoutPadding().encodeToString(D0.toBytes()));
58 |
59 | for (int att : userAttList) {
60 | byte[] idHash = sha1(Integer.toString(att));
61 | Element H = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();
62 | Element Datt = H.powZn(t).getImmutable();
63 | skProp.setProperty("D"+att, Base64.getEncoder().withoutPadding().encodeToString(Datt.toBytes()));
64 | }
65 |
66 | skProp.setProperty("userAttList", Arrays.toString(userAttList));
67 | storePropToFile(skProp, skFileName);
68 | }
69 |
70 | public static void encrypt(String pairingParametersFileName, Element message, Node[] accessTree,
71 | String pkFileName, String ctFileName) throws NoSuchAlgorithmException {
72 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
73 |
74 | Properties pkProp = loadPropFromFile(pkFileName);
75 | String gString = pkProp.getProperty("g");
76 | Element g = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(gString)).getImmutable();
77 | String g_betaString = pkProp.getProperty("g_beta");
78 | Element g_beta = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(g_betaString)).getImmutable();
79 | String egg_alphaString = pkProp.getProperty("egg_alpha");
80 | Element egg_alpha = bp.getGT().newElementFromBytes(Base64.getDecoder().decode(egg_alphaString)).getImmutable();
81 |
82 | Properties ctProp = new Properties();
83 | //计算密文组件 C=M e(g,g)^(alpha s)
84 | Element s = bp.getZr().newRandomElement().getImmutable();
85 | Element C = message.duplicate().mul(egg_alpha.powZn(s)).getImmutable();
86 | Element C0 = g.powZn(s).getImmutable();
87 |
88 | ctProp.setProperty("C", Base64.getEncoder().withoutPadding().encodeToString(C.toBytes()));
89 | ctProp.setProperty("C0", Base64.getEncoder().withoutPadding().encodeToString(C0.toBytes()));
90 |
91 | //先设置根节点要共享的秘密值
92 | accessTree[0].secretShare = s;
93 | //进行共享,使得每个叶子节点获得响应的秘密分片
94 | nodeShare(accessTree, accessTree[0], bp);
95 |
96 | for (Node node:accessTree) {
97 | if (node.isLeaf()){
98 | Element r = bp.getZr().newRandomElement().getImmutable();
99 |
100 | byte[] idHash = sha1(Integer.toString(node.att));
101 | Element Hi = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();
102 |
103 | Element C1 = g_beta.powZn(node.secretShare).mul(Hi.powZn(r.negate()));
104 | Element C2 = g.powZn(r);
105 |
106 | ctProp.setProperty("C1-"+node.att, Base64.getEncoder().withoutPadding().encodeToString(C1.toBytes()));
107 | ctProp.setProperty("C2-"+node.att, Base64.getEncoder().withoutPadding().encodeToString(C2.toBytes()));
108 | }
109 | }
110 | storePropToFile(ctProp, ctFileName);
111 | }
112 |
113 | public static Element Decrypt(String pairingParametersFileName, Node[] accessTree, String ctFileName, String skFileName) {
114 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
115 |
116 | Properties ctProp = loadPropFromFile(ctFileName);
117 |
118 | Properties skProp = loadPropFromFile(skFileName);
119 | String userAttListString = skProp.getProperty("userAttList");
120 | //恢复用户属性列表 int[]类型
121 | int[] userAttList = Arrays.stream(userAttListString.substring(1, userAttListString.length()-1).split(",")).map(String::trim).mapToInt(Integer::parseInt).toArray();
122 |
123 | System.out.println("用户属性列表:" + userAttListString);
124 |
125 | String CString = ctProp.getProperty("C");
126 | Element C = bp.getGT().newElementFromBytes(Base64.getDecoder().decode(CString)).getImmutable();
127 | String C0String = ctProp.getProperty("C0");
128 | Element C0 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C0String)).getImmutable();
129 |
130 | String DString = skProp.getProperty("D");
131 | Element D = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(DString)).getImmutable();
132 | String D0String = skProp.getProperty("D0");
133 | Element D0 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(D0String)).getImmutable();
134 |
135 | for (Node node : accessTree) {
136 | if (node.isLeaf()) {
137 | // 如果叶子节点的属性值属于属性列表,则将属性对应的密文组件和秘钥组件配对的结果作为秘密值
138 | if (Arrays.stream(userAttList).boxed().collect(Collectors.toList()).contains(node.att)){
139 | String C1tring = ctProp.getProperty("C1-"+node.att);
140 | Element C1 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C1tring)).getImmutable();
141 | String C2tring = ctProp.getProperty("C2-"+node.att);
142 | Element C2 = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(C2tring)).getImmutable();
143 |
144 | String DattString = skProp.getProperty("D"+node.att);
145 | Element Datt = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(DattString)).getImmutable();
146 |
147 | node.secretShare = bp.pairing(C1,D0).mul(bp.pairing(C2,Datt)).getImmutable();
148 | }
149 | }
150 | }
151 | // 进行秘密恢复
152 | boolean treeOK = nodeRecover(accessTree, accessTree[0], userAttList, bp);
153 | if (treeOK) {
154 | Element egg_alphas = bp.pairing(C0,D).div(accessTree[0].secretShare);
155 | return C.div(egg_alphas);
156 | }
157 | else {
158 | System.out.println("The access tree is not satisfied.");
159 | return null;
160 | }
161 | }
162 |
163 | //d-1次多项式表示为q(x)=coef[0] + coef[1]*x^1 + coef[2]*x^2 + coef[d-1]*x^(d-1)
164 | //多项式的系数的数据类型为Zr Element,从而是的后续相关计算全部在Zr群上进行
165 | //通过随机选取coef参数,来构造d-1次多项式q(x)。约束条件为q(0)=s。
166 | public static Element[] randomP(int d, Element s, Pairing bp) {
167 | Element[] coef = new Element[d];
168 | coef[0] = s;
169 | for (int i = 1; i < d; i++){
170 | coef[i] = bp.getZr().newRandomElement().getImmutable();
171 | }
172 | return coef;
173 | }
174 | //计算由coef为系数确定的多项式qx在点index处的值,注意多项式计算在群Zr上进行
175 | public static Element qx(Element index, Element[] coef, Pairing bp){
176 | Element res = coef[0].getImmutable();
177 | for (int i = 1; i < coef.length; i++){
178 | Element exp = bp.getZr().newElement(i).getImmutable();
179 | //index一定要使用duplicate复制使用,因为index在每一次循环中都要使用,如果不加duplicte,index的值会发生变化
180 | res = res.add(coef[i].mul(index.duplicate().powZn(exp)));
181 | }
182 | return res;
183 | }
184 | //拉格朗日因子计算 i是集合S中的某个元素,x是目标点的值
185 | public static Element lagrange(int i, int[] S, int x, Pairing bp) {
186 | Element res = bp.getZr().newOneElement().getImmutable();
187 | Element iElement = bp.getZr().newElement(i).getImmutable();
188 | Element xElement = bp.getZr().newElement(x).getImmutable();
189 | for (int j : S) {
190 | if (i != j) {
191 | //注意:在循环中重复使用的项一定要用duplicate复制出来使用
192 | //这儿xElement和iElement重复使用,但因为前面已经getImmutable所以可以不用duplicate
193 | Element numerator = xElement.sub(bp.getZr().newElement(j));
194 | Element denominator = iElement.sub(bp.getZr().newElement(j));
195 | res = res.mul(numerator.div(denominator));
196 | }
197 | }
198 | return res;
199 | }
200 |
201 | // 共享秘密
202 | // nodes是整颗树的所有节点,n是要分享秘密的节点
203 | public static void nodeShare(Node[] nodes, Node n, Pairing bp){
204 | // 如果是叶子节点,则不需要再分享
205 | if (!n.isLeaf()){
206 | // 如果不是叶子节点,则先生成一个随机多项式,多项式的常数项为当前节点的秘密值(这个值将被用于分享)
207 | // 多项式的次数,由节点的gate对应的threshold决定
208 | Element[] coef = randomP(n.gate[0], n.secretShare, bp);
209 | for (int j=0; j validChildrenList = new ArrayList();
224 | int[] validChildren;
225 | // 遍历每一个子节点
226 | for (int j=0; ji).toArray();
245 | // 利用拉格朗日差值恢复秘密
246 | // 注意,此处是在指数因子上做拉格朗日差值
247 | Element secret = bp.getGT().newOneElement().getImmutable();
248 | for (int i : validChildren) {
249 | Element delta = lagrange(i, validChildren, 0, bp); //计算拉个朗日插值因子
250 | secret = secret.mul(nodes[i].secretShare.duplicate().powZn(delta)); //基于拉格朗日因子进行指数运算,然后连乘
251 | }
252 | n.secretShare = secret;
253 | }
254 | }
255 | else {
256 | // 判断叶子节点的属性值是否属于属性列表
257 | // 判断一个元素是否属于数组,注意String类型和int类型的判断方式不同
258 | if (Arrays.stream(atts).boxed().collect(Collectors.toList()).contains(n.att)){
259 | n.valid = true;
260 | }
261 | }
262 | return n.valid;
263 | }
264 |
265 | public static void storePropToFile(Properties prop, String fileName){
266 | try(FileOutputStream out = new FileOutputStream(fileName)){
267 | prop.store(out, null);
268 | }
269 | catch (IOException e) {
270 | e.printStackTrace();
271 | System.out.println(fileName + " save failed!");
272 | System.exit(-1);
273 | }
274 | }
275 |
276 | public static Properties loadPropFromFile(String fileName) {
277 | Properties prop = new Properties();
278 | try (FileInputStream in = new FileInputStream(fileName)){
279 | prop.load(in);
280 | }
281 | catch (IOException e){
282 | e.printStackTrace();
283 | System.out.println(fileName + " load failed!");
284 | System.exit(-1);
285 | }
286 | return prop;
287 | }
288 |
289 | public static byte[] sha1(String content) throws NoSuchAlgorithmException {
290 | MessageDigest instance = MessageDigest.getInstance("SHA-1");
291 | instance.update(content.getBytes());
292 | return instance.digest();
293 | }
294 |
295 | public static void basicTest() throws Exception {
296 | int[] userAttList = {1, 2, 3};
297 |
298 | // Node[] accessTree = new Node[7];
299 | // accessTree[0] = new Node(new int[]{2,3}, new int[]{1,2,3});
300 | // accessTree[1] = new Node(1);
301 | // accessTree[2] = new Node(new int[]{2,3}, new int[]{4,5,6});
302 | // accessTree[3] = new Node(5);
303 | // accessTree[4] = new Node(2);
304 | // accessTree[5] = new Node(3);
305 | // accessTree[6] = new Node(4);
306 |
307 | Node[] accessTree = new Node[5];
308 | accessTree[0] = new Node(new int[]{4,4}, new int[]{1,2,3,4});
309 | accessTree[1] = new Node(1);
310 | accessTree[2] = new Node(2);
311 | accessTree[3] = new Node(3);
312 | accessTree[4] = new Node(4);
313 |
314 | String dir = "data/";
315 | String pairingParametersFileName = "a.properties";
316 | String pkFileName = dir + "pk.properties";
317 | String mskFileName = dir + "msk.properties";
318 | String skFileName = dir + "sk.properties";
319 | String ctFileName = dir + "ct.properties";
320 |
321 | setup(pairingParametersFileName, pkFileName, mskFileName);
322 | keygen(pairingParametersFileName, userAttList, pkFileName, mskFileName, skFileName);
323 |
324 | Element message = PairingFactory.getPairing(pairingParametersFileName).getGT().newRandomElement().getImmutable();
325 | System.out.println("明文消息:" + message);
326 | encrypt(pairingParametersFileName, message, accessTree, pkFileName, ctFileName);
327 |
328 | Element res = Decrypt(pairingParametersFileName, accessTree, ctFileName, skFileName);
329 | System.out.println("解密结果:" + res);
330 |
331 | if (message.isEqual(res)) {
332 | System.out.println("成功解密!");
333 | }
334 | }
335 | public static void main(String[] args) throws Exception {
336 | basicTest();
337 | }
338 |
339 | }
340 |
--------------------------------------------------------------------------------
/src/KPABE.java:
--------------------------------------------------------------------------------
1 | import it.unisa.dia.gas.jpbc.Element;
2 | import it.unisa.dia.gas.jpbc.Pairing;
3 | import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;
4 |
5 | import java.io.FileInputStream;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.security.NoSuchAlgorithmException;
9 | import java.util.*;
10 | import java.util.stream.Collectors;
11 |
12 | import static java.lang.Integer.valueOf;
13 |
14 | public class KPABE {
15 |
16 | public static void setup(String pairingParametersFileName, int U, String pkFileName, String mskFileName) {
17 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
18 | Element g = bp.getG1().newRandomElement().getImmutable();
19 |
20 | Properties mskProp = new Properties();
21 | Properties pkProp = new Properties();
22 | //属性表示为1,2,3,...,U
23 | //对每个属性i,选取一个随机数ti作为该属性对应的主密钥,并计算相应公钥g^ti
24 | for (int i = 1; i <= U; i++){
25 | Element t = bp.getZr().newRandomElement().getImmutable();
26 | Element T = g.powZn(t).getImmutable();
27 | mskProp.setProperty("t"+i, Base64.getEncoder().withoutPadding().encodeToString(t.toBytes()));
28 | pkProp.setProperty("T"+i, Base64.getEncoder().withoutPadding().encodeToString(T.toBytes()));
29 | }
30 | //另外选取一个随机数y,计算e(g,g)^y
31 | Element y = bp.getZr().newRandomElement().getImmutable();
32 | Element egg_y = bp.pairing(g, g).powZn(y).getImmutable();
33 | mskProp.setProperty("y", Base64.getEncoder().withoutPadding().encodeToString(y.toBytes()));
34 | pkProp.setProperty("egg_y", Base64.getEncoder().withoutPadding().encodeToString(egg_y.toBytes()));
35 | pkProp.setProperty("g", Base64.getEncoder().withoutPadding().encodeToString(g.toBytes()));
36 |
37 | storePropToFile(mskProp, mskFileName);
38 | storePropToFile(pkProp, pkFileName);
39 | }
40 |
41 | public static void keygen(String pairingParametersFileName, Node[] accessTree, String pkFileName, String mskFileName, String skFileName) throws NoSuchAlgorithmException {
42 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
43 |
44 | Properties pkProp = loadPropFromFile(pkFileName);
45 | String gString = pkProp.getProperty("g");
46 | Element g = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(gString)).getImmutable();
47 |
48 | Properties mskProp = loadPropFromFile(mskFileName);
49 | String yString = mskProp.getProperty("y");
50 | Element y = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(yString)).getImmutable();
51 |
52 | //先设置根节点要共享的秘密值
53 | accessTree[0].secretShare = y;
54 | //进行共享,使得每个叶子节点获得响应的秘密分片
55 | nodeShare(accessTree, accessTree[0], bp);
56 |
57 | Properties skProp = new Properties();
58 | //计算每个属性对应的私钥g^(q/t),q是多项式在该属性位置的值,t是属性对应的主密钥
59 | for (Node node : accessTree) {
60 | if (node.isLeaf()) {
61 | // 对于每个叶子结点,先获取对应的主秘钥组件t,然后计算秘钥组件。
62 | String tString = mskProp.getProperty("t"+node.att);
63 | Element t = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(tString)).getImmutable();
64 | Element q = node.secretShare;
65 | Element D = g.powZn(q.div(t)).getImmutable();
66 | skProp.setProperty("D"+node.att, Base64.getEncoder().withoutPadding().encodeToString(D.toBytes()));
67 | }
68 | }
69 | //将用户访问树也添加在私钥中
70 | //如何进行序列化和反序列化
71 | // skProp.setProperty("userAttList", Arrays.toString(accessTree));
72 | storePropToFile(skProp, skFileName);
73 | }
74 |
75 | public static void encrypt(String pairingParametersFileName, Element message, int[] messageAttList, String pkFileName, String ctFileName) {
76 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
77 |
78 | Properties pkProp = loadPropFromFile(pkFileName);
79 | String eggString = pkProp.getProperty("egg_y");
80 | Element egg_y = bp.getGT().newElementFromBytes(Base64.getDecoder().decode(eggString)).getImmutable();
81 | //计算密文组件 EP=Me(g,g)^(ys)
82 | Element s = bp.getZr().newRandomElement().getImmutable();
83 | Element EP = message.duplicate().mul(egg_y.powZn(s)).getImmutable();
84 |
85 | Properties ctProp = new Properties();
86 | //针对每个密文属性,计算密文组件 E=T^s
87 | for (int att : messageAttList) {
88 | String TString = pkProp.getProperty("T"+att);
89 | Element T = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(TString)).getImmutable();
90 | Element E = T.powZn(s).getImmutable();
91 |
92 | ctProp.setProperty("E"+att, Base64.getEncoder().withoutPadding().encodeToString(E.toBytes()));
93 | }
94 | ctProp.setProperty("EP", Base64.getEncoder().withoutPadding().encodeToString(EP.toBytes()));
95 | //密文属性列表也添加至密文中
96 | ctProp.setProperty("messageAttList", Arrays.toString(messageAttList));
97 | storePropToFile(ctProp, ctFileName);
98 | }
99 |
100 | public static Element decrypt(String pairingParametersFileName, Node[] accessTree, String pkFileName, String ctFileName, String skFileName) {
101 | Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
102 |
103 | Properties pkProp = loadPropFromFile(pkFileName);
104 |
105 | Properties ctProp = loadPropFromFile(ctFileName);
106 | String messageAttListString = ctProp.getProperty("messageAttList");
107 | //恢复明文消息的属性列表 int[]类型
108 | int[] messageAttList = Arrays.stream(messageAttListString.substring(1, messageAttListString.length()-1).split(",")).map(String::trim).mapToInt(Integer::parseInt).toArray();
109 |
110 | Properties skProp = loadPropFromFile(skFileName);
111 | for (Node node : accessTree) {
112 | if (node.isLeaf()) {
113 | // 如果叶子节点的属性值属于属性列表,则将属性对应的密文组件和秘钥组件配对的结果作为秘密值
114 | if (Arrays.stream(messageAttList).boxed().collect(Collectors.toList()).contains(node.att)){
115 | String EString = ctProp.getProperty("E"+node.att);
116 | Element E = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(EString)).getImmutable();
117 | String DString = skProp.getProperty("D"+node.att);
118 | Element D = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(DString)).getImmutable();
119 | // 这儿存在于密文属性列表中的叶子节点的秘密值是配对后的结果
120 | node.secretShare = bp.pairing(E,D).getImmutable();
121 | }
122 | }
123 | }
124 | // 进行秘密恢复
125 | boolean treeOK = nodeRecover(accessTree, accessTree[0], messageAttList, bp);
126 | if (treeOK) {
127 | String EPString = ctProp.getProperty("EP");
128 | Element EP = bp.getGT().newElementFromBytes(Base64.getDecoder().decode(EPString)).getImmutable();
129 | //恢复M=EP除以上述连乘结果
130 | Element res = EP.div(accessTree[0].secretShare);
131 | return res;
132 | }
133 | else{
134 | System.out.println("The access tree is not satisfied.");
135 | return null;
136 | }
137 | }
138 |
139 |
140 |
141 | //d-1次多项式表示为q(x)=coef[0] + coef[1]*x^1 + coef[2]*x^2 + coef[d-1]*x^(d-1)
142 | //多项式的系数的数据类型为Zr Element,从而是的后续相关计算全部在Zr群上进行
143 | //通过随机选取coef参数,来构造d-1次多项式q(x)。约束条件为q(0)=s。
144 | public static Element[] randomP(int d, Element s, Pairing bp) {
145 | Element[] coef = new Element[d];
146 | coef[0] = s;
147 | for (int i = 1; i < d; i++){
148 | coef[i] = bp.getZr().newRandomElement().getImmutable();
149 | }
150 | return coef;
151 | }
152 | //计算由coef为系数确定的多项式qx在点index处的值,注意多项式计算在群Zr上进行
153 | public static Element qx(Element index, Element[] coef, Pairing bp){
154 | Element res = coef[0].getImmutable();
155 | for (int i = 1; i < coef.length; i++){
156 | Element exp = bp.getZr().newElement(i).getImmutable();
157 | //index一定要使用duplicate复制使用,因为index在每一次循环中都要使用,如果不加duplicte,index的值会发生变化
158 | res = res.add(coef[i].mul(index.duplicate().powZn(exp)));
159 | }
160 | return res;
161 | }
162 | //拉格朗日因子计算 i是集合S中的某个元素,x是目标点的值
163 | public static Element lagrange(int i, int[] S, int x, Pairing bp) {
164 | Element res = bp.getZr().newOneElement().getImmutable();
165 | Element iElement = bp.getZr().newElement(i).getImmutable();
166 | Element xElement = bp.getZr().newElement(x).getImmutable();
167 | for (int j : S) {
168 | if (i != j) {
169 | //注意:在循环中重复使用的项一定要用duplicate复制出来使用
170 | //这儿xElement和iElement重复使用,但因为前面已经getImmutable所以可以不用duplicate
171 | Element numerator = xElement.sub(bp.getZr().newElement(j));
172 | Element denominator = iElement.sub(bp.getZr().newElement(j));
173 | res = res.mul(numerator.div(denominator));
174 | }
175 | }
176 | return res;
177 | }
178 |
179 | // 共享秘密
180 | // nodes是整颗树的所有节点,n是要分享秘密的节点
181 | public static void nodeShare(Node[] nodes, Node n, Pairing bp){
182 | // 如果是叶子节点,则不需要再分享
183 | if (!n.isLeaf()){
184 | // 如果不是叶子节点,则先生成一个随机多项式,多项式的常数项为当前节点的秘密值(这个值将被用于分享)
185 | // 多项式的次数,由节点的gate对应的threshold决定
186 | Element[] coef = randomP(n.gate[0], n.secretShare, bp);
187 | for (int j=0; j validChildrenList = new ArrayList();
202 | int[] validChildren;
203 | // 遍历每一个子节点
204 | for (int j=0; ji).toArray();
223 | // 利用拉格朗日差值恢复秘密
224 | // 注意,此处是在指数因子上做拉格朗日差值
225 | Element secret = bp.getGT().newOneElement().getImmutable();
226 | for (int i : validChildren) {
227 | Element delta = lagrange(i, validChildren, 0, bp); //计算拉个朗日插值因子
228 | secret = secret.mul(nodes[i].secretShare.duplicate().powZn(delta)); //基于拉格朗日因子进行指数运算,然后连乘
229 | }
230 | n.secretShare = secret;
231 | }
232 | }
233 | else {
234 | // 判断叶子节点的属性值是否属于属性列表
235 | // 判断一个元素是否属于数组,注意String类型和int类型的判断方式不同
236 | if (Arrays.stream(atts).boxed().collect(Collectors.toList()).contains(n.att)){
237 | n.valid = true;
238 | }
239 | }
240 | return n.valid;
241 | }
242 |
243 | public static void storePropToFile(Properties prop, String fileName){
244 | try(FileOutputStream out = new FileOutputStream(fileName)){
245 | prop.store(out, null);
246 | }
247 | catch (IOException e) {
248 | e.printStackTrace();
249 | System.out.println(fileName + " save failed!");
250 | System.exit(-1);
251 | }
252 | }
253 |
254 | public static Properties loadPropFromFile(String fileName) {
255 | Properties prop = new Properties();
256 | try (FileInputStream in = new FileInputStream(fileName)){
257 | prop.load(in);
258 | }
259 | catch (IOException e){
260 | e.printStackTrace();
261 | System.out.println(fileName + " load failed!");
262 | System.exit(-1);
263 | }
264 | return prop;
265 | }
266 |
267 |
268 | public static void main(String[] args) throws Exception {
269 | int U = 20;
270 | int[] messageAttList = {1, 2, 4, 5};
271 | Node[] accessTree = new Node[7];
272 | accessTree[0] = new Node(new int[]{2,3}, new int[]{1,2,3});
273 | accessTree[1] = new Node(1);
274 | accessTree[2] = new Node(new int[]{2,3}, new int[]{4,5,6});
275 | accessTree[3] = new Node(5);
276 | accessTree[4] = new Node(2);
277 | accessTree[5] = new Node(3);
278 | accessTree[6] = new Node(4);
279 |
280 | // int[] messageAttList = {1};
281 | // Node[] accessTree = new Node[3];
282 | // accessTree[0] = new Node(new int[]{2,2}, new int[]{1,2});
283 | // accessTree[1] = new Node(1);
284 | // accessTree[2] = new Node(2);
285 |
286 | String dir = "data/";
287 | String pairingParametersFileName = "a.properties";
288 | String pkFileName = dir + "pk.properties";
289 | String mskFileName = dir + "msk.properties";
290 | String skFileName = dir + "sk.properties";
291 | String ctFileName = dir + "ct.properties";
292 |
293 | setup(pairingParametersFileName, U, pkFileName, mskFileName);
294 |
295 | keygen(pairingParametersFileName, accessTree, pkFileName, mskFileName, skFileName);
296 |
297 | Element message = PairingFactory.getPairing(pairingParametersFileName).getGT().newRandomElement().getImmutable();
298 | // System.out.println("明文消息:" + message);
299 | encrypt(pairingParametersFileName, message, messageAttList, pkFileName, ctFileName);
300 |
301 | // 模拟实际情况,将所有的节点的secretShare置为null
302 | for (Node node : accessTree) {
303 | node.secretShare = null;
304 | }
305 |
306 | Element res = decrypt(pairingParametersFileName, accessTree, pkFileName, ctFileName, skFileName);
307 | System.out.println("解密结果:" + res);
308 | if (message.isEqual(res)) {
309 | System.out.println("成功解密!");
310 | }
311 | }
312 |
313 | }
314 |
--------------------------------------------------------------------------------
/src/Node.java:
--------------------------------------------------------------------------------
1 | import it.unisa.dia.gas.jpbc.Element;
2 | import it.unisa.dia.gas.jpbc.Pairing;
3 |
4 | import java.util.Arrays;
5 |
6 | public class Node {
7 | // gate用两个数(t,n)表示,n表示子节点个数, t表示门限值
8 | // 如果是叶子节点,则为null
9 | public int[] gate;
10 | // children表示内部节点,此字段为子节点索引列表
11 | // 如果是叶子节点,则为null
12 | public int[] children;
13 | // att表示属性值,
14 | // 如果是内部节点,此字段null
15 | public int att;
16 | // 对应的秘密值
17 | public Element secretShare;
18 |
19 | // 用于秘密恢复,表示此节点是否可以恢复
20 | public boolean valid;
21 | //内部节点的构造方法
22 | public Node(int[] gate, int[] children){
23 | this.gate = gate;
24 | this.children = children;
25 | }
26 | // 叶子节点的构造方法
27 | public Node(int att){
28 | this.att = att;
29 | }
30 | public boolean isLeaf() {
31 | return this.children==null ? true : false;
32 | }
33 | @Override
34 | public String toString() {
35 | if (this.isLeaf()){
36 | return Integer.toString(this.att);
37 | }
38 | else {
39 | return Arrays.toString(this.gate);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/密文策略属性基加密(CP-ABE).pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hjlpb/ABE/6fb99d4660d555c71918d206bfbe3a707d1d1c73/密文策略属性基加密(CP-ABE).pdf
--------------------------------------------------------------------------------
/秘钥策略属性基加密(KP-ABE).pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hjlpb/ABE/6fb99d4660d555c71918d206bfbe3a707d1d1c73/秘钥策略属性基加密(KP-ABE).pdf
--------------------------------------------------------------------------------