基于JPBC的无证书聚合签名方案实现

基于JPBC的无证书聚合签名方案实现

摘要

一开始签名方案是基于PKI的,无证书签名起源于 基于身份密码体制, 2009 年第一篇无证书签名方案1被提出,随后出现了一些列方案2,3;包括无配对的无证书聚合签名方案4,更多内容参考文献5.

暂时没有看见无证书聚合签名方案实现相关的代码,本文基于JPBC库实现,使用方法可以参考B站视频。也可以使用C++和PBC库实现。

方案概述

本文方案是基于论文3描述的。

Setup

给定安全参数 κ ∈ Z \kappa \in Z κ∈Z,KGC选择两个循环群 G 1 G_1 G1 、 G 2 G_2 G2,其阶均为素数 q q q , G 1 G_1 G1 的生成元 P P P,计算可接受的配对 e : G 1 × G 1 → G 2 e:G_1×G_1→G_2 e:G1×G1→G2 。 KGC 随机选择主密钥 s ∈ Z q ∗ s\in Z_q^\ast s∈Zq∗ ,设置 P p u b = s P P_{pub}=sP Ppub=sP ,选择加密哈希函数 H 1 : { 0 , 1 } ∗ → G 1 H_1:\{0,1\}^\ast→G_1 H1:{0,1}∗→G1 , H 2 : { 0 , 1 } ∗ → G 1 H_2:\{0,1\}^\ast→G_1 H2:{0,1}∗→G1, H 3 : { 0 , 1 } ∗ → Z q ∗ H_3:\{0,1\}^\ast→Z_q^\ast H3:{0,1}∗→Zq∗. 系统参数为 { q , G 1 , G 2 , e , P , P p u b , H 1 , H 2 , H 3 } \{q,G_1,G_2,e,P,P_{pub},H_1,H_2,H_3 \} {q,G1,G2,e,P,Ppub,H1,H2,H3}, 主密钥是s。

PartialKeyGen :

给定用户身份 I D i ∈ { 0 , 1 } ∗ ID_i\in \{0,1\}^\ast IDi∈{0,1}∗,KGC首先计算 Q I D i = H 1 ( I D i ) Q_{ID_i }=H_1 (ID_i) QIDi=H1(IDi)。 然后,它设置该用户的部分密钥 p s k I D i = s Q ( I D i ) psk_{ID_i }=sQ_(ID_i ) pskIDi=sQ(IDi)并将其通过安全通道传输给对应用户。 用户可以通过检查是否正确来检查其正确性 e ( p s k I D i , P ) = e ( Q I D i , P p u b ) e(psk_{ID_i },P)=e(Q_{ID_i },P_{pub}) e(pskIDi,P)=e(QIDi,Ppub)。

UserKeyGen :

用户 I D i ID_i IDi随机选择值 x I D i ∈ Z q ∗ x_{ID_i }\in Z_q^\ast xIDi∈Zq∗作为他的用户私钥 u s k I D i usk_{ID_i } uskIDi,并且计算用户公钥 u p k I D i = x I D i P upk_{ID_i}=x_{ID_i } P upkIDi=xIDiP。

Sign :

对于消息 m i ∈ 0 , 1 ∗ m_i∈{0,1}^\ast mi∈0,1∗,选择状态信息 ∆ ∆ ∆(选择公开参数作为状态信息),具有 I D i ID_i IDi身份的签名者执行以下步骤:

  1. 选择随机数 r i ∈ Z q ∗ r_i∈Z_q^\ast ri∈Zq∗并且计算 U i = r i P ∈ G 1 U_i=r_i P∈G_1 Ui=riP∈G1.
  2. 计算 Q = H 2 ( ∆ ) , h i = H 3 ( m i , I D i , u p k I D i , U i ) Q=H_2(∆),h_i=H_3(m_i,ID_i,upk_{ID_i},U_i) Q=H2(∆),hi=H3(mi,IDi,upkIDi,Ui)
  3. 计算 V i = p s k I D i + r i ⋅ Q + h i ⋅ x i ⋅ P p u b V_i=psk_{ID_i }+r_i⋅Q+h_i⋅x_i⋅P_{pub} Vi=pskIDi+ri⋅Q+hi⋅xi⋅Ppub.

输出 ( U i , V i ) (U_i,V_i ) (Ui,Vi)作为 m i m_i mi的签名。

Verify

