mirror of
https://github.com/denoland/deno.git
synced 2025-02-01 12:16:11 -05:00
fix(ext/crypto): export private x25519 JWK key (#27828)
Ref https://github.com/denoland/deno/issues/26431
This commit is contained in:
parent
21e8260cc9
commit
88490d0927
5 changed files with 42 additions and 27 deletions
|
@ -48,6 +48,7 @@ import {
|
|||
op_crypto_verify_ed25519,
|
||||
op_crypto_verify_key,
|
||||
op_crypto_wrap_key,
|
||||
op_crypto_x25519_public_key,
|
||||
} from "ext:core/ops";
|
||||
const {
|
||||
ArrayBufferIsView,
|
||||
|
@ -4532,17 +4533,18 @@ function exportKeyX25519(format, key, innerKey) {
|
|||
return TypedArrayPrototypeGetBuffer(pkcs8Der);
|
||||
}
|
||||
case "jwk": {
|
||||
if (key[_type] === "private") {
|
||||
throw new DOMException("Not implemented", "NotSupportedError");
|
||||
}
|
||||
const x = op_crypto_base64url_encode(innerKey);
|
||||
const jwk = {
|
||||
kty: "OKP",
|
||||
crv: "X25519",
|
||||
x,
|
||||
"key_ops": key.usages,
|
||||
ext: key[_extractable],
|
||||
};
|
||||
if (key[_type] === "private") {
|
||||
jwk.x = op_crypto_x25519_public_key(innerKey);
|
||||
jwk.d = op_crypto_base64url_encode(innerKey);
|
||||
} else {
|
||||
jwk.x = op_crypto_base64url_encode(innerKey);
|
||||
}
|
||||
return jwk;
|
||||
}
|
||||
default:
|
||||
|
|
|
@ -98,6 +98,7 @@ deno_core::extension!(deno_crypto,
|
|||
op_crypto_base64url_decode,
|
||||
op_crypto_base64url_encode,
|
||||
x25519::op_crypto_generate_x25519_keypair,
|
||||
x25519::op_crypto_x25519_public_key,
|
||||
x25519::op_crypto_derive_bits_x25519,
|
||||
x25519::op_crypto_import_spki_x25519,
|
||||
x25519::op_crypto_import_pkcs8_x25519,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
// Copyright 2018-2025 the Deno authors. MIT license.
|
||||
|
||||
use base64::prelude::BASE64_URL_SAFE_NO_PAD;
|
||||
use curve25519_dalek::montgomery::MontgomeryPoint;
|
||||
use deno_core::op2;
|
||||
use deno_core::ToJsBuffer;
|
||||
|
@ -20,17 +21,16 @@ pub enum X25519Error {
|
|||
#[error(transparent)]
|
||||
Der(#[from] spki::der::Error),
|
||||
}
|
||||
|
||||
// u-coordinate of the base point.
|
||||
const X25519_BASEPOINT_BYTES: [u8; 32] = [
|
||||
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
#[op2(fast)]
|
||||
pub fn op_crypto_generate_x25519_keypair(
|
||||
#[buffer] pkey: &mut [u8],
|
||||
#[buffer] pubkey: &mut [u8],
|
||||
) {
|
||||
// u-coordinate of the base point.
|
||||
const X25519_BASEPOINT_BYTES: [u8; 32] = [
|
||||
9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0,
|
||||
];
|
||||
let mut rng = OsRng;
|
||||
rng.fill_bytes(pkey);
|
||||
// https://www.rfc-editor.org/rfc/rfc7748#section-6.1
|
||||
|
@ -42,6 +42,17 @@ pub fn op_crypto_generate_x25519_keypair(
|
|||
pubkey.copy_from_slice(&x25519_dalek::x25519(pkey, X25519_BASEPOINT_BYTES));
|
||||
}
|
||||
|
||||
#[op2]
|
||||
#[string]
|
||||
pub fn op_crypto_x25519_public_key(#[buffer] private_key: &[u8]) -> String {
|
||||
use base64::Engine;
|
||||
|
||||
let private_key: [u8; 32] =
|
||||
private_key.try_into().expect("Expected byteLength 32");
|
||||
BASE64_URL_SAFE_NO_PAD
|
||||
.encode(x25519_dalek::x25519(private_key, X25519_BASEPOINT_BYTES))
|
||||
}
|
||||
|
||||
const MONTGOMERY_IDENTITY: MontgomeryPoint = MontgomeryPoint([0; 32]);
|
||||
|
||||
#[op2(fast)]
|
||||
|
|
|
@ -2085,3 +2085,20 @@ Deno.test(async function x25519SharedSecret() {
|
|||
assertEquals(sharedSecret1.byteLength, 16);
|
||||
assertEquals(new Uint8Array(sharedSecret1), new Uint8Array(sharedSecret2));
|
||||
});
|
||||
|
||||
Deno.test(async function x25519ExportJwk() {
|
||||
const keyPair = await crypto.subtle.generateKey(
|
||||
{
|
||||
name: "X25519",
|
||||
},
|
||||
true,
|
||||
["deriveBits"],
|
||||
) as CryptoKeyPair;
|
||||
|
||||
const jwk = await crypto.subtle.exportKey("jwk", keyPair.privateKey);
|
||||
|
||||
assertEquals(jwk.kty, "OKP");
|
||||
assertEquals(jwk.crv, "X25519");
|
||||
assert(jwk.d);
|
||||
assert(jwk.x);
|
||||
});
|
||||
|
|
|
@ -845,14 +845,6 @@
|
|||
"Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign])",
|
||||
"Good parameters: Ed448 bits (pkcs8, buffer(73), {name: Ed448}, false, [sign, sign])",
|
||||
"Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign, sign])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits, deriveKey])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits, deriveKey])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])",
|
||||
"Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, true, [deriveKey])",
|
||||
"Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])",
|
||||
"Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])",
|
||||
|
@ -902,14 +894,6 @@
|
|||
"Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign])",
|
||||
"Good parameters: Ed448 bits (pkcs8, buffer(73), {name: Ed448}, false, [sign, sign])",
|
||||
"Good parameters: Ed448 bits (jwk, object(crv, d, x, kty), {name: Ed448}, false, [sign, sign])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits, deriveKey])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits, deriveKey])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveBits])",
|
||||
"Good parameters: X25519 bits (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])",
|
||||
"Good parameters with ignored JWK alg: X25519 (jwk, object(crv, d, x, kty), {name: X25519}, true, [deriveKey, deriveBits, deriveKey, deriveBits])",
|
||||
"Good parameters: X448 bits (pkcs8, buffer(72), {name: X448}, true, [deriveKey])",
|
||||
"Good parameters: X448 bits (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])",
|
||||
"Good parameters with ignored JWK alg: X448 (jwk, object(crv, d, x, kty), {name: X448}, true, [deriveKey])",
|
||||
|
|
Loading…
Add table
Reference in a new issue