ke

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 20, 2026 License: BSD-2-Clause Imports: 11 Imported by: 0

Documentation

Overview

Package ke implements TLS 1.2 key exchange methods.

Each Exchange implementation produces a ClientKeyExchange message body (cke) and the pre-master secret (preMaster) used by suites.MasterSecret.

Implementations: ECDHEExchange (P-256/P-384/P-521/X25519), RSAExchange, DHEExchange. GOST VKO is Phase 6.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DHEComputePublic

func DHEComputePublic(pBytes, baseBytes, exponentBytes []byte) ([]byte, error)

DHEComputePublic computes base^exponent mod p using constant-time bigmod arithmetic. pBytes is the group prime; baseBytes is the base (g for computing public key, Yc for shared secret); exponentBytes is the private exponent x. Returns the result left-padded to len(pBytes) bytes.

Note: This function does NOT validate the DHE parameters (it is used for both key generation and shared-secret computation by trusted callers). Callers that receive base from an untrusted source must validate with validateDHEParams first.

func ECDHGeneratePublic

func ECDHGeneratePublic(seed []byte) (privBytes, pubBytes []byte, err error)

ECDHGeneratePublic generates an ECDH P-256 public key from a fixed 32-byte seed. Returns the raw private key bytes and the uncompressed public key bytes. Used in tests to build deterministic server ECDHE parameters.

func GOST2001TestPublicKeyFromPrivate

func GOST2001TestPublicKeyFromPrivate(prvRaw []byte) ([]byte, error)

GOST2001TestPublicKeyFromPrivate derives the GOST R 34.10-2001 public key from a private key using the test parameter set curve. Used in tests to generate the public key for the upstream test vectors (which use CurveIdGostR34102001TestParamSet, not CryptoPro-A).

func NewVKOGost2001ExchangeTestCurve

func NewVKOGost2001ExchangeTestCurve(prvRaw, pubRaw, ukm []byte) *vkoGost2001TestCurveExchange

NewVKOGost2001ExchangeTestCurve creates a VKOGost2001Exchange that uses the GOST R 34.10-2001 test parameter set curve (not CryptoPro-A). Used only in unit tests that verify round-trip logic with upstream gogost test vectors.

Production code uses NewVKOGost2001ExchangeWithKey (CryptoPro-A curve).

Types

type DHEExchange

type DHEExchange struct {
	// contains filtered or unexported fields
}

DHEExchange implements the finite-field Diffie-Hellman Ephemeral (DHE) key exchange for TLS 1.2 (RFC 5246 §7.4.3, §8.1.2).

ServerParams encoding

The raw ServerKeyExchange body per RFC 5246 §7.4.3:

dh_p    opaque <1..2^16-1>   — big-endian big integer
dh_g    opaque <1..2^16-1>
dh_Ys   opaque <1..2^16-1>

Each field is length-prefixed with a 2-byte big-endian length.

Parameter validation (fail-fast)

  • p must be at least 1024 bits (128 bytes).
  • p must be odd (even p is not prime, hence invalid).
  • g must be ≥ 2.
  • 1 < Ys < p-1 (strict bounds; identity element and p-1 are both rejected).

For RFC 7919 named groups (ffdhe2048, ffdhe3072): the Ys^q ≡ 1 (mod p) check where q = (p-1)/2 is implied by the bounds check on safe primes. RFC 7919 ffdhe groups are safe primes (p = 2q+1, q prime), so the only elements of order ≤ 2 in (Z/pZ)* are {1, p-1}. Both are already caught by the strict range check. For non-named groups we skip the subgroup check (non-named groups may not be safe primes and the server is trusted per TLS).

Constant-time invariant

The private exponent x and the shared secret Z = Ys^x mod p are computed exclusively with filippo.io/bigmod.Nat.Exp — a constant-time Montgomery modular exponentiation — never with math/big.Int.Exp.

math/big is used ONLY for public operations:

  • Parsing p, g, Ys from bytes (math/big.Int.SetBytes — public data)
  • Computing p-1 for the bounds check (public data)
  • Comparing Ys against 1 and p-1 (public data)
  • Checking g ≥ 2 (public data)