给定一个消息 m i m_i mi签名 ( U i , V i ) (U_i,V_i ) (Ui,Vi),其对应的身份为 I D i ID_i IDi和公钥 u p k I D i upk_{ID_i} upkIDi,计算 Q ( I D i ) = H 1 ( I D i ) , Q = H 2 ( ∆ ) Q_(ID_i )=H_1 (ID_i ),Q=H_2 (∆) Q(IDi)=H1(IDi),Q=H2(∆) ,
h i = H 3 ( m i , I D i , u p k I D i , U i ) h_i=H_3 (m_i,ID_i,upk_{ID_i },U_i ) hi=H3(mi,IDi,upkIDi,Ui)

如果等式 e ( V i , P ) = e ( h i ⋅ u p k I D i + Q I D i , P p u b ) e ( U i , Q ) e(V_i,P)=e(h_i⋅upk_{ID_i }+Q_{ID_i },P_{pub} )e(U_i,Q) e(Vi,P)=e(hi⋅upkIDi+QIDi,Ppub)e(Ui,Q) 成立,接收签名;否则拒绝。

Aggregate

任何人都可以充当聚合签名生成器, 对于n个用户的聚合集 { U 1 , ... , U n } \{U_1,...,U_n\} {U1,...,Un}其对应身份为 { I D 1 , ... , I D n } \{ID_1,...,ID_n \} {ID1,...,IDn}以及对应公钥 { u p k 1 , ... , u p k n } \{upk_1,...,upk_n\} {upk1,...,upkn},对应消息签名对为 { ( m 1 , σ 1 = ( U 1 , V 1 ) ) , ... , ( m n , σ n = ( U n , V n ) ) } \{(m_1,σ_1=(U_1,V_1 )),...,(m_n,σ_n=(U_n,V_n))\} {(m1,σ1=(U1,V1)),...,(mn,σn=(Un,Vn))},

聚合签名计算: V = ∑ i = 1 n V i V=∑_{i=1}^n V_i V=∑i=1nVi, 将 σ = ( U 1 , ... , U n , V ) σ=(U_1,...,U_n,V) σ=(U1,...,Un,V)作为聚合签名。

Aggregate-Verify

验证聚合签名 σ = ( U 1 , ... , U n , V ) σ=(U_1,...,U_n,V) σ=(U1,...,Un,V)由n个用户 { U 1 , ... , U n } \{U_1,...,U_n\} {U1,...,Un}身份为 { I D 1 , ... , I D n } \{ID_1,...,ID_n\} {ID1,...,IDn}和对应的公钥 { u p k 1 , ... , u p k n } \{upk_1,...,upk_n\} {upk1,...,upkn};关于消息 { m 1 , ... , m n } \{m_1,...,m_n \} {m1,...,mn} 验证者执行以下操作:

计算 Q I D i = H 1 ( I D i ) , Q = H 2 ( ∆ ) , h i = H 3 ( m i , I D i , u p k I D i , U i ) , i = 1 , ... , n Q_{ID_i }=H_1 (ID_i ),Q=H_2 (∆),h_i=H_3 (m_i,ID_i,upk_{ID_i },U_i ),i=1,...,n QIDi=H1(IDi),Q=H2(∆),hi=H3(mi,IDi,upkIDi,Ui),i=1,...,n.

验证: e ( V , P ) = e ( ∑ i = 1 n [ h i ⋅ u p k I D i + Q I D i ] , P p u b ) e ( ∑ i = 1 n U i , Q ) e(V,P)=e(∑{i=1}^n [h_i⋅upk{ID_i}+Q_{ID_i} ] ,P_{pub} )e(∑_{i=1}^n U_i ,Q) e(V,P)=e(∑i=1n[hi⋅upkIDi+QIDi],Ppub)e(∑i=1nUi,Q).如果满足则通过;否则验证失败。

代码实现

整体思路, 将相关密钥信息作为文件保存(序列化后可以通过网络传输),根据方案不同的功能设计不同的函数。

关于文件a_181_603.properties的内容

properties 复制代码
type=a
q=98826429041171753291515535532523512299028170537954154869719707264887274916552228805607584116490046284509883309001532457986879277885241872021906840932513241346999389365188296460009947
h=32243626948934860887488490158437299489453513352745889246437755713701521031193083418924110592954582395114812811896992400310730276
r=3064991081731777546575510593831386635550174528483098623
exp2=181
exp1=127
sign1=-1
sign0=-1

代码

