本文带你了解如何使用两个新标准在daf-jose和EIP-2844中直接在IPFS中存储签名和加密的数据。
在IPFS上存储经过身份验证和加密的数据是许多Web3应用程序的核心构建块,但是迄今为止,还没有标准化的方式来编码这种类型的数据。
没有标准,许多开发人员被迫为其签名和加密的数据创建自定义格式。通过将数据存储到IPFS的特定实现中,这已经阻碍了IPFS中存储的信息的开放性和互操作性。验证数据的另一种方法是将数据放入IPFS,并将数据的CID放入区块链(如以太坊)的智能合约中。从本质上讲,这是在数据之上添加签名并将签名记录持久保存在区块链上的昂贵方法。
随着EIP-2844的引入,该标准允许钱包支持一些新的方法来基于DID和dag-joseIPLD编解码器对数据进行签名和解密,我们现在可以简单地将经过身份验证和加密的数据直接放入IPFS。在本教程中,您将学习如何通过两个库使用这些原语,js-did以及3ID Connect!
01
什么是DID和JOSE
DID是用于分散标识符的W3C标准。它指定了从字符串标识符(例如did:3:bafy…)到包含用于签名验证和密钥交换的公共密钥的DID文档的一般方法。在大多数DID方法中,出于安全原因旋转键时可以更新文档。
JOSE是IETF的标准,代表JSON对象签名和加密,几乎可以解释其含义。该标准有两个主要原语:JWS(JSON Web签名)和JWE(JSON Web加密)。这两种格式都允许多个参与者:在JWS中,有效负载上可以有一个或多个签名,在JWE中,加密明文可以有一个或多个接收者。
02
使用dag-jose和EIP28
当我们使用dag-jose和EIP-2844作为基本构建模块来构建Ceramic时,我们创建了一些较低级别的工具,使我们可以更轻松地使用这些技术。本教程将向您展示如何直接使用这些功能强大的工具。
IdentityWallet是使用3ID作为DID方法的EIP-2844的实现。它可以单独用作DID提供程序,也可以在3ID Connect库中更方便地使用。3ID Connect允许用户使用其以太坊钱包(即将支持更多区块链)来访问DID Provider。
js-did是一个库,允许开发人员以DID的形式表示用户。这是我们在本教程中将要看到的主要界面。它使我们能够与当前经过身份验证的用户签署数据,将数据加密给任何用户(DID),以及与当前经过身份验证的用户解密数据。
03
IPFS中签名数据
通过使用dag-jose IPLD编解码器,我们可以创建链接和签名的数据结构。这是通过创建包含指向其他数据链接的JSON Web签名(JWS)来完成的。dag-jose编解码器解决的主要问题之一是,传统上将JWS的有效负载编码为:base64url这意味着,如果其中包含IPLD链接,则您将无法遍历这些链接。相反,我们对DagJWS所做的是将有效负载强制为CID的字节。然后,编解码器将有效负载转换为CID实例,并将其设置link为DagJWS的属性。这使我们可以轻松地遍历生成的DAG。
04
设置环境
本节将介绍如何设置本教程所需的一些特定依赖项。如果您只想跳过设置部分,我们准备了一个简单的游乐场,其中捆绑了ipfs,3id-connect和dids。您可以通过以下方式使用它:打开网页,单击“连接”,然后打开开发人员控制台,您可以在其中运行命令。如果您决定这样做,请跳过以下两个部分。
05
设置具有dag-jose支持的IPFS
由于dag-jose是新的IPLD编解码器,因此默认情况下它尚未包含在js-ipfs中。它还实现了新的IPLD编解码器API,js-ipfs尚不支持该API。因此,在创建IPFS实例时,需要执行以下操作:
import IPFS from 'ipfs'import dagJose from 'dag-jose'import multiformats from 'multiformats/basics'import legacy from 'multiformats/legacy'multiformats.multicodec.add(dagJose)const dagJoseFormat = legacy(multiformats, dagJose.name)const ipfs = await Ipfs.create({ ipld: { formats: [dagJoseFormat] } })
06
设置DID和3ID Connet
在下面的示例设置中,我们使用注入的以太坊提供程序(例如MetaMask)创建3ID Connect和DID实例。
import { DID } from 'dids'import { ThreeIdConnect, EthereumAuthProvider } from '3id-connect'// create 3id connect instanceconst addresses = await window.ethereum.enable()const authProvider = new EthereumAuthProvider(window.ethereum, addresses[0])await threeIdConnect.connect(authProvider)// create did instanceconst didProvider = await threeIdConnect.getDidProvider()const did = new DID({ provider: didProvider })await did.authenticate()window.did = didconsole.log('Connected with DID:', did.id)
07
创建数字签名
现在我们可以开始签名并将数据添加到IPFS!首先,让我们创建一个简单的函数,该函数接收有效负载,使用该did.createDagJWS方法对其进行签名,然后将结果数据添加到IPFS。正如我们在下面的代码中看到的那样,我们从该方法中获得了两个对象:jwsDagJWS本身和linkedBlock编码有效载荷的原始字节。后台发生的事情是使用dag-cbor对有效负载进行编码,此后,将已编码有效负载的CID用作created的有效负载jws。我们可以通过访问DagJWS实例上的有效负载CID jws.link。
async function addSignedObject(payload) { // sign the payload as dag-jose const { jws, linkedBlock } = await did.createDagJWS(payload) // put the JWS into the ipfs dag const jwsCid = await ipfs.dag.put(jws, { format: 'dag-jose', hashAlg: 'sha2-256' }) // put the payload into the ipfs dag await ipfs.block.put(linkedBlock, { cid: jws.link }) return jwsCid}
使用此功能,让我们创建第一个签名的数据对象:
// Create our first signed objectconst cid1 = await addSignedObject({ hello: 'world' })// Log the DagJWS:console.log((await ipfs.dag.get(cid1)).value)// > {// > payload: "AXESIHhRlyKdyLsRUpRdpY4jSPfiee7e0GzCynNtDoeYWLUB",// > signatures: [{// > signature: "h7bHmTaBGza_QlFRI9LBfgB3Nw0m7hLzwMm4nLvcR3n9sHKRoCrY0soWnDbmuG7jfVgx4rYkjJohDuMNgbTpEQ",// > protected: "eyJraWQiOiJkaWQ6MzpiYWdjcWNlcmFza3hxeng0N2l2b2tqcW9md295dXliMjN0aWFlcGRyYXpxNXJsem4yaHg3a215YWN6d29hP3ZlcnNpb24taWQ9MCNrV01YTU1xazVXc290UW0iLCJhbGciOiJFUzI1NksifQ"// > }],// > link: CID(bafyreidykglsfhoixmivffc5uwhcgshx4j465xwqntbmu43nb2dzqwfvae)// > }// Log the payload:ipfs.dag.get(cid1, { path: '/link' }).then(b => console.log(b.value))// > { hello: 'world' }// Create another signed object that links to the previous oneconst cid2 = addSignedObject({ hello: 'getting the hang of this', prev: cid1 })// Log the new payload:ipfs.dag.get(cid2, { path: '/link' }).then(b => console.log(b.value))// > {// > hello: 'getting the hang of this'// > prev: CID(bagcqcerappi42sb4uyrjkhhakqvkiaibkl4pfnwpyt53xkmsbkns4y33ljzq)// > }// Log the old payload:ipfs.dag.get(cid2, { path: '/link/prev/link' }).then(b => console.log(b.value))// > { hello: 'world' }
请注意,由于有效负载将由您的DID签名,因此CID和JWS的值对您而言将有所不同。
08
验证签名的数据结构
验证JWS非常简单。只需检索JWS对象并将其传递给verifyJWS方法。如果签名无效,则此函数将引发错误。如果签名有效,它将返回用于签名JWS的DID(带有密钥片段)。
const jws1 = await ipfs.dag.get(cid1)const jws2 = await ipfs.dag.get(cid2)const signingDID1 = await did.verifyJWS(jws1)await did.verifyJWS(jws2)
09
IPFS中的加密数据
IPFS中的签名数据是一个难题,但也许更有趣的是加密数据。通过使用dag-jose和EIP-2844,我们可以将数据加密为一个或多个DID,并将其直接存储在IPFS中。下面,我们演示如何使用js-did库提供的便捷工具来执行此操作。
10
加密IPLD数据
有一种简单的方法可以创建DagJWE对象,该对象被加密为一个或多个DID createDagJWE。此方法接受IPLD对象(可能还包括CID链接的JSON对象)和DID数组。它将解析DID以检索在其DID文档中找到的公共加密密钥,并创建一个已加密到这些密钥的JWE。首先,让我们创建一个辅助函数,该函数创建一个JWE并将其放入IPFS。
async function addEncryptedObject(cleartext, dids) { const jwe = await did.createDagJWE(cleartext, dids) return ipfs.dag.put(jwe, { format: 'dag-jose', hashAlg: 'sha2-256' })}
一旦有了此功能,我们就可以创建一些加密的对象。在下面的示例中,我们首先创建一个简单的加密对象,然后创建一个链接到前一个对象的附加加密对象。
const cid3 = await addEncryptedObject({ hello: 'secret' }, [did.id])const cid4 = await addEncryptedObject({ hello: 'cool!', prev: cid3 }, [did.id])
请注意,在上面的示例中,我们用于[did.id](<http://did.id>)将数据加密为当前已验证的DID。我们当然也可以将数据加密为未经本地身份验证的用户(例如另一个用户)的DID!
11
解密IPLD数据
从IPFS检索数据后,我们将只获得加密的JWE。这意味着我们需要在获取数据后解密数据。由于我们已经创建了相互链接的对象,因此让我们创建一个函数来检索这些对象并递归解密它们。
async function followSecretPath(cid) { const jwe = (await ipfs.dag.get(cid)).value const cleartext = await did.decryptDagJWE(jwe) console.log(cleartext) if (cleartext.prev) { followSecretPath(cleartext.prev) }}
上面的函数是一个示例,仅记录解密的对象。我们可以使用它来查看这些对象的内容。
// Retrieve a single objectfollowSecretPath(cid3)// > { hello: 'secret' }// Retrive multiple linked objectsfollowSecretPath(cid4)// > { hello: 'cool!', path: CID(bagcqceraqittnizulygv6qldqgezp3siy2o5vpg66n7wms3vhffvyc7pu7ba) }// > { hello: 'secret' }
– END-
作者:,来源:星际联盟Filecoin
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。
郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。