ClientKeyExchange body format

Per RFC 5246 §7.4.7.2:

dh_Yc   opaque <1..2^16-1>   (2-byte length + client public key bytes)

Pre-master secret

Z = Ys^x mod p, left-padded with zero bytes to len(p) bytes per RFC 5246 §8.1.2.

func NewDHEExchange

func NewDHEExchange(privateX []byte) *DHEExchange

NewDHEExchange creates a DHEExchange.

privateX optionally fixes the client private exponent for testing. In production, pass nil to use a securely random exponent.

func (*DHEExchange) ClientKeyExchange

func (d *DHEExchange) ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)

ClientKeyExchange parses the ServerKeyExchange DHE params, validates them, generates (or reuses) a client private exponent, computes the shared secret, and returns the CKE body and pre-master secret.

type ECDHEExchange

type ECDHEExchange struct{}

ECDHEExchange implements the ECDHE (Elliptic Curve Diffie-Hellman Ephemeral) key exchange for TLS 1.2.

Supported named curves (RFC 4492 NamedCurve values):

  • 0x0017: secp256r1 (P-256)
  • 0x0018: secp384r1 (P-384)
  • 0x0019: secp521r1 (P-521)
  • 0x001D: x25519

ServerParams format (RFC 5246 §7.4.3 / RFC 4492 §5.4):

curve_type   uint8  = 3 (named_curve; any other value is rejected)
named_curve  uint16
point_len    uint8
point        [point_len]byte  (uncompressed for P-curves; raw 32 bytes for X25519)

ClientKeyExchange body (cke):

point_len    uint8
point        [point_len]byte  (client ephemeral public key)

Pre-master secret: the X coordinate (P-curves) or raw output (X25519) of the ECDH shared secret, with leading zeros preserved to the curve's fixed size.

func NewECDHEExchange

func NewECDHEExchange() *ECDHEExchange

NewECDHEExchange creates an ECDHEExchange.

func (*ECDHEExchange) ClientKeyExchange

func (e *ECDHEExchange) ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)

ClientKeyExchange generates a client ephemeral keypair, computes the shared secret against the server's public key, and returns the CKE body and pre-master secret.

type Exchange

type Exchange interface {
	// ClientKeyExchange computes the client's key-exchange contribution.
	//
	// cke is the raw ClientKeyExchange message body sent on the wire.
	// preMaster is the pre-master secret fed into MasterSecret.
	// err is non-nil if the server parameters are invalid or crypto fails.
	ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)
}

Exchange is the interface implemented by all TLS 1.2 key exchange methods.

ServerParams encoding per key exchange type:

  • ECDHE: raw body of the ServerKeyExchange message, starting with curve_type (1 byte) then named_curve (2 bytes) then server public key length-prefixed (1 byte). Defined in RFC 5246 §7.4.3 / RFC 4492 §5.4.
  • DHE: raw body of the ServerKeyExchange message: dh_p (2-byte length + data), dh_g (2-byte length + data), dh_Ys (2-byte length + data). Defined in RFC 5246 §7.4.3.
  • RSA: RSAExchange holds *rsa.PublicKey directly; ServerParams is ignored (pass nil). The server public key comes from the server certificate, not from a ServerKeyExchange message.

func NewECDHEExchangeWithRand

func NewECDHEExchangeWithRand(rnd io.Reader) Exchange

NewECDHEExchangeWithRand creates an ECDHEExchange that reads from rnd instead of crypto/rand.Reader. If rnd is nil, crypto/rand.Reader is used.

func NewRSAExchangeWithRand

func NewRSAExchangeWithRand(rnd io.Reader, pub *rsa.PublicKey) Exchange

NewRSAExchangeWithRand creates an RSAExchange that reads from rnd. If rnd is nil, crypto/rand.Reader is used.

type Gost2018Exchange

type Gost2018Exchange struct {
	// contains filtered or unexported fields
}

Gost2018Exchange implements the Exchange interface for GOST 2018 key exchange (draft-smyshlyaev-tls12-gost-suites, suites 0xC100 / 0xC101).

