admin管理员组文章数量:1410730
I want implement a elliptic curve diffie hellman using HKDF as key derivation function. I am using a python backend and (vanilla) javascript in frontend. I am using python cryptography library in backend and Web Crypto api in frontend as cryptographic library. I created ECDH key pair in both side and exchanged the pbulic keys. Now I am trying to create the AES shared key with the exchanged public key and private key along with HKDF algorithm. I am able to do it in the python backend (I followed this example for the python code):
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()
But Iam not sure how to do it using web crypto api. Here is my attempt: (but doesn't work)
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"]
);
}
How can I create the shared AES key along with HKDF (same way as python) in the frontend using web crypto api?
I want implement a elliptic curve diffie hellman using HKDF as key derivation function. I am using a python backend and (vanilla) javascript in frontend. I am using python cryptography library in backend and Web Crypto api in frontend as cryptographic library. I created ECDH key pair in both side and exchanged the pbulic keys. Now I am trying to create the AES shared key with the exchanged public key and private key along with HKDF algorithm. I am able to do it in the python backend (I followed this example for the python code):
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()
But Iam not sure how to do it using web crypto api. Here is my attempt: (but doesn't work)
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"]
);
}
How can I create the shared AES key along with HKDF (same way as python) in the frontend using web crypto api?
Share Improve this question edited Jun 11, 2021 at 16:21 Tahlil asked Jun 11, 2021 at 14:05 TahlilTahlil 1,0912 gold badges17 silver badges30 bronze badges 1- @Topaco I followed this python example.... I know that web crypto api has both ECDH and HKDF options...but not sure how to use them together to generate the AES key like in the python code. – Tahlil Commented Jun 11, 2021 at 16:26
1 Answer
Reset to default 8The referenced Python code uses P-384 (aka secp384r1) as elliptic curve. This is patible with the WebCrypto API, which supports three curves P-256 (aka secp256r1), P-384 and P-521 (aka secp521r1), see EcKeyImportParams
.
The following WebCrypto code generates a shared secret using ECDH and derives an AES key from the shared secret using HKDF. In detail the following happens:
- To allow parison of the derived key with that of the referenced Python code, predefined EC keys are applied. The private key is imported as PKCS#8, the public key as X.509/SPKI. Note that due to a Firefox bug concerning the import of EC keys, the script below cannot be run in the Firefox browser.
- After the import the shared secret is created with ECDH using
deriveBits()
(and notderiveKey()
). - The shared secret is imported with
importKey()
and then the AES key is derived using HKDF, again withderiveBits()
.
(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)));
}
with the following output:
Shared secret:
xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF
Derived key:
Yh0FkhqrT9XDQqIiSrGv5YmBjCSj9jhR5fF6HusbN1Q=
To pare the generated AES key with that of the referenced Python code, the following Python code is used, which is based on the referenced code but applies predefined keys that are the counterparts of the keys used in the WebCrypto code. Since the focus here is on key derivation, the AES part is not considered:
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()
with the following output:
Shared secret: xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF
Derived key: Yh0FkhqrT9XDQqIiSrGv5YmBjCSj9jhR5fF6HusbN1Q=
which corresponds to the values of the WebCrypto code.
本文标签: javascriptWeb cryptography implement HKDF for the output of ECDHStack Overflow
版权声明:本文标题:javascript - Web cryptography implement HKDF for the output of ECDH - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744898466a2631204.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论