我让ECDH共享密钥(下面的sec1和sec2)在NodeJS/Java脚本中工作:

let sk1 = crypto.createECDH('secp256k1')
sk1.setPrivateKey(Buffer.from("71179b991d7693de813aeaa5bfa241a2ac9e0535867ebf8f6b1b0884472ef4a7", "hex"));
let pk1 = crypto.createECDH('secp256k1')
pk1.setPublicKey(Buffer.from("02de4cba976ab77795c46c1c3b95afc077b17afe1bca02d28963a3bcdd9c082168", "hex"));
let sk2 = crypto.createECDH('secp256k1')
sk2.setPrivateKey(Buffer.from("1e114f237e3c59ba2b92aedf213f1127c9169c039752495c1ffb649cb9b90598", "hex"));
let pk2 = crypto.createECDH('secp256k1')
pk2.setPublicKey(Buffer.from("033415a4e45739e8f003450392793a15d3ad6cb49ff5b1943695f2cea92703aa64", "hex"));

console.log('sk1', sk1.getPrivateKey());
console.log('pk1', pk1.getPublicKey('hex', 'compressed'));
console.log('sk2', sk2.getPrivateKey());
console.log('pk2', pk2.getPublicKey('hex', 'compressed'));

let sec1 = sk2.computeSecret(pk1.getPublicKey());
let sec2 = sk1.computeSecret(pk2.getPublicKey());

console.log('sec1', sec1);
console.log('sec2', sec2);

assert.equal(sec1, sec2);

这将产生:

sk1 <Buffer 71 17 9b 99 1d 76 93 de 81 3a ea a5 bf a2 41 a2 ac 9e 05 35 86 7e bf 8f 6b 1b 08 84 47 2e f4 a7>
pk1 02de4cba976ab77795c46c1c3b95afc077b17afe1bca02d28963a3bcdd9c082168
sk2 <Buffer 1e 11 4f 23 7e 3c 59 ba 2b 92 ae df 21 3f 11 27 c9 16 9c 03 97 52 49 5c 1f fb 64 9c b9 b9 05 98>
pk2 033415a4e45739e8f003450392793a15d3ad6cb49ff5b1943695f2cea92703aa64
sec1 <Buffer 23 55 7d 44 6a 48 23 d6 a3 2f b0 87 58 82 26 d1 e8 ef 4f 6b 7b 6d 26 09 13 13 84 0a 74 ed 0b 4d>
sec2 <Buffer 23 55 7d 44 6a 48 23 d6 a3 2f b0 87 58 82 26 d1 e8 ef 4f 6b 7b 6d 26 09 13 13 84 0a 74 ed 0b 4d>

我正试着在《铁 rust 》中做同样的事情.Rust代码的共享秘密彼此匹配,但与我从NodeJS/Java脚本(和C)获得的共享秘密不匹配.

从《铁 rust 》中,我得到了:

running 1 test
sk1: [71, 17, 9b, 99, 1d, 76, 93, de, 81, 3a, ea, a5, bf, a2, 41, a2, ac, 9e, 5, 35, 86, 7e, bf, 8f, 6b, 1b, 8, 84, 47, 2e, f4, a7]
pk1: [2, de, 4c, ba, 97, 6a, b7, 77, 95, c4, 6c, 1c, 3b, 95, af, c0, 77, b1, 7a, fe, 1b, ca, 2, d2, 89, 63, a3, bc, dd, 9c, 8, 21, 68]
sk2: [1e, 11, 4f, 23, 7e, 3c, 59, ba, 2b, 92, ae, df, 21, 3f, 11, 27, c9, 16, 9c, 3, 97, 52, 49, 5c, 1f, fb, 64, 9c, b9, b9, 5, 98]
pk2: [3, 34, 15, a4, e4, 57, 39, e8, f0, 3, 45, 3, 92, 79, 3a, 15, d3, ad, 6c, b4, 9f, f5, b1, 94, 36, 95, f2, ce, a9, 27, 3, aa, 64]
sec1: [45, b7, 3c, 8a, ac, 8b, cf, 65, 1d, ad, 11, f7, f0, 4f, 63, b9, f0, 34, 86, d0, 28, ab, 4d, 5c, 52, bd, d5, d6, 92, d7, c2, aa]
sec2: [45, b7, 3c, 8a, ac, 8b, cf, 65, 1d, ad, 11, f7, f0, 4f, 63, b9, f0, 34, 86, d0, 28, ab, 4d, 5c, 52, bd, d5, d6, 92, d7, c2, aa]
test ecies::tests::test_shared_secret ... ok

