gpt4 book ai didi

javascript - 用于 ECDH 输出的 Web 密码学实现 HKDF

转载 作者:行者123 更新时间:2023-12-04 14:56:09 25 4
gpt4 key购买 nike

我想使用 HKDF 作为 key 推导函数来实现椭圆曲线 diffie hellman。我在前端使用 python 后端和( Vanilla )javascript。我正在使用 python cryptography后端库和Web Crypto api在前端作为加密库。我在双方都创建了 ECDH key 对并交换了公共(public) key 。现在我正在尝试使用交换的公钥和私钥以及 HKDF 算法创建 AES 共享 key 。我可以在 python 后端执行此操作(我遵循 this example 获取 python 代码):

def encrypt(public_key, secret):
global loaded_public_key
loaded_public_key = public_key
shared_key = server_private_key.exchange(ec.ECDH(), public_key)
IV = bytes("ddfbccae-b4c4-11", encoding="utf-8")
derived_key = HKDF(
algorithm=hashes.SHA256(),
length=32,
salt=None,
info=None,
).derive(shared_key)
aes = Cipher(algorithms.AES(derived_key), modes.GCM(IV))
encryptor = aes.encryptor()
padder = padding.PKCS7(128).padder()
padded_data = padder.update(secret.encode()) + padder.finalize()
return encryptor.update(secret.encode()) + encryptor.finalize()
但我不确定如何使用网络加密 api 来做到这一点。这是我的尝试:(但不起作用)
async function deriveSecretKey(privateKey, publicKey) {
let sharedKey = await window.crypto.subtle.deriveKey(
{
name: "ECDH",
public: publicKey
},
privateKey,
{
name: "AES-GCM",
length: 256
},
false,
["encrypt", "decrypt"]
);
return window.crypto.subtle.deriveKey(
{
name: "HKDF",
hash: {name: "SHA-256"} ,
salt: new ArrayBuffer(0),
info: new ArrayBuffer(0)
},
sharedKey,
{
name: "AES-GCM",
length: 256
},
false,
["encrypt", "decrypt"]
);
}
如何使用 Web Crypto api 在前端创建共享 AES key 和 HKDF(与 python 相同)?

最佳答案

