AwsEncryptionSdk.Crypto.ECDSA (AWS Encryption SDK v1.0.0)

View Source

ECDSA operations for AWS Encryption SDK.

Provides key generation and encoding for P-384 (secp384r1) curve used by signed algorithm suites.

Spec Reference

https://github.com/awslabs/aws-encryption-sdk-specification/blob/master/framework/algorithm-suites.md

Summary

Functions

Decodes a base64-encoded public key from encryption context.

Encodes a public key to base64 for storage in encryption context.

Generates an ECDSA key pair for the P-384 curve.

Normalizes a public key to uncompressed format.

Generates an ECDSA signature over the given message using SHA-384.

Signs a pre-computed digest using ECDSA P-384.

Verifies an ECDSA signature over the given message using SHA-384.

Verifies an ECDSA signature against a pre-computed digest.

Types

curve()

@type curve() :: :secp384r1 | :secp256r1

key_pair()

@type key_pair() :: {private_key :: binary(), public_key :: binary()}

Functions

decode_public_key(encoded)

@spec decode_public_key(String.t()) :: {:ok, binary()} | {:error, :invalid_base64}

Decodes a base64-encoded public key from encryption context.

Examples

iex> {_private_key, public_key} = AwsEncryptionSdk.Crypto.ECDSA.generate_key_pair(:secp384r1)
iex> encoded = AwsEncryptionSdk.Crypto.ECDSA.encode_public_key(public_key)
iex> {:ok, decoded} = AwsEncryptionSdk.Crypto.ECDSA.decode_public_key(encoded)
iex> decoded == public_key
true

encode_public_key(public_key)

@spec encode_public_key(binary()) :: String.t()

Encodes a public key to base64 for storage in encryption context.

The public key is stored as-is (uncompressed point format) and base64 encoded.

Examples

iex> {_private_key, public_key} = AwsEncryptionSdk.Crypto.ECDSA.generate_key_pair(:secp384r1)
iex> encoded = AwsEncryptionSdk.Crypto.ECDSA.encode_public_key(public_key)
iex> String.printable?(encoded)
true

generate_key_pair(atom)

@spec generate_key_pair(curve()) :: key_pair()

Generates an ECDSA key pair for the P-384 curve.

Returns {private_key, public_key} where:

  • private_key is the raw private key bytes
  • public_key is the uncompressed public key point

Examples

iex> {private_key, public_key} = AwsEncryptionSdk.Crypto.ECDSA.generate_key_pair(:secp384r1)
iex> byte_size(private_key)
48
iex> byte_size(public_key)
97

normalize_public_key(uncompressed_key, curve)

@spec normalize_public_key(binary(), curve()) :: binary()

Normalizes a public key to uncompressed format.

Handles both compressed (0x02/0x03 prefix, 49 bytes for P-384 or 33 bytes for P-256) and uncompressed (0x04 prefix, 97 bytes for P-384 or 65 bytes for P-256) formats.

The curve is auto-detected from the key size when possible:

  • 33 bytes compressed or 65 bytes uncompressed → secp256r1
  • 49 bytes compressed or 97 bytes uncompressed → secp384r1

sign(message, private_key, atom)

@spec sign(binary(), binary(), curve()) :: binary()

Generates an ECDSA signature over the given message using SHA-384.

Parameters

  • message - Binary data to sign
  • private_key - Raw private key bytes (48 bytes for P-384)
  • curve - Elliptic curve to use (:secp384r1)

Returns

  • DER-encoded ECDSA signature

Examples

iex> {private_key, _public_key} = AwsEncryptionSdk.Crypto.ECDSA.generate_key_pair(:secp384r1)
iex> message = "test message"
iex> signature = AwsEncryptionSdk.Crypto.ECDSA.sign(message, private_key, :secp384r1)
iex> is_binary(signature)
true

sign_digest(digest, private_key)

@spec sign_digest(binary(), binary()) :: binary()

Signs a pre-computed digest using ECDSA P-384.

This is useful for streaming where the hash is accumulated incrementally.

Parameters

  • digest - SHA-384 digest (48 bytes)
  • private_key - Raw private key bytes

Returns

  • DER-encoded ECDSA signature

Examples

iex> {private_key, _public_key} = AwsEncryptionSdk.Crypto.ECDSA.generate_key_pair(:secp384r1)
iex> digest = :crypto.hash(:sha384, "test message")
iex> signature = AwsEncryptionSdk.Crypto.ECDSA.sign_digest(digest, private_key)
iex> is_binary(signature)
true

verify(message, signature, public_key, atom)

@spec verify(binary(), binary(), binary(), curve()) :: boolean()

Verifies an ECDSA signature over the given message using SHA-384.

Parameters

  • message - Binary data that was signed
  • signature - DER-encoded ECDSA signature
  • public_key - Raw public key bytes (97 bytes uncompressed point for P-384)
  • curve - Elliptic curve to use (:secp384r1)

Returns

  • true if signature is valid
  • false if signature is invalid

Examples

iex> {private_key, public_key} = AwsEncryptionSdk.Crypto.ECDSA.generate_key_pair(:secp384r1)
iex> message = "test message"
iex> signature = AwsEncryptionSdk.Crypto.ECDSA.sign(message, private_key, :secp384r1)
iex> AwsEncryptionSdk.Crypto.ECDSA.verify(message, signature, public_key, :secp384r1)
true

verify_digest(digest, signature, public_key)

@spec verify_digest(binary(), binary(), binary()) :: boolean()

Verifies an ECDSA signature against a pre-computed digest.

Parameters

  • digest - SHA-384 digest (48 bytes)
  • signature - DER-encoded ECDSA signature
  • public_key - Raw public key bytes

Returns

  • true if valid, false otherwise

Examples

iex> {private_key, public_key} = AwsEncryptionSdk.Crypto.ECDSA.generate_key_pair(:secp384r1)
iex> digest = :crypto.hash(:sha384, "test message")
iex> signature = AwsEncryptionSdk.Crypto.ECDSA.sign_digest(digest, private_key)
iex> AwsEncryptionSdk.Crypto.ECDSA.verify_digest(digest, signature, public_key)
true