使用代码:

#[test]
fn test_shared_secret() {
    let sk1 = secp256k1::SecretKey::from_slice(&hex!("71179b991d7693de813aeaa5bfa241a2ac9e0535867ebf8f6b1b0884472ef4a7")).expect("bad key");
    let pk1 = secp256k1::PublicKey::from_slice(&hex!("02de4cba976ab77795c46c1c3b95afc077b17afe1bca02d28963a3bcdd9c082168")).expect("bad key");
    let sk2 = secp256k1::SecretKey::from_slice(&hex!("1e114f237e3c59ba2b92aedf213f1127c9169c039752495c1ffb649cb9b90598")).expect("bad key");
    let pk2 = secp256k1::PublicKey::from_slice(&hex!("033415a4e45739e8f003450392793a15d3ad6cb49ff5b1943695f2cea92703aa64")).expect("bad key");

    println!("sk1: {:x?}", sk1.secret_bytes());
    println!("pk1: {:x?}", pk1.serialize());
    println!("sk2: {:x?}", sk2.secret_bytes());
    println!("pk2: {:x?}", pk2.serialize());

    let sec1 = secp256k1::ecdh::SharedSecret::new(&pk2, &sk1);
    let sec2 = secp256k1::ecdh::SharedSecret::new(&pk1, &sk2);

    println!("sec1: {:x?}", sec1.secret_bytes());
    println!("sec2: {:x?}", sec2.secret_bytes());
    assert_eq!(sec1, sec2);
}

如何使在Rust中计算的ECDH共享密钥与我在NodeJS/Javascript(和C)中已有的密钥相匹配?


在阅读@Topaco的答案后,请更新.

我将铁 rust 代码更改为:

    let sec1 = secp256k1::ecdh::shared_secret_point(&pk2, &sk1);
    let sec2 = secp256k1::ecdh::shared_secret_point(&pk1, &sk2);

    println!("sec1: {:x?}", sec1);
    println!("sec2: {:x?}", sec2);

它现在产生了:

sk1: [71, 17, 9b, 99, 1d, 76, 93, de, 81, 3a, ea, a5, bf, a2, 41, a2, ac, 9e, 5, 35, 86, 7e, bf, 8f, 6b, 1b, 8, 84, 47, 2e, f4, a7]
pk1: [2, de, 4c, ba, 97, 6a, b7, 77, 95, c4, 6c, 1c, 3b, 95, af, c0, 77, b1, 7a, fe, 1b, ca, 2, d2, 89, 63, a3, bc, dd, 9c, 8, 21, 68]
sk2: [1e, 11, 4f, 23, 7e, 3c, 59, ba, 2b, 92, ae, df, 21, 3f, 11, 27, c9, 16, 9c, 3, 97, 52, 49, 5c, 1f, fb, 64, 9c, b9, b9, 5, 98]
pk2: [3, 34, 15, a4, e4, 57, 39, e8, f0, 3, 45, 3, 92, 79, 3a, 15, d3, ad, 6c, b4, 9f, f5, b1, 94, 36, 95, f2, ce, a9, 27, 3, aa, 64]
sec1: [23, 55, 7d, 44, 6a, 48, 23, d6, a3, 2f, b0, 87, 58, 82, 26, d1, e8, ef, 4f, 6b, 7b, 6d, 26, 9, 13, 13, 84, a, 74, ed, b, 4d, a4, 8e, f4, 7b, 67, 68, 61, 2c, 33, d1, 1e, e7, 8e, 80, 4a, 71, ef, 79, dd, 3c, b0, 18, 15, f5, b3, 80, 3f, 93, e1, 9e, 64, 4e]
sec2: [23, 55, 7d, 44, 6a, 48, 23, d6, a3, 2f, b0, 87, 58, 82, 26, d1, e8, ef, 4f, 6b, 7b, 6d, 26, 9, 13, 13, 84, a, 74, ed, b, 4d, a4, 8e, f4, 7b, 67, 68, 61, 2c, 33, d1, 1e, e7, 8e, 80, 4a, 71, ef, 79, dd, 3c, b0, 18, 15, f5, b3, 80, 3f, 93, e1, 9e, 64, 4e]

