Tah*_*lil 5 javascript encryption cryptography webcrypto-api
我想使用 HKDF 作为密钥导出函数来实现椭圆曲线 diffie hellman。我在前端使用 python 后端和(普通)javascript。我在后端使用python 加密库,在前端使用Web Crypto api作为加密库。我在双方创建了 ECDH 密钥对并交换了公共密钥。现在我尝试使用交换的公钥和私钥以及 HKDF 算法创建 AES 共享密钥。我可以在 python 后端执行此操作(我按照此示例获取 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()
Run Code Online (Sandbox Code Playgroud)
但我不知道如何使用网络加密 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"]
);
}
Run Code Online (Sandbox Code Playgroud)
如何使用 Web 加密 api 在前端创建共享 AES 密钥以及 HKDF(与 python 相同)?
引用的 Python 代码使用P-384(又名 secp384r1)作为椭圆曲线。这与 WebCrypto API 兼容,后者支持三种曲线 P-256(又名 secp256r1)、P-384 和 P-521(又名 secp521r1),请参阅EcKeyImportParams。
以下 WebCrypto 代码使用 ECDH 生成共享密钥,并使用 HKDF 从共享密钥派生 AES 密钥。详细地发生以下情况:
deriveBits()导入后,使用(而不是)通过 ECDH 创建共享密钥deriveKey()。importKey(),然后使用 HKDF 派生 AES 密钥,再次使用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)));
}Run Code Online (Sandbox Code Playgroud)
输出如下:
Shared secret:
xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF
Derived key:
Yh0FkhqrT9XDQqIiSrGv5YmBjCSj9jhR5fF6HusbN1Q=
Run Code Online (Sandbox Code Playgroud)
为了将生成的 AES 密钥与引用的 Python 代码的密钥进行比较,使用以下 Python 代码,该代码基于引用的代码,但应用了与 WebCrypto 代码中使用的密钥对应的预定义密钥。由于这里的重点是密钥派生,因此不考虑 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()
Run Code Online (Sandbox Code Playgroud)
输出如下:
Shared secret: xbU6oDHMTYj3O71liM5KEJof3/0P4HlHJ28k7qtdqU/36llCizIlOWXtj8v+IngF
Derived key: Yh0FkhqrT9XDQqIiSrGv5YmBjCSj9jhR5fF6HusbN1Q=
Run Code Online (Sandbox Code Playgroud)
它对应于 WebCrypto 代码的值。
| 归档时间: |
|
| 查看次数: |
1878 次 |
| 最近记录: |