java 复制代码
import it.unisa.dia.gas.jpbc.Element;
import it.unisa.dia.gas.jpbc.Pairing;
import it.unisa.dia.gas.plaf.jpbc.pairing.PairingFactory;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class CLAS {

    //生成公私钥对,并保存到文件中
    public static void Setup(String pairingParametersFileName, String pubParamFileName, String KGC_SK_FileName) {
        Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
        //G1的生成元P
        Element P = bp.getG1().newRandomElement().getImmutable();
        //计算主私钥和公钥
        Element s = bp.getZr().newRandomElement().getImmutable();
        Element P_Pub = P.mulZn(s);

        Properties pubParamProp = new Properties();

        //后面对写的元素统一采用如下方法:首先将元素转为字节数组,然后进行Base64编码为可读字符串
        pubParamProp.setProperty("P", Base64.getEncoder().encodeToString(P.toBytes()));
        pubParamProp.setProperty("P_Pub", Base64.getEncoder().encodeToString(P_Pub.toBytes()));

        storePropToFile(pubParamProp, pubParamFileName);

        Properties param_s = new Properties();//私钥不存入公开参数中,由KGC自己保存
        param_s.setProperty("s", Base64.getEncoder().encodeToString(s.toBytes()));
        storePropToFile(param_s, KGC_SK_FileName);
    }

    //根据用户id生成私钥
    public static void PartialPrivateKeyGen(String pairingParametersFileName, String id, String KGC_SK_FileName) throws NoSuchAlgorithmException {
        Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
        //使用HASH 将 id 转为QID
        byte[] idHash = HASH(id);
        Element QID = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();

        //从文件中读取 主私钥
        Properties mskProp = loadPropFromFile(KGC_SK_FileName);
        String sString = mskProp.getProperty("s");
        Element s = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(sString)).getImmutable();  //Base64编码后对应的恢复元素的方法

        //计算用户私钥, 这里应该将私钥安全的传输给用户
        //方便模拟,统一存入一个文件中
        Element psk_ID = QID.powZn(s).getImmutable();
        Properties pskProp = new Properties();
        pskProp.setProperty("psk", Base64.getEncoder().encodeToString(psk_ID.toBytes()));
        storePropToFile(pskProp, id + ".properties");
    }

    //生成用户私钥
    public static void UserKeyGen(String pairingParametersFileName, String pubParamFileName, String id) {
        Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
        //从文件中读取公钥
        Properties pkProp = loadPropFromFile(pubParamFileName);
        String PString = pkProp.getProperty("P");

        Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(PString)).getImmutable();
        //生成随机数x,作为用户的私钥
        Element x = bp.getZr().newRandomElement().getImmutable();
        //计算用户公钥
        Element upk = P.mulZn(x);

        Properties userProp = new Properties();
        userProp.setProperty("usk", Base64.getEncoder().encodeToString(x.toBytes()));
        userProp.setProperty("upk", Base64.getEncoder().encodeToString(upk.toBytes()));
        storePropToFile(userProp, id + ".properties");
    }

    //签名
    public static Element[] Sign(String pairingParametersFileName, String pubParamFileName, String id, byte[] message) throws NoSuchAlgorithmException {
        Pairing bp = PairingFactory.getPairing(pairingParametersFileName);
        //获取公开参数
        Properties pubProp = loadPropFromFile(pubParamFileName);
        Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P"))).getImmutable();
        Element P_Pub = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P_Pub"))).getImmutable();

        //获取用户自己的信息
        Properties userProp = loadPropFromFile(id + ".properties");
        Element upk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("upk"))).getImmutable();
        Element x = bp.getZr().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("usk"))).getImmutable();
        Element psk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("psk"))).getImmutable();

        //选择随机数
        Element r = bp.getZr().newRandomElement();
        Element U = P.mulZn(r).getImmutable();

        //获取状态信息,将公开参数作为状态信息
        String p = pubProp.getProperty("P");
        String pPub = pubProp.getProperty("P_Pub");
        byte[] hash = HASH(p + pPub);
        Element Q = hashToG(bp, hash);

        // 计算m, id, upk,U组合的hash值
        byte[] res = hashCombination(message, id.getBytes(), upk.toBytes(), U.toBytes());
        Element h = hashToZ(bp, res);


        Element V = P_Pub.mulZn(x).mulZn(h).add(Q.mulZn(r)).add(psk).getImmutable();

        Element[] sigma = new Element[2];
        sigma[0] = U;
        sigma[1] = V;
        return sigma;

    }

    //验证
    public static boolean Verify(String pairingParametersFileName, String pubParamFileName, String id, byte[] message, Element[] sigma) throws NoSuchAlgorithmException {
        Pairing bp = PairingFactory.getPairing(pairingParametersFileName);

        //使用sha1 将 id 转为QID
        byte[] idHash = HASH(id);
        Element QID = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();

        //获取公开参数
        Properties pubProp = loadPropFromFile(pubParamFileName);
        Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P"))).getImmutable();
        Element P_Pub = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P_Pub"))).getImmutable();

        //获取状态信息,将公开参数作为状态信息
        String p = pubProp.getProperty("P");
        String pPub = pubProp.getProperty("P_Pub");
        byte[] hash = HASH(p + pPub);
        Element Q = hashToG(bp, hash);

        //获取用户的公钥,
        Properties userProp = loadPropFromFile(id + ".properties");
        Element upk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("upk"))).getImmutable();

        // 计算m, id, upk,U组合的hash值
        byte[] res = hashCombination(message, id.getBytes(), upk.toBytes(), sigma[0].toBytes());

        Element h = hashToZ(bp, res);

        Element left = bp.pairing(sigma[1], P);
        Element right = bp.pairing(QID.add(upk.mulZn(h)), P_Pub).mul(bp.pairing(sigma[0], Q));
        return left.isEqual(right);
    }

    //聚合签名, U_1,U_2,...,U_n,V
    public static Element[] Aggregate(List<Element[]> sigmaList) {
        Element[] res = new Element[sigmaList.size() + 1];
        Element[] init = sigmaList.get(0);
        res[0] = init[0];
        Element V = init[1];
        for (int i = 1; i < sigmaList.size(); i++) {
            res[i] = sigmaList.get(i)[0];
            V = V.add(sigmaList.get(1)[1]);
        }
        res[sigmaList.size()] = V;
        return res;
    }

    // 聚合签名验证
    public static boolean AggregateVerify(String pairingParametersFileName, String pubParamFileName, String[] idx, byte[][] message, Element[] sigma) throws NoSuchAlgorithmException {
        Pairing bp = PairingFactory.getPairing(pairingParametersFileName);

        Element[] QIDX = new Element[idx.length];
        for (int i = 0; i < idx.length; i++) {
            byte[] idHash = HASH(idx[i]);
            Element QID = bp.getG1().newElementFromHash(idHash, 0, idHash.length).getImmutable();
            QIDX[i] = QID;
        }

        //获取公开参数信息
        Properties pubProp = loadPropFromFile(pubParamFileName);
        Element P = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P"))).getImmutable();
        Element P_Pub = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(pubProp.getProperty("P_Pub"))).getImmutable();
        String p = pubProp.getProperty("P");
        String pPub = pubProp.getProperty("P_Pub");
        byte[] hash = HASH(p + pPub);
        Element Q = hashToG(bp, hash);


        Element[] PKX = new Element[idx.length];
        for (int i = 0; i < idx.length; i++) {
            Properties userProp = loadPropFromFile(idx[i] + ".properties");
            Element upk = bp.getG1().newElementFromBytes(Base64.getDecoder().decode(userProp.getProperty("upk"))).getImmutable();
            PKX[i] = upk;
        }

        Element[] hx = new Element[idx.length];
        for (int i = 0; i < idx.length; i++) {
            byte[] res = hashCombination(message[i], idx[i].getBytes(), PKX[i].toBytes(), sigma[i].toBytes());
            Element h = hashToZ(bp, res);
            hx[i] = h;
        }
        Element left = bp.pairing(sigma[idx.length], P);
        Element U = sigma[0];
        for (int i = 1; i < idx.length; i++) {
            U = U.add(sigma[i]);
        }
        Element part = QIDX[0].add(PKX[0].mulZn(hx[0]));
        for (int i = 1; i < idx.length; i++) {
            part = part.add(QIDX[i].add(PKX[i].mulZn(hx[i])));
        }
        Element right = bp.pairing(part, P_Pub).mul(bp.pairing(U, Q));
        return left.isEqual(right);
    }

    //一种可行的组合方法
    public static byte[] hashCombination(byte[] message, byte[] id, byte[] upk, byte[] U) throws NoSuchAlgorithmException {
        int m_len = message.length, id_len = id.length, upk_len = upk.length, u_len = U.length;
        int total_len = m_len + id_len + upk_len + u_len;
        byte[] res = new byte[total_len];
        for (int i = 0; i < m_len; i++) {
            res[i] = message[i];
        }
        for (int i = 0; i < id_len; i++) {
            res[i + m_len] = id[i];
        }
        for (int i = 0; i < upk_len; i++) {
            res[i + m_len + id_len] = upk[i];
        }
        for (int i = 0; i < u_len; i++) {
            res[i + m_len + id_len + upk_len] = U[i];
        }
        MessageDigest instance = MessageDigest.getInstance("SHA-256");
        instance.update(res);
        return instance.digest();
    }

    public static void storePropToFile(Properties prop, String fileName) {
        try (FileOutputStream out = new FileOutputStream(fileName, true)) {
            prop.store(out, null);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(fileName + " save failed!");
            System.exit(-1);
        }
    }

    public static Properties loadPropFromFile(String fileName) {
        Properties prop = new Properties();
        try (FileInputStream in = new FileInputStream(fileName)) {
            prop.load(in);
        } catch (IOException e) {
            e.printStackTrace();
            System.out.println(fileName + " load failed!");
            System.exit(-1);
        }
        return prop;
    }

    public static byte[] HASH(String content) throws NoSuchAlgorithmException {
        MessageDigest instance = MessageDigest.getInstance("SHA-1");
        instance.update(content.getBytes());
        return instance.digest();
    }

    public static Element hashToG(Pairing pb, byte[] code) {
        return pb.getG1().newElementFromHash(code, 0, code.length).getImmutable();
    }

    public static Element hashToZ(Pairing pb, byte[] code) {
        return pb.getZr().newElementFromHash(code, 0, code.length).getImmutable();
    }

    public static void main(String[] args) throws Exception {
        String pairingParametersFileName = "a_181_603.properties";
        String idAlice = "alice@example.com";
        String idBob = "bob@example.com";
        String pubParamFileName = "data/pub.properties";
        String KGCFileName = "data/kgc.properties";
        Setup(pairingParametersFileName, pubParamFileName, KGCFileName);
        PartialPrivateKeyGen(pairingParametersFileName, idAlice, KGCFileName);
        PartialPrivateKeyGen(pairingParametersFileName, idBob, KGCFileName);
        UserKeyGen(pairingParametersFileName, pubParamFileName, idAlice);
        UserKeyGen(pairingParametersFileName, pubParamFileName, idBob);

        String message_a = "Alice,This is a message from Alice!";
        String message_b = "Bob,This is a message from Bob!";


        Element[] sigma1 = Sign(pairingParametersFileName, pubParamFileName, idAlice, message_a.getBytes());
        Element[] sigma2 = Sign(pairingParametersFileName, pubParamFileName, idBob, message_b.getBytes());
        boolean result = Verify(pairingParametersFileName, pubParamFileName, idAlice, message_a.getBytes(), sigma1);
        System.out.println("Alice 验证签名通过? " + result);
        result = Verify(pairingParametersFileName, pubParamFileName, idBob, message_b.getBytes(), sigma2);
        System.out.println("Bob 验证签名通过? " + result);

        List<Element[]> sigmaList = new ArrayList<>();
        sigmaList.add(sigma1);
        sigmaList.add(sigma2);
        Element[] SIGMA = Aggregate(sigmaList);
        String[] idx = {idAlice, idBob};
        byte[][] message = {message_a.getBytes(), message_b.getBytes()};
//        message[0][1] = 1;//假如消息被篡改
        result = AggregateVerify(pairingParametersFileName, pubParamFileName, idx, message, SIGMA);
        System.out.println("聚合签名验证通过? " + result);

    }

}

