美文网首页
分布式身份DID实践

分布式身份DID实践

作者: 冰冰大象 | 来源:发表于2021-10-15 21:12 被阅读0次

    转自https://blog.csdn.net/studyzy 关于DID说明这个讲的比较好,参考他的。
    假设一个场景,个人,公安局,第三方。 第三方需要个人信息用于登录和确认身份。则DID流程如下图

    did流程图
    描述一下流程

    1. 生成DID

    个人和公安局分别生成did标识和did文档,生成did部分代码如下

    // 第一步生成自己的did和did文档
        // 生成自己的公私钥
        _,ownPublicKeyPem,ownPrivateKey,ownPublicKey:=GenerateKey()
        // 生成唯一标识符UUID
        didId := dids.GetUUID()
        // 生成自己的did
        myDid := CreateOwnDID(didId)
        fmt.Println("已生成我自己的did:",myDid)
        // 生成自己的did文档
        ownDoc,jsonDoc:=CreateOwnDIDDocument(didId,myDid,ownPublicKeyPem)
        fmt.Println("已生成我自己的did文档:",jsonDoc)
        // 此时将生成的didId 作为Key 将did文档存到区块链链上
    

    生成的did文档如下

    {
      "@context": "https://w3id.org/did/v1", //did 协议
      "id": "did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2", //did 标识符
    // 公钥信息
      "publicKey": [ 
        {
          "id": "did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2#keys-1",
          "type": "Secp256k1",
      // 公钥
          "publicKeyHex": "02b97c30de767f084ce3080168ee293053ba33b235d7116a3263d29f1450936b71"
        }
      ],
    // 采用哪一个公钥认证
      "authentication": ["did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2#key-1"],
    // 通过服务端来验证公钥 可以通过服务端来查询公钥确实属于该服务端的
      "service": [
        {
          "id": "did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2#resolver",
          "type": "DIDResolve",
          "serviceEndpoint": "https://xxxxxxx"
        }
      ]
    }
    

    did文档最核心的功能就是存着你的公钥,并且这个公钥还能通过serviceEndpoint 指定的服务器来验证

    2. 上链

    然后将did标识作为key,did文档作为值分别存储于区块链上。这里什么区块链都行,不做要求

    3. 个人申请VC

    个人向公安局提出申请VC请求,需要向公安局提交个人的验证资料,身份证什么的,同时将你的did标识,和签名发给公安局

    4. 验证个人DID

    公安局通过did标识从链上下载你的did文档,得的你的公钥,然后验证签名。

    5. 生成VC 并上链

    公安局开始创建VC 部分代码如下

    // 第三步 我来到公安局 申请可验证声明VC,于是警察叔叔来我家 调查一下,确定没有问题。可以发证
        // 于是要求我上传身份证等信息,同时还需要上传我did
         own:="我就是孙博,和我上传的一堆东西"
         //用我的私钥签名
         ownSign,_:= ownPrivateKey.Sign([]byte(own))
        // 当警察叔叔拿到我的数据后,更具我的did 从区块链上拿到我的did文档,因为did文档有我的公钥呀
        // 1 验证一下我的did是否正确
          if isok,_:= ownPublicKey.Verify([]byte(own),ownSign);isok{
            fmt.Println("嗯 上传的数据就是孙博的签名的没有问题")
          }
        // 2 验证通过后 警察叔叔开始生成 可验证声明VC 里面的敏感信息可以用申请的人公钥加密
        nameP,_:=ownPublicKey.Encrypt([]byte("孙博"))
        name:=&CredentialSubjectValue{Value:hex.EncodeToString(nameP),Index: "0"}
        birthdayP,_:=ownPublicKey.Encrypt([]byte("1999"))
        birthday:=&CredentialSubjectValue{Value:hex.EncodeToString(birthdayP),Index: "1"}
        dataList := [][]byte{
            []byte("孙博"),
            []byte("1999"),
        }
        // 最重要就是生成MerkleRoot,用户数据披露和校验
        root := dids.CalcMerkleRoot(dataList)
        // 警察叔叔对Merkle根签名
        policeSignRoot,_:= policePrivateKey.Sign(root)
        policeSignRootString:=hex.EncodeToString(policeSignRoot)
        // 生成VC
        credentialSubject:=&CredentialSubject{Id: myDid,Name: name,Birthday: birthday}
        proof:=&Proof{Type: "Secp256k1",SignatureValue:policeSignRootString,VerificationMethod:policeDoc.Authentication[0]}
        vc:=&VC{Context:[]string{"https://www.w3.org/2018/credentials/v1"},
            Id:dids.GetUUID(),
            Type:[]string{"VerifiableCredential", "AlumniCredential"},
            Issuer:policeDid,
            IssuanceDate:time.Now().String(),
            CredentialSubject:credentialSubject,
            Proof:proof,
        }
        vcjson,_:= jsoniter.Marshal(vc)
        fmt.Println("警察叔叔已经生成VC:"+string(vcjson))
        // 警察叔叔这时候将生成的vc,将vc 上链,因为vc中的个人数据都由我的公钥加密,所以安全
        // 我从链上下载后 需要验签一下Merkle根,验签通过则表示这个VC就是警察叔叔发的
    

    对应的VC如下

    {
    // did 协议
      "@context": [
        "https://www.w3.org/2018/credentials/v1"
      ],
      "id": "唯一标识符",
      "type": ["VerifiableCredential", "AlumniCredential"],
      // 发证人DID 也就是 公安局
      "issuer": "did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2",
      "issuanceDate": "2010-01-01T19:73:24Z",
     // 我的数据呀 这里目前只有姓名和出生年,
      "credentialSubject": {
        // 申请人did 也就是我did
        "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
        "name":{
         // 用我的公钥加密了
          "value": "用申请方的公钥加密",
        //  这个是顺序 主要是用在生成MerkleTree的
          "index": "0"
        },
        "birthday":{
          "value": "用申请方的公钥加密",
          "index": "1"
        },
       // 证明 用来进行属性披露的 VC 的时候用不着 ,空字符就行
        "evidence": ""
      },
    // 验证方式
      "proof": {
        "type": "Secp256k1",
       // 签名数据
        "signatureValue": "将credentialSubject原始数据生成MerkleRoot后签名",
     // 这个很重要 告诉我 使用的是公安局did 的那个公钥 才能验签signatureValue
        "verificationMethod": "did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2#key-1"
      }
    }
    

    因为VC里数据都用公钥加密里 所以将VC上链,key就是VC的id,这里上链的好处 一会说

    6. 个人获取VC并验证

    个人通过VC的ID 从链上下载VC

    1. 通过我的私钥解密credentialSubject 获得明文所有属性
    2. 根据所有属性生成MerkleTree,并获取MerkleRoot
    3. 验证VC的signatureValue 是否是公安局的MerkleRoot 签名
    4. 通过签名后,表示该VC就是公安局背书的,并且数据没有被修改
    5. 将VC属性明文保存到本地

    7. 第三方向个人发送验证申请

    这里可以是个人主动 发送 也可以是第三方申请,其实都一样

    8. 个人生成VP

    收到第三方申请后,我决定只告诉他我的姓名,不暴露我的出生日期,所以我选择性披露姓名

    1. 私钥解密credentialSubject,获取所有属性,并生成证明
        // 1 解密VC数据 得到明文
        named,_:= hex.DecodeString(vc.CredentialSubject.Name.Value)
        ownNamed,_:=ownPrivateKey.Decrypt(named)
        birthdayd,_:= hex.DecodeString(vc.CredentialSubject.Birthday.Value)
        ownBirthdayd,_:=ownPrivateKey.Decrypt(birthdayd)
        newDataList := [][]byte{
            ownNamed,
            ownBirthdayd,
        }
        // 生成证明
        evidence, _ := dids.CalcMerkleEvidence(newDataList, 0)
    

    这里说下证明类型

    type Evidence struct {
        RawData       []byte   //需要披露的属性
        MerkleSibling [][]byte //路径
        Index         uint     //需要披露的属性所在Merkle树中的位置从0开始
        MerkleRoot    []byte   //根
    }
    

    证明里最重要的其实就是MerkleRoot和MerkleSibling 路径,没有带任何明文数据,至于MerkleRoot和MerkleSibling 的算法https://blog.csdn.net/studyzy
    生成的VP 如下

    {
      "@context": [
        "https://www.w3.org/2018/credentials/v1",
        "https://www.w3.org/2018/credentials/examples/v1"
      ],
      "type": "VerifiablePresentation",
    // 这里是将VC直接带过来
      "verifiableCredential": [{
        "@context": [
          "https://www.w3.org/2018/credentials/v1"
        ],
        "id": "http://example.edu/credentials/1872",
        "type": ["VerifiableCredential", "AlumniCredential"],
        "issuer": "did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2",
        "issuanceDate": "2010-01-01T19:73:24Z",
        "credentialSubject": {
          "id": "did:example:ebfeb1f712ebc6f1c276e12ec21",
          "name":{
            "value": "用申请方did:example:ebfeb1f712ebc6f1c276e12ec21的公钥加密",
            "index": "0"
          },
          "birthday":{
            "value": "用申请方did:example:ebfeb1f712ebc6f1c276e12ec21的公钥加密",
            "index": "1"
          },
    // 此时证明数据存在
          "evidence": "生成属性披露证明,属性证明里带有本次的新的MerkleRoot"
        },
        "proof": {
          "type": "Secp256k1",
          "signatureValue": "将credentialSubject原始数据生成MerkleTree后签名",
          "verificationMethod": "did:ccp:7f8ca8982f6cc6e8ea087bd9457ab8024bd2#key-1"
        }
      }],
    // VP 验证
      "proof": {
        "type": "Secp256k1",
       // 将evidence证明进行签名,用我的私钥签名
        "signatureValue": "将evidence证明进行签名",
      //  验证signatureValue 采用的公钥ID
        "verificationMethod": "did:example:ebfeb1f712ebc6f1c276e12ec21#keys-1"
      }
    }
    
    

    将生成的VP 发送给第三方

    9 验证VP是否是我的

    第三方等到我VP后,从链上分别通过我的DID 和公安局的DID 获取DID文档。获取VP-> verifiableCredential-> evidence证明 和 vp-> proof-> signatureValue证明签名 来验证VP是否是我发送的

        // 1 从链上获取孙博的DID文档,假设这里已经获取到了
        // 根据vp的验证方法 VerificationMethod 找到公钥
        var publicKey crypto.PublicKey
        for _,pk:=range ownDoc.PublicKey{
            // 找到我的公钥
            if pk.ID==vp.Proof.VerificationMethod{
                publicKey,_=dids.PublicKeyFromPEM([]byte(pk.PublicKeyHex))
            }
        }
        // 获取证明签名
        newOwnSign,_:=hex.DecodeString(vp.Proof.SignatureValue)
        if isok,_:= publicKey.Verify([]byte(vc.CredentialSubject.Evidence),newOwnSign);isok{
            fmt.Println("VP验证成功就是孙博的DID签发的")
        }
    

    10 验证VP里的VC数据是否正确

    有一种可能我的个人正确信息其实只有公安局才有,他发的VC才可信,但是我在生成VP的时候,如果修改了信息,第三方如何知道验证呢?因此VC的上链才能解决这个问题。
    解决方法如下

    1. 从链上下载VC 验证后 获取MerkleRoot签名,这个是有公安局背书的 没有问题
    2. 从PV里反序列化证明,可以从证明里得到我自己生成的MerkleRoot
    3. 将证明里的MerkleRoot和VC签名的MerkleRoot 用公安局公钥验证
      通过则表示我生成证明的数据就是公安局背书的数据
      代码如下
    // 3 验证数据是否是警察叔叔背书
        zk:=&dids.ZKEvidence{}
        // 反序列等到我的证书
        jsoniter.Unmarshal([]byte(vp.VC.CredentialSubject.Evidence),&zk)
        // 获取VC里警察叔叔的merkleRoot签名
        merkleRootSign,_:= hex.DecodeString(vp.VC.Proof.SignatureValue)
        // 用警察叔叔的公钥 对我证明里的MerkleRoot 和 签名的merkleRootSign 验证一下
        if isOk,_:= policePublicKey.Verify(zk.MerkleRoot,merkleRootSign);isOk{
            fmt.Println("数据完整新验证完成")
        }
        // 4 获取披露数据
        pass := dids.ZKProve(zk)
        if pass {
            fmt.Printf("证据验证通过!断言「%s」成立", zk.RawData)
        } else {
            fmt.Println("证据验证失败")
        }
    

    以前经常遇到,有人问有什么场景是只有区块链能做的,其他系统不能做的。除了公链数字货币,分布式身份算一个,因为VC 和DID文档 必须是可信的,不能恶意篡改!
    至于优点么,1. 能解决不同系统的用户统一问题,2. 用户的隐私保护。

    相关文章

      网友评论

          本文标题:分布式身份DID实践

          本文链接:https://www.haomeiwen.com/subject/pahxwltx.html