Help us shape the future of Go! Take the 2026 Go Developer Survey

uploads

package
v0.1.331 Latest Latest
Warning

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

Go to latest
Published: Oct 4, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package uploads provides helpers for client-side-encrypted upload storage: the wire envelope shape and Seal / Parse / Open functions that mirror the browser's encryption.ts.

Index

Examples

Constants

View Source
const EncryptionAlgorithm = "RSA_DECRYPT_OAEP_3072_SHA256"

EncryptionAlgorithm is the KMS algorithm string the client is hardcoded against. The org public key endpoint advertises this; SealEnvelope refuses to run against any other value rather than silently producing payloads no reader can decrypt.

Variables

This section is empty.

Functions

func OpenEnvelope

func OpenEnvelope(payload string, unwrapAESKey func(wrappedKey []byte) (aesKey []byte, err error)) ([]byte, error)

OpenEnvelope is the inverse of SealEnvelope. The caller supplies an unwrap function that decrypts the RSA-OAEP-wrapped AES key (typically a KMS AsymmetricDecrypt call against the version recorded in env.KeyVersion); this package stays GCP-free.

The split lets break-glass / reader code reuse the same AES-GCM / base64 logic the upload side uses, without forcing every SDK consumer to pull in cloud.google.com/go/kms.

func SealEnvelope

func SealEnvelope(plaintext []byte, publicKeyPEM, algorithm, keyVersion string) (string, error)

SealEnvelope produces the JSON-encoded payload string the upload service expects in the request's payload field. It mirrors the browser's hybrid AES-GCM / RSA-OAEP encryption minus the network call:

  1. Generate a fresh AES-256 key + 12-byte IV.
  2. AES-256-GCM encrypt the plaintext.
  3. Parse the SPKI PEM into an RSA public key.
  4. RSA-OAEP-SHA256 wrap the AES key.
  5. Base64-encode each binary field, marshal the envelope.

The algorithm parameter is the value advertised by the server's GetOrgPublicKey response; mismatch against the client's hardcoded EncryptionAlgorithm is a hard failure rather than silently producing payloads no reader can decrypt.

keyVersion is the CryptoKeyVersion (e.g. "1") that wrapped this envelope, recorded so post-rotation readers know which private key to call AsymmetricDecrypt against.

Types

type Envelope

type Envelope struct {
	Ciphertext   string `json:"ciphertext"`
	EncryptedKey string `json:"encryptedKey"`
	IV           string `json:"iv"`
	Timestamp    string `json:"timestamp"`

	// KeyVersion is the integer CryptoKeyVersion the client used for
	// RSA-OAEP wrapping (matches Cloud KMS' version numbering, e.g. "1").
	// Carried in the envelope so decrypters can pick the right version
	// regardless of what's currently the published primary — required
	// for any post-rotation read of pre-rotation blobs. Empty means "1"
	// for backward compatibility with envelopes uploaded before this
	// field existed.
	KeyVersion string `json:"keyVersion,omitempty"`
}

Envelope is the wire shape the client encrypts and the server stores as-is. All binary fields are base64-encoded; the server treats the JSON-encoded envelope as opaque and never inspects its contents.

func ParseEnvelope

func ParseEnvelope(payload string) (*Envelope, error)

ParseEnvelope decodes the JSON envelope without performing the RSA-OAEP/AES-GCM decryption. Useful on the upload path when the server wants to read non-sensitive metadata (Timestamp) without touching the plaintext.

Example

ExampleParseEnvelope demonstrates decoding a JSON envelope without performing any cryptographic operations.

package main

import (
	"fmt"

	"chainguard.dev/sdk/uploads"
)

func main() {
	payload := `{"ciphertext":"abc=","encryptedKey":"def=","iv":"ghi=","timestamp":"2024-01-01T00:00:00Z","keyVersion":"1"}`
	env, err := uploads.ParseEnvelope(payload)
	fmt.Println(err)
	fmt.Println(env.KeyVersion)
	fmt.Println(env.Timestamp)
}
Output:
<nil>
1
2024-01-01T00:00:00Z
Example (Invalid)

ExampleParseEnvelope_invalid demonstrates the error returned when the payload is not a valid JSON envelope.

package main

import (
	"fmt"

	"chainguard.dev/sdk/uploads"
)

func main() {
	_, err := uploads.ParseEnvelope("not-json")
	fmt.Println(err != nil)
}
Output:
true

Jump to

Keyboard shortcuts

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