Требуются разъяснения по правильному асимметричному шифрованию с использованием пакета tweetnacl с парами ключей Solana (Ed25519)
Я работаю с блокчейном Solana, который использует пары ключей Ed25519, где открытый ключ - это адрес кошелька, а секретный ключ используется для подписи сообщений в транзакциях. Я обнаружил, что некоторые из javascript-библиотек Solana (@solana / web3.js, @solana / spl-token и т. Д.) Используют некоторые структуры данных, совместимые с
tweetnacl
реализация .
Я решил использовать пары ключей Solana Ed25519 в моем собственном шифровании / дешифровании данных на бэкэнде, поэтому я следовал документации, но везде (
NaCl
,
libsodium
) для Public-Key-Authenticated-Encryption они сказали, что вы можете и ДОЛЖНЫ ИСПОЛЬЗОВАТЬ открытый ключ для шифрования и секретный ключ для дешифрования и только на странице tweetnacl (https://github.com/dchest/tweetnacl-js#public-key-authenticated-encryption-box) они сказали:
nacl.box(message, nonce, theirPublicKey, mySecretKey)
а также:
nacl.box.open(box, nonce, theirPublicKey, mySecretKey)
и не
nacl.box.open(box, nonce, myPublicKey, theirSecretKey)
где последний выглядит более логичным, и я действительно не понимаю, есть ли опечатка или я не понял, как ее использовать.
в любом случае, насколько я понимаю, NaCl использует Ed25519 только для подписи, но X25519 (где Curve25519 бирационально равен Ed25519) для шифрования Pubkey, поэтому я создал тест:
// get seed from mnemonic ising bip39 library
let targetKeyPair = web3.Keypair.fromSeed(Uint8Array.from(seed.slice(0,32)))
// derive nacl.box.Keypair from secret
let targetNaclKeyPair = nacl.box.keyPair.fromSecretKey(targetKeyPair.secretKey.slice(0,32))
// convert Ed25519 to X25519 using e2curve
let targetDHPublicKey = ed2curve.convertPublicKey(targetKeyPair.publicKey.toBytes())
let targetDHSecretKey = ed2curve.convertSecretKey(targetKeyPair.secretKey.slice(0,32))
// do similar stuff for master key
let masterKeyPair = web3.Keypair.fromSecretKey(secretKey)
let masterNaclKeyPair = nacl.box.keyPair.fromSecretKey(secretKey.slice(0,32))
let masterDHPublicKey = ed2curve.convertSecretKey(masterKeyPair.publicKey.toBytes())
var masterDHSecretKey = ed2curve.convertSecretKey(masterKeyPair.secretKey.slice(0,32))
// prepare nonce and message
let nonce = Uint8Array.from(entropy, x => x.charCodeAt(0)).slice(0,24)
let msg = Uint8Array.from("some super secret message!!!", x => x.charCodeAt(0))
console.log('toEncrypt', msg)
// wrap call to nacl for future testing
function encryptData(toEncrypt, nonce, pk, sk) {
return nacl.box(toEncrypt, nonce, pk, sk)
}
function decryptData(toDecrypt, nonce, pk, sk) {
return nacl.box.open(toDecrypt, nonce, pk, sk)
}
// create encrypted message from Target to Master and back with all keypair sets
let encryptedMessageFromMasterToTarget = encryptData(msg, nonce, targetKeyPair.publicKey.toBytes(), masterKeyPair.secretKey.slice(0,32))
let encryptedMessageFromTargetToMaster = encryptData(msg, nonce, masterKeyPair.publicKey.toBytes(), targetKeyPair.secretKey.slice(0,32))
let encryptedMessageFromNaclMasterToTarget = encryptData(msg, nonce, targetNaclKeyPair.publicKey, masterNaclKeyPair.secretKey)
let encryptedMessageFromNaclTargetToMaster = encryptData(msg, nonce, masterNaclKeyPair.publicKey, targetNaclKeyPair.secretKey)
let encryptedMessageFromDHMasterToTarget = encryptData(msg, nonce, targetDHPublicKey, masterDHSecretKey)
let encrypredMessageFromDHTargetToMaster = encryptData(msg, nonce, masterDHPublicKey, targetDHSecretKey)
console.log('encrypted message from master to target: ', encryptedMessageFromMasterToTarget)
console.log('encrypted message from target to master: ', encryptedMessageFromTargetToMaster)
console.log('encryptedMessageFromNaclMasterToTarget', encryptedMessageFromNaclMasterToTarget)
console.log('encryptedMessageFromNaclTargetToMaster', encryptedMessageFromNaclTargetToMaster)
console.log('encryptedMessageFromDHMasterToTarget', encryptedMessageFromDHMasterToTarget)
console.log('encrypredMessageFromDHTargetToMaster', encrypredMessageFromDHTargetToMaster)
// decrypt message with argument order from tweetnacl documentation
let decryptedMessageFromMasterToTarget = decryptData(encryptedMessageFromMasterToTarget, nonce, targetKeyPair.publicKey.toBytes(), masterKeyPair.secretKey.slice(0,32))
let decryptedMessageFromTargetToMaster = decryptData(encryptedMessageFromTargetToMaster, nonce, masterKeyPair.publicKey.toBytes(), targetKeyPair.secretKey.slice(0,32))
let decryptedMessageFromNaclMasterToTarget = decryptData(encryptedMessageFromNaclMasterToTarget, nonce, targetNaclKeyPair.publicKey, masterNaclKeyPair.secretKey)
let decryptedMessageFromNaclTargetToMaster = decryptData(encryptedMessageFromNaclTargetToMaster, nonce, masterNaclKeyPair.publicKey, targetNaclKeyPair.secretKey)
let decryptedMessageFromDHMasterToTarget = decryptData(encryptedMessageFromDHMasterToTarget, nonce, targetDHPublicKey, masterDHSecretKey)
let decryptedMessageFromDHTargetToMaster = decryptData(encrypredMessageFromDHTargetToMaster, nonce, masterDHPublicKey, targetDHSecretKey)
// decrypt message with argument order from tweetnacl documentation
let decryptedReverseMessageFromMasterToTarget = decryptData(encryptedMessageFromMasterToTarget, nonce, masterKeyPair.publicKey.toBytes(), targetKeyPair.secretKey.slice(0,32))
let decryptedReverseMessageFromTargetToMaster = decryptData(encryptedMessageFromTargetToMaster, nonce, targetKeyPair.publicKey.toBytes(), masterKeyPair.secretKey.slice(0,32))
let decryptedReverseMessageFromNaclMasterToTarget = decryptData(encryptedMessageFromNaclMasterToTarget, nonce, masterNaclKeyPair.publicKey, targetNaclKeyPair.secretKey)
let decryptedReverseMessageFromNaclTargetToMaster = decryptData(encryptedMessageFromNaclTargetToMaster, nonce, targetNaclKeyPair.publicKey, masterNaclKeyPair.secretKey)
let decryptedReverseMessageFromDHMasterToTarget = decryptData(encryptedMessageFromDHMasterToTarget, nonce, masterDHPublicKey, targetDHSecretKey)
let decryptedReverseMessageFromDHTargetToMaster = decryptData(encrypredMessageFromDHTargetToMaster, nonce, targetDHPublicKey, masterDHSecretKey)
console.log('decrypted message from master to target: ', decryptedMessageFromMasterToTarget)
console.log('decrypted message from target to master: ', decryptedMessageFromTargetToMaster)
console.log('decryptedMessageFromNaclMasterToTarget', decryptedMessageFromNaclMasterToTarget)
console.log('decryptedMessageFromNaclTargetToMaster', decryptedMessageFromNaclTargetToMaster)
console.log('decryptedMessageFromDHMasterToTarget', decryptedMessageFromDHMasterToTarget)
console.log('decryptedMessageFromDHTargetToMaster', decryptedMessageFromDHTargetToMaster)
console.log('decryptedReverseMessageFromMasterToTarget', decryptedReverseMessageFromMasterToTarget)
console.log('decryptedReverseMessageFromTargetToMaster', decryptedReverseMessageFromTargetToMaster)
console.log('decryptedReverseMessageFromNaclMasterToTarget', decryptedReverseMessageFromNaclMasterToTarget)
console.log('decryptedReverseMessageFromNaclTargetToMaster', decryptedReverseMessageFromNaclTargetToMaster)
console.log('decryptedReverseMessageFromDHMasterToTarget', decryptedReverseMessageFromDHMasterToTarget)
console.log('decryptedReverseMessageFromDHTargetToMaster', decryptedReverseMessageFromDHTargetToMaster)
после запуска теста я получил очень интересные результаты:
toEncrypt Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
encrypted message from master to target: Uint8Array(44) [
122, 99, 177, 120, 62, 111, 165, 208, 58,
204, 206, 199, 163, 253, 204, 67, 223, 171,
76, 83, 158, 156, 107, 240, 106, 230, 75,
169, 9, 16, 72, 164, 104, 236, 99, 77,
224, 27, 225, 17, 161, 156, 105, 187
]
encrypted message from target to master: Uint8Array(44) [
132, 248, 6, 59, 219, 67, 101, 81, 221,
134, 117, 200, 163, 105, 55, 67, 2, 148,
206, 231, 46, 146, 198, 168, 248, 241, 82,
16, 244, 53, 98, 27, 189, 91, 241, 63,
145, 119, 27, 81, 65, 158, 250, 216
]
encryptedMessageFromNaclMasterToTarget Uint8Array(44) [
118, 213, 85, 253, 123, 205, 4, 179, 93,
40, 80, 155, 136, 180, 150, 163, 208, 155,
253, 93, 104, 93, 101, 249, 60, 233, 29,
186, 222, 152, 239, 32, 18, 253, 11, 71,
165, 39, 204, 83, 78, 223, 220, 246
]
encryptedMessageFromNaclTargetToMaster Uint8Array(44) [
118, 213, 85, 253, 123, 205, 4, 179, 93,
40, 80, 155, 136, 180, 150, 163, 208, 155,
253, 93, 104, 93, 101, 249, 60, 233, 29,
186, 222, 152, 239, 32, 18, 253, 11, 71,
165, 39, 204, 83, 78, 223, 220, 246
]
encryptedMessageFromDHMasterToTarget Uint8Array(44) [
26, 22, 0, 190, 81, 129, 130, 122, 205,
78, 116, 19, 15, 181, 182, 228, 74, 154,
5, 75, 191, 97, 217, 140, 155, 124, 12,
108, 36, 0, 66, 60, 250, 184, 251, 183,
56, 0, 26, 220, 152, 91, 236, 98
]
encrypredMessageFromDHTargetToMaster Uint8Array(44) [
78, 219, 56, 57, 177, 158, 255, 43, 112,
81, 251, 44, 119, 46, 179, 233, 83, 71,
69, 131, 136, 242, 63, 46, 120, 128, 123,
0, 78, 128, 79, 1, 96, 40, 25, 31,
47, 193, 204, 203, 151, 246, 113, 79
]
decrypted message from master to target: Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decrypted message from target to master: Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decryptedMessageFromNaclMasterToTarget Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decryptedMessageFromNaclTargetToMaster Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decryptedMessageFromDHMasterToTarget Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decryptedMessageFromDHTargetToMaster Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decryptedReverseMessageFromMasterToTarget null
decryptedReverseMessageFromTargetToMaster null
decryptedReverseMessageFromNaclMasterToTarget Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decryptedReverseMessageFromNaclTargetToMaster Uint8Array(28) [
115, 111, 109, 101, 32, 115, 117,
112, 101, 114, 32, 115, 101, 99,
114, 101, 116, 32, 109, 101, 115,
115, 97, 103, 101, 33, 33, 33
]
decryptedReverseMessageFromDHMasterToTarget null
decryptedReverseMessageFromDHTargetToMaster null
Когда используется производный nacl.box.keyPair, кажется, единственное рабочее решение для обратного дешифрования, однако зашифрованное сообщение абсолютно одинаково для обоих направлений (от главного к целевому и наоборот). совершенно неправильно, и преобразование в ed2curve также не работает должным образом. Даже если подумать, что все расшифрованные сообщения с не обратным порядком аргументов возвращают правильные данные!
Итак, мой вопрос: как правильно использовать пары ключей Solana для шифрования с открытым ключом (асимметричного)?