NodeJS的:

sec1 <Buffer 23 55 7d 44 6a 48 23 d6 a3 2f b0 87 58 82 26 d1 e8 ef 4f 6b 7b 6d 26 09 13 13 84 0a 74 ed 0b 4d>
sec2 <Buffer 23 55 7d 44 6a 48 23 d6 a3 2f b0 87 58 82 26 d1 e8 ef 4f 6b 7b 6d 26 09 13 13 84 0a 74 ed 0b 4d>

Rust共享密钥的长度为64个字节,但NodeJS共享密钥只是其中的前32个字节.因为它们共享前32个字节(可能是X坐标),这就是我所需要的,它对我来说是有效的.

推荐答案

共享秘密是由私钥和公钥相乘得到的EC点(x,y)的x坐标.对于secp256k1,x和y的大小均为32字节.使用Rust,可以按如下方式确定共享密钥:

...
let ec_point_1 = secp256k1::ecdh::shared_secret_point(&pk2, &sk1);
let sec1 = &ec_point_1[0..32];
println!("sec1: {:02x?}", sec1); // sec1: [23, 55, 7d, 44, 6a, 48, 23, d6, a3, 2f, b0, 87, 58, 82, 26, d1, e8, ef, 4f, 6b, 7b, 6d, 26, 09, 13, 13, 84, 0a, 74, ed, 0b, 4d]

shared_secret_point()以x和y坐标x|y的串联形式返回EC点,这就是前32个字节等于共享密钥的原因.

在以这种方式确定的共享秘密上,使用密钥导出函数(由双方商定)来导出最终密钥.


In contrast to shared_secret_point(), SharedSecret() already applies a key derivation function whose logic can be found here:
First a version is determined (here 0x02), this is concatenated with the raw shared secret (here 0x23557d446a4823d6a32fb087588226d1e8ef4f6b7b6d26091313840a74ed0b4d) and from the result (0x0223557d446a4823d6a32fb087588226d1e8ef4f6b7b6d26091313840a74ed0b4d) the SHA56 hash is generated (0x45b73c8aac8bcf651dad11f7f04f63b9f03486d028ab4d5c52bdd5d692d7c2aa) in accordance with the output of the Rust code.
Note that this key derivation is not a standard and is therefore generally not implemented by other libraries.

Rust相关问答推荐

Tauri tauri—apps/plugin—store + zustand

什么是Rust惯用的方式来使特征向量具有单个向量项的别名?

两个相关特征的冲突实现错误

为什么std repeat trait绑定在impl块和关联函数之间?

在Rust中宏的表达式中提取对象

定义采用更高级类型泛型的性状

如何在 struct 的自定义序列化程序中使用serde序列化_WITH

如何编写一个以一个闭包为参数的函数,该函数以另一个闭包为参数?

如何为rust trait边界指定多种可能性

正则表达式中的重叠匹配?(铁 rust 正则式发动机)

在文件链实施中绕过borrow 判断器

是否提供Bundle 在可执行文件中的warp中的静态文件?

是否可以使用Serde/Rust全局处理无效的JSON值?

Windows 上 ndarray-linalg 与 mkl-stats 的链接时间错误

借来的价值生命周期 不够长,不确定为什么它仍然是借来的

打印 `format_args!` 时borrow 时临时值丢失

强制特征仅在 Rust 中的给定类型大小上实现

字符串切片的向量超出范围但原始字符串仍然存在,为什么判断器说有错误?

Rust,我如何正确释放堆分配的内存?

在 Rust 中获得准确时间的正确方法?