参考文献

  1. A new certificateless aggregate signature scheme

  2. Cryptanalysis and improvement of a certificateless aggregate signature scheme

  3. A certificateless aggregate signature scheme for healthcare wireless sensor network

  4. Efficient certificateless aggregate signcryption scheme without bilinear pairings

Security issues in IoT applications using certificateless aggregate signcryption schemes: An overview

相关推荐
Turbo正则16 小时前
量子计算基础概念以及八大分支
密码学·量子计算
网安INF11 天前
公钥加密与签名算法计算详解(含计算题例子)
网络·算法·网络安全·密码学
电院工程师12 天前
基于机器学习的侧信道分析(MLSCA)Python实现(带测试)
人工智能·python·嵌入式硬件·安全·机器学习·密码学
电院工程师14 天前
SM3算法C语言实现(无第三方库,带测试)
c语言·算法·安全·密码学
weiwei2284415 天前
secp256k1算法详解一
区块链·数字签名·源码编译·elliptic curve
小七mod15 天前
【BTC】密码学原理
web3·区块链·密码学·比特币·btc·肖臻·北大区块链
电院工程师21 天前
轻量级密码算法PRESENT的C语言实现(无第三方库)
c语言·算法·安全·密码学
电院工程师21 天前
轻量级密码算法CHAM的python实现
python·嵌入式硬件·算法·安全·密码学
电院工程师22 天前
SM3算法Python实现(无第三方库)
开发语言·python·算法·安全·密码学
网安INF22 天前
SHA-1算法详解:原理、特点与应用
java·算法·密码学