Files
skills/docs/security-stack/crypto/crypto-browser/src/ecdsa-p384/ecdsa-p384.md
2026-05-29 08:20:56 +01:00

4.7 KiB
Raw Blame History

ecdsa-p384

(no submodules)

Purpose

Provides ECDSA (Elliptic Curve Digital Signature Algorithm) operations using the NIST P-384 curve and SHA-384 hash, backed by crypto.subtle. P-384 offers 192 bits of security — stronger than P-256's 128 bits — and is required by many compliance frameworks (NIST SP 800-57, CNSA Suite 2.0, NSA Suite B). This module is intended for contexts where P-384 is mandated by policy or interoperability requirements.

The public key format is the 97-byte uncompressed point representation (0x04 prefix followed by 48-byte X and Y coordinates). The private key is PKCS8 DER. Both formats are standard and directly importable by other Web Crypto implementations.

Features

  • generateKeypair() — generates a P-384 ECDSA keypair using crypto.subtle.generateKey
  • sign(privateKey, message) — signs with ECDSA-P384 / SHA-384
  • verify(publicKey, signature, message) — verifies an ECDSA-P384 signature
  • Public key: 97-byte uncompressed point (raw format)
  • Private key: PKCS8 DER bytes
  • Signature format: IEEE P1363 (R || S) as returned by crypto.subtle
  • assertWebCryptoAvailable() guard on every call
  • Typed BrowserCryptoError for all failure paths

Usage: Basic Example

import { ecdsaP384 } from "@suaveplan/crypto-browser/ecdsa-p384/ecdsa-p384";

const kp = await ecdsaP384.generateKeypair();
// kp.publicKey is 97 bytes (uncompressed P-384 point)
// kp.privateKey is PKCS8 DER bytes

const message = new TextEncoder().encode("document to sign");
const signature = await ecdsaP384.sign(kp.privateKey, message);
const valid = await ecdsaP384.verify(kp.publicKey, signature, message);
console.log(valid); // true

Usage: Advanced Example

import { ecdsaP384 } from "@suaveplan/crypto-browser/ecdsa-p384/ecdsa-p384";
import { BrowserCryptoError } from "@suaveplan/crypto-browser/errors";

// Issue a signed certificate-like structure
async function issueAttestation(
  issuerPrivateKey: Uint8Array,
  payload: Uint8Array
): Promise<{ signature: Uint8Array; algorithm: string }> {
  try {
    const signature = await ecdsaP384.sign(issuerPrivateKey, payload);
    return { signature, algorithm: "ECDSA-P384-SHA384" };
  } catch (err) {
    if (err instanceof BrowserCryptoError) {
      throw new Error(`Signing failed: ${err.code}`);
    }
    throw err;
  }
}

// Verify the attestation with a stored public key
async function verifyAttestation(
  publicKey: Uint8Array,
  payload: Uint8Array,
  signature: Uint8Array
): Promise<boolean> {
  return ecdsaP384.verify(publicKey, signature, payload);
}

API Reference

ecdsaP384.generateKeypair(): Promise<{ publicKey: Uint8Array; privateKey: Uint8Array }>

Generates a P-384 ECDSA keypair.

Returns: Promise<{ publicKey: Uint8Array; privateKey: Uint8Array }> — 97-byte uncompressed public key and PKCS8 DER private key.

Throws: BrowserCryptoError — BROWSER_CRYPTO.KEY.GENERATION_FAILED or BROWSER_CRYPTO.NOT_AVAILABLE.


ecdsaP384.sign(privateKey, message): Promise<Uint8Array>

Signs message using ECDSA-P384 with SHA-384.

Parameter Type Description
privateKey Uint8Array PKCS8 DER private key bytes
message Uint8Array Bytes to sign

Returns: Promise<Uint8Array> — IEEE P1363 signature (96 bytes for P-384).

Throws: BrowserCryptoError — BROWSER_CRYPTO.OPERATION.FAILED or BROWSER_CRYPTO.NOT_AVAILABLE.


ecdsaP384.verify(publicKey, signature, message): Promise<boolean>

Verifies an ECDSA-P384 / SHA-384 signature.

Parameter Type Description
publicKey Uint8Array 97-byte uncompressed P-384 public key
signature Uint8Array IEEE P1363 signature bytes
message Uint8Array Original message bytes

Returns: Promise<boolean> — true if signature is valid.

Throws: BrowserCryptoError — BROWSER_CRYPTO.OPERATION.FAILED or BROWSER_CRYPTO.NOT_AVAILABLE.

Implementation Notes

SHA-384 is paired with P-384 because the security level of the hash should match that of the curve. Using SHA-256 with P-384 would create a mismatch: the 192-bit curve security would be limited to the 128-bit collision resistance of SHA-256.

The signature output format from crypto.subtle.sign for ECDSA is IEEE P1363 (raw R || S concatenation), not DER/ASN.1. This differs from OpenSSL's default DER encoding. When interoperating with systems that expect DER signatures, a conversion layer is needed.

P-384 key generation is typically 2–5× slower than P-256 due to the larger field size. For high-throughput signing workloads where P-256 security is sufficient, consider using webCryptoEcdsaP256Engine instead.