使用 libsodium 加密,需要使用 crypto_box_keypair 生成公钥和私钥

问题描述

我一直在使用 libsodium 库来实现 Shamir 秘密共享并尝试测试由暗水晶完成的实现

https://gitlab.com/dark-crystal-javascript/key-backup-crypto/-/blob/master/example.js

实现是这样的

function encryptionKeypair () {
    const keypair = {
      publicKey: sodium.sodium_malloc(sodium.crypto_Box_PUBLICKEYBYTES),secretKey: sodium.sodium_malloc(sodium.crypto_Box_SECRETKEYBYTES)
    }
    sodium.crypto_Box_keypair(keypair.publicKey,keypair.secretKey)
    return keypair
  },function oneWayBox (message,publicKey) {
    console.log('in one way Box');
    const curvePublicKey = sodium.sodium_malloc(sodium.crypto_Box_PUBLICKEYBYTES)
    // console.log('curvePublicKey',curvePublicKey.toString('hex'));
    console.log('curvePublicKey',curvePublicKey.length);
    console.log('publicKey',publicKey.length);
    
    sodium.crypto_sign_ed25519_pk_to_curve25519(curvePublicKey,publicKey)

    // console.log('curvePublicKey',curvePublicKey.toString('hex'));


    console.log('in one way Box');
    console.log('\n');

    const ephemeral = this.encryptionKeypair()
    const nonce = this.randomBytes(sodium.crypto_Box_NONCEBYTES)
    const cipherText = sodium.sodium_malloc(message.length + sodium.crypto_Box_MACBYTES)
  
    sodium.crypto_Box_easy(cipherText,message,nonce,curvePublicKey,ephemeral.secretKey)
    zero(ephemeral.secretKey)
    zero(message)
    return Buffer.concat([nonce,ephemeral.publicKey,cipherText])
  },

下面是 Secret-sharing-generation.js

const secrets = require('secret-sharing')
const s = require('.')

const secret = 'My secret key'
const label = ''

console.log('Secret to share:',secret.toString('hex'))

console.log(`Packing with label: '${label}'`)
const packedSecret = s.packLabel(secret,label)
console.log(`Packed secret: ${packedSecret.toString('hex')}`)
console.log(`Length of packed secret is ${packedSecret.length} bytes.`)
const signingKeypair = s.keypair()
const encryptionKeypair = s.signingKeypairToEncryptionKeypair(signingKeypair)

const custodians = []
for (let i = 0; i < 5; i++) {
  custodians.push(s.encryptionKeypair())
}


console.log('custodians',custodians);

console.log('Creating 5 shares,3 needed to recover')
secrets.share(packedSecret,5,3).then((shards) => {
  console.log('Shards:')
  console.log(shards.map(s => s.toString('hex')))
  console.log('Signed shards:')
  const signedShards = s.signShards(shards,signingKeypair)
  console.log(signedShards.map(s => s.toString('hex')))

  const BoxedShards = signedShards.map((shard,i) => {
    return s.oneWayBox(shard,custodians[i].publicKey)
  })

  console.log('Boxed shards:')
  console.log(BoxedShards.map(s => s.toString('hex')))
  console.log(`Length of Boxed shards are ${BoxedShards[0].length} bytes.`)
  secrets.combine(shards.slice(2)).then((result) => {
    console.log('Result of recombining 3 shares:',result.toString())
  })
})

现在的问题是,当我使用 encryptionKeypair 函数生成密钥对时,然后当我尝试使用此 {{1} 中生成的密钥对生成 crypto_sign_ed25519_sk_to_curve25519我得到的功能

encryptionKeypair

我检查了我的交换空间,它是完全免费的

 UnhandledPromiseRejectionWarning: Error: ENOMEM,Cannot allocate memory

我无法理解是什么问题。

解决方法

我不清楚您为什么要将使用 encryptionKeypair() 创建的密钥对与 crypto_sign_ed25519_sk_to_curve25519()crypto_sign_ed25519_pk_to_curve25519() 进行转换。

后两种方法将秘密或公开的 Ed25519 密钥(用于签名的上下文)转换为秘密或公开的 X25519 密钥(用于密钥交换的上下文)。

encryptionKeypair() 应用 crypto_box_keypair(),因此已经创建了一个 X25519 密钥对,因此不需要(也不可能)进行转换。

转换方法的工作用途是,例如使用 crypto_sign_keypair(),生成 Ed25519 密钥对:

var sodium = require('sodium-native');
...
var ed25519KeyPair = signingKeypair() // Create an Ed25519 keypair
var x25519KeyPair = {
    publicKey: sodium.sodium_malloc(sodium.crypto_box_PUBLICKEYBYTES),secretKey: sodium.sodium_malloc(sodium.crypto_box_SECRETKEYBYTES)
}
sodium.crypto_sign_ed25519_pk_to_curve25519(x25519KeyPair.publicKey,ed25519KeyPair.publicKey) // Convert the public Ed25519 into a public X25519 key
sodium.crypto_sign_ed25519_sk_to_curve25519(x25519KeyPair.secretKey,ed25519KeyPair.secretKey) // Convert the secret Ed25519 into a secret X25519 key
console.log(x25519KeyPair.publicKey)
console.log(x25519KeyPair.secretKey)

function signingKeypair () {
    const keypair = {
        publicKey: sodium.sodium_malloc(sodium.crypto_sign_PUBLICKEYBYTES),secretKey: sodium.sodium_malloc(sodium.crypto_sign_SECRETKEYBYTES)
    }
    sodium.crypto_sign_keypair(keypair.publicKey,keypair.secretKey)
    return keypair
}

此外,我无法重现发布的错误消息。使用 encryptionKeypair() 而不是 signingKeypair() 时,我收到以下错误消息错误:公钥转换失败

编辑:

在第二个代码段中,custodians' 密钥对是使用 s.encryptionKeypair() 创建的,它生成 X25519 密钥对。在稍后调用的 s.oneWayBox() 中,它然后尝试使用 crypto_sign_ed25519_pk_to_curve25519() 转换公钥,这必须如上所述失败。

想必这是一个错误!一种可能的解决方法是使用 custodians(或 s.keypair())生成 signingKeypair()' 密钥对,这会创建 Ed25519 密钥对。然后可以将公钥成功转换为 s.oneWayBox() 中的 X25519 密钥。通过此更改,oneWayBox() 在我的机器上运行时不会出现任何错误。

这个对 Ed25519 密钥对的改变也与 encryptionKeypair() 的描述一致,它指出这个方法只在生成临时密钥时使用,例如在oneWayBox()。在所有其他情况下,它是从 Ed25519 密钥内部派生的。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...