referenced Python code使用 P-384(又名 secp384r1)作为椭圆曲线。这与 WebCrypto API 兼容,它支持三种曲线 P-256(又名 secp256r1)、P-384 和 P-521(又名 secp521r1),请参阅 EcKeyImportParams .
以下 WebCrypto 代码使用 ECDH 生成共享 key ,并使用 HKDF 从共享 key 派生 AES key 。详细情况如下:

  • 为了允许将派生 key 与引用的 Python 代码的 key 进行比较,应用了预定义的 EC key 。私钥导入为 PKCS#8,公钥导入为 X.509/SPKI。请注意,由于与导入 EC key 有关的 Firefox 错误,以下脚本无法在 Firefox 浏览器中运行。
  • 导入后,使用 ECDH 创建共享 key deriveBits() (而不是 deriveKey() )。
  • 使用 importKey() 导入共享 key 然后使用 HKDF 导出 AES key ,再次使用 deriveBits() .

  • (async () => {
    await deriveKey();
    })();

    async function deriveKey() {

    //
    // Key import
    //
    var server_x509 = `-----BEGIN PUBLIC KEY-----
    MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEd7fej9GYVI7Vt6x5B6XhruHvmE/rnzIj
    HmpxP8PKfnfWgrJbyG2cgQc3mf9uusqk1FKImA86rx2+avK8+7xIK9wxuF3x2KQq
    nxNp7bUBit3phyhp72Nt/QLXmZHcDKXL
    -----END PUBLIC KEY-----`;
    var client_pkcs8 = `-----BEGIN PRIVATE KEY-----
    MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBjr4EGktNtx+3xErsC
    MzldruzzfAEEO8Oth1/3b8sNfrqRsAgMnB/oVy024I+15wOhZANiAASbTF7LLedW
    dik6nH8JX8WeU0R1ZRlqq0EAZ/t+UrFcSOaVJSOx5jMJ3nrqwuk2DnobDqFwXH6t
    ZMsZHh4NFZ+bCVeHJRqy4SCZvQFB/xcksF29p1v14XHYI/XKMGyLLx4=
    -----END PRIVATE KEY-----`;

    var client_private_key = b64_to_ab(client_pkcs8.replace('-----BEGIN PRIVATE KEY-----', '').replace('-----END PRIVATE KEY-----', ''));
    var server_public_key = b64_to_ab(server_x509.replace('-----BEGIN PUBLIC KEY-----', '').replace('-----END PUBLIC KEY-----', ''));
    var privateKey = await window.crypto.subtle.importKey(
    'pkcs8',
    client_private_key,
    { name: "ECDH", namedCurve: "P-384" },
    true,
    ["deriveKey", "deriveBits"]
    );
    var publicKey = await window.crypto.subtle.importKey(
    "spki",
    server_public_key,
    { name: "ECDH", namedCurve: "P-384" },
    true,
    []
    );

    //
    // Determine shared secret
    //
    var sharedSecret = await window.crypto.subtle.deriveBits(
    { name: "ECDH", namedCurve: "P-384", public: publicKey },
    privateKey,
    384
    );
    console.log("Shared secret:\n", ab_to_b64(sharedSecret).replace(/(.{48})/g,'$1\n'));

    //
    // Derive key from shared secret via HKDF
    //
    var sharedSecretKey = await window.crypto.subtle.importKey(
    "raw",
    sharedSecret,
    { name: "HKDF" },
    false,
    ["deriveKey", "deriveBits"]
    );
    var derived_key = await crypto.subtle.deriveBits(
    { name: "HKDF", hash: "SHA-256", salt: new Uint8Array([]), info: new Uint8Array([]) },
    sharedSecretKey,
    256
    );
    console.log("Derived key:\n", ab_to_b64(derived_key).replace(/(.{48})/g,'$1\n'))
    };

    function b64_to_ab(base64_string){
    return Uint8Array.from(atob(base64_string), c => c.charCodeAt(0));
    }

    function ab_to_b64(arrayBuffer){
    return btoa(String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)));
    }

    输出如下:
    Shared secret:
    xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF
    Derived key:
    Yh0FkhqrT9XDQqIiSrGv5YmBjCSj9jhR5fF6HusbN1Q=

    为了将生成的 AES key 与引用的 Python 代码的 key 进行比较,使用了以下 Python 代码,该代码基于引用的代码,但应用了与 WebCrypto 代码中使用的 key 对应的预定义 key 。由于这里的重点是 key 派生,因此不考虑 AES 部分:
    from cryptography.hazmat.primitives.asymmetric import ec
    from cryptography.hazmat.primitives.kdf.hkdf import HKDF
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives import serialization
    import base64

    def deriveKey():

    server_pkcs8 = b'''-----BEGIN PRIVATE KEY-----
    MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDBReGpDVmoVTzxNbJx6
    aL4L9z1EdB91eonAmAw7mKDocLfCJITXZPUAmM46c6AipTmhZANiAAR3t96P0ZhU
    jtW3rHkHpeGu4e+YT+ufMiMeanE/w8p+d9aCslvIbZyBBzeZ/266yqTUUoiYDzqv
    Hb5q8rz7vEgr3DG4XfHYpCqfE2nttQGK3emHKGnvY239AteZkdwMpcs=
    -----END PRIVATE KEY-----'''

    client_x509 = b'''-----BEGIN PUBLIC KEY-----
    MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEm0xeyy3nVnYpOpx/CV/FnlNEdWUZaqtB
    AGf7flKxXEjmlSUjseYzCd566sLpNg56Gw6hcFx+rWTLGR4eDRWfmwlXhyUasuEg
    mb0BQf8XJLBdvadb9eFx2CP1yjBsiy8e
    -----END PUBLIC KEY-----'''

    client_public_key = serialization.load_pem_public_key(client_x509)
    server_private_key = serialization.load_pem_private_key(server_pkcs8, password=None)
    shared_secret = server_private_key.exchange(ec.ECDH(), client_public_key)
    print('Shared secret: ' + base64.b64encode(shared_secret).decode('utf8')) # Shared secret: xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF

    derived_key = HKDF(
    algorithm=hashes.SHA256(),
    length=32,
    salt=None,
    info=None,
    ).derive(shared_secret)
    print('Derived key: ' + base64.b64encode(derived_key).decode('utf8')) # Derived key: Yh0FkhqrT9XDQqIiSrGv5YmBjCSj9jhR5fF6HusbN1Q=

    deriveKey()
    输出如下:
    Shared secret: xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF
    Derived key: Yh0FkhqrT9XDQqIiSrGv5YmBjCSj9jhR5fF6HusbN1Q=
    它对应于 WebCrypto 代码的值。

    关于javascript - 用于 ECDH 输出的 Web 密码学实现 HKDF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67938461/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com