The exchange generates an ephemeral GOST R 34.10-2012 keypair, derives the 64-byte key material via KEG2012_256, and wraps the pre-master secret using kexp15 (R 1323565.1.020-2018 §6.3.2). The result is encoded as a PSKeyTransport_gost ASN.1 structure (tmp/engine/gost_asn1.c:70-76).

func NewGost2018Exchange

func NewGost2018Exchange(
	curve *gost.Curve,
	spkiAlgo, serverPubRaw []byte,
	variant Gost2018Variant,
	randoms []byte,
) (*Gost2018Exchange, error)

NewGost2018Exchange creates a Gost2018Exchange ready to produce a CKE.

curve must be the GOST R 34.10-2012 256-bit curve from the server certificate (resolve via gost.CurveByOID). spkiAlgo is the raw DER of the server cert's SPKI AlgorithmIdentifier (used verbatim in the ephemeral SPKI). serverPubRaw is the 64-byte raw public key. variant selects Kuznyechik or Magma.

randoms is clientRandom || serverRandom (64 bytes). Per OpenSSL ssl/statem/statem_clnt.c:ossl_gost_ukm, the TLS 1.2 GOST 2018 UKM is Streebog-256(clientRandom || serverRandom) — not a fresh random. The server derives the same UKM independently and uses it to unwrap the CKE; if the UKM on the wire differs, `gost_kimp15` returns BAD_MAC and the handshake aborts. Callers may pass nil only for unit tests; production callers from the TLS handshake path must supply the 64-byte concatenation.

rng is injectable for deterministic testing; pass nil to use crypto/rand.Reader.

func (*Gost2018Exchange) ClientKeyExchange

func (e *Gost2018Exchange) ClientKeyExchange(_ []byte) (cke, preMaster []byte, err error)

ClientKeyExchange implements Exchange for GOST 2018 KEX.

serverParams is ignored — the server public key was provided at construction time; GOST 2018 suites do not send a ServerKeyExchange message.

Orchestration reference: tmp/engine/gost_ec_keyx.c:413-551 (pkey_gost2018_encrypt).

type Gost2018Variant

type Gost2018Variant int

Gost2018Variant selects the block cipher used for kexp15 key transport. Mirrors gost.KexpVariant but lives in ke for the public-surface Export.

const (
	// Variant2018Kuznyechik uses Kuznyechik (128-bit block, iv_len=8, mac_len=16).
	// Corresponds to TLS suite 0xC100.
	Variant2018Kuznyechik Gost2018Variant = iota

	// Variant2018Magma uses Magma (64-bit block, iv_len=4, mac_len=8).
	// Corresponds to TLS suite 0xC101.
	Variant2018Magma
)

type RSAExchange

type RSAExchange struct {
	// contains filtered or unexported fields
}

RSAExchange implements the RSA key exchange for TLS 1.2 (RFC 5246 §7.4.7.1).

The server public key is loaded at construction time (from the server certificate). There is no ServerKeyExchange message for RSA key exchange. ServerParams passed to ClientKeyExchange is ignored; pass nil.

Pre-master secret: 48 bytes with version prefix {0x03, 0x03} followed by 46 random bytes.

ClientKeyExchange body (cke): per RFC 5246 §7.4.7.1, a uint16 big-endian length prefix followed by the PKCS#1 v1.5 encrypted pre-master secret. Its length is 2 + modulus bytes (e.g. 258 bytes for RSA-2048).

func NewRSAExchange

func NewRSAExchange(pub *rsa.PublicKey) *RSAExchange

NewRSAExchange creates an RSAExchange with the server's RSA public key. pub must not be nil.

func (*RSAExchange) ClientKeyExchange

func (r *RSAExchange) ClientKeyExchange(serverParams []byte) (cke []byte, preMaster []byte, err error)

ClientKeyExchange generates a 48-byte pre-master secret with version prefix {0x03, 0x03}, encrypts it with the server's RSA public key using PKCS#1 v1.5, and returns the encrypted bytes as the ClientKeyExchange body.

serverParams is ignored (RSA key exchange has no ServerKeyExchange); pass nil.

type VKOGost2001Exchange

