├── .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 --------------------------------------------------------------------------------