type VKOGost2001Exchange struct {
	// contains filtered or unexported fields
}

VKOGost2001Exchange implements Exchange for GOST2001-GOST89-GOST89 (suite ID 0x0081). It uses GOST R 34.10-2001 VKO key agreement (RFC 4357) combined with CryptoPro key wrap to produce a GOST_KEY_TRANSPORT envelope, matching gost-engine's pkey_GOST_ECcp_encrypt.

The client generates a fresh ephemeral key pair per handshake on the same curve carried by the server's certificate.

func NewVKOGost2001Exchange

func NewVKOGost2001Exchange(curve *gost.Curve, spkiAlgo, pubRaw, ukm []byte) (*VKOGost2001Exchange, error)

NewVKOGost2001Exchange creates a VKOGost2001Exchange that generates a fresh ephemeral key pair on the given curve. curve must match the curve OID from the server certificate (resolve via gost.CurveByOID). spkiAlgo is the DER of the server cert's SPKI AlgorithmIdentifier; it is reused to build the ephemeral key's SPKI inside the GOST_KEY_TRANSPORT envelope. pubRaw is the server's GOST R 34.10-2001 public key from the server certificate SPKI. ukm is derived from client_random (first 8 bytes).

func (*VKOGost2001Exchange) ClientKeyExchange

func (e *VKOGost2001Exchange) ClientKeyExchange(_ []byte) (cke []byte, preMaster []byte, err error)

ClientKeyExchange implements Exchange for VKO2001.

serverParams is ignored (GOST suites have no ServerKeyExchange; the server public key was provided at construction time via pubRaw).

Produces a GOST_KEY_TRANSPORT-wrapped ClientKeyExchange body per RFC 9189 §4.1 and gost-engine's pkey_GOST_ECcp_encrypt (tmp/engine/gost_ec_keyx.c:277-407). The 32-byte premaster is a fresh random value wrapped via CryptoPro key wrap under the VKO2001-derived shared key (CryptoPro-A S-box); the wrap output goes into GOST_KEY_INFO, and the ephemeral public key + UKM go into GOST_KEY_AGREEMENT_INFO.

type VKOGost2012_256Exchange

type VKOGost2012_256Exchange struct {
	// contains filtered or unexported fields
}

VKOGost2012_256Exchange implements Exchange for GOST2012-GOST8912-GOST8912 (suite IDs 0xFF85 / 0xC102). It uses GOST R 34.10-2012 VKO with 256-bit KEK (RFC 7836) on the curve carried by the server certificate. Observed curves in Tarantool-EE fixtures include id-GostR3410-2001-CryptoPro-A (256-bit) for GOST2012-256 certificates; the 512-bit paramSetA may also appear.

func NewVKOGost2012_256Exchange

func NewVKOGost2012_256Exchange(curve *gost.Curve, spkiAlgo, pubRaw, ukm []byte) (*VKOGost2012_256Exchange, error)

NewVKOGost2012_256Exchange creates a VKOGost2012_256Exchange with a fresh ephemeral key on the given curve. curve must match the server certificate's CurveOID (resolve via gost.CurveByOID). spkiAlgo is the DER of the server cert's SPKI AlgorithmIdentifier (x509gost.Certificate.SPKIAlgorithmDER); it is reused to build the ephemeral key's SPKI inside the GOST_KEY_TRANSPORT envelope. pubRaw is the server's public key bytes. ukm is derived from client_random (first 8 bytes).

func (*VKOGost2012_256Exchange) ClientKeyExchange

func (e *VKOGost2012_256Exchange) ClientKeyExchange(_ []byte) (cke []byte, preMaster []byte, err error)

ClientKeyExchange implements Exchange for VKO2012_256.

Produces a GOST_KEY_TRANSPORT-wrapped ClientKeyExchange body per RFC 9189 §4.1 and gost-engine's pkey_GOST_ECcp_encrypt. The 32-byte premaster is a fresh random value wrapped via CryptoPro key wrap under the VKO-derived shared key; the wrap output goes into GOST_KEY_INFO, and the ephemeral public key + UKM go into GOST_KEY_AGREEMENT_INFO.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL