cryptutil

package module
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Jul 19, 2024 License: MIT Imports: 19 Imported by: 5

README

GoDoc

cryptutil

Some tools for handling common crypto tasks not found in the go standard library

ECDH Message encryption

Sometimes you want to send a message. Sometimes you want it encrypted. Sending an encrypted message to a ECDSA key can be painful and come with all sorts of difficulties.

This library aims to provide a simple encryption/decryption scheme that just takes a plaintext and a key and returns an encrypted string.

The decryption function accepts any kind of ECDH handler, allowing the actual private key to be stored into a TPM or a HSM.

Bottle

Bottles are containers for arbitrary data (json, cbor, anything) that can be used to add any number of signatures, encryption layers etc to the underlying message, while keeping recovery of the original message fairly easy.

// Create a new bottle with a message inside
bottle := cryptutil.NewBottle([]byte("s.o.s. to the world"))

// encrypt for Alice OR Bob (either will be able to open the bottle)
bottle.Encrypt(rand.Reader, bob.Public(), alice.Public())
bottle.BottleUp() // bottle in a bottle, so that the signature includes the encryption
bottle.Sign(rand.Reader, alice) // sign from Alice

// Bob is opening the bottle
opener, err := cryptutil.NewOpener(bob)
res, info, err := opener.Open(bottle)
// first, check err to see if opening the bottle was successful
// Then you can inspect info to see which signatures were verified, and how many
// layers of encryption were decrypted

ID Card

ID Cards can be used by entities with a signing key to provide alternate encryption keys.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	ErrNoAppropriateKey = errors.New("no appropriate key available to open bottle")
	ErrVerifyFailed     = errors.New("signature verification failed")
)
View Source
var EmptyOpener = &Opener{}

EmptyOpener is an opener without any keys that can open bottles, but can't check keys

Functions

func DecryptShortBuffer added in v0.1.1

func DecryptShortBuffer(k []byte, rcvd any) ([]byte, error)

DecryptShortBuffer decrypts a given buffer

func ECDHDecrypt

func ECDHDecrypt(data []byte, privateKey ECDHHandler) ([]byte, error)

ECDHDecrypt decrypts data received for us, using the private key passed (can be a tpm, etc)

func ECDHEncrypt

func ECDHEncrypt(rnd io.Reader, data []byte, remote *ecdh.PublicKey) ([]byte, error)

ECDHEncrypt encrypts data for receiving by remote

func EncryptShortBuffer added in v0.1.1

func EncryptShortBuffer(rand io.Reader, k []byte, rcvd crypto.PublicKey) ([]byte, error)

EncryptShortBuffer performs a simple encryption of a buffer

func Hash added in v0.1.1

func Hash(b []byte, alg ...func() hash.Hash) []byte

Hash is a helper function to perform hashes on buffers, including multi-level hashing

func MemClr added in v0.1.1

func MemClr(b []byte)

MemClr is a simple function that will clear a buffer in order to make it easier to reset memory storing private keys on defer.

func Sign added in v0.1.4

func Sign(rand io.Reader, key crypto.Signer, buf []byte, opts ...crypto.SignerOpts) ([]byte, error)

Sign generates a signature for the given buffer. Hash will be performed as needed

func Verify added in v0.1.4

func Verify(key crypto.PublicKey, buf, sig []byte, opts ...crypto.SignerOpts) error

Verify will verify the given buffer against the signature, depending on the key type. If the key is a RSA key and PSS options are given, then the signature will be handled as a PSS signature.

Unlike Verify methods found in most packages, this one takes in the actual buffer to be signed and will perform the hash if it needs to be done.

Types

type Bottle added in v0.1.1

type Bottle struct {
	Header     map[string]any      `json:"hdr,omitempty"` // extra values to be stored, will not be signed/encrypted unless the message is bottled
	Message    []byte              `json:"msg"`
	Format     MessageFormat       `json:"fmt"`
	Recipients []*MessageRecipient `json:"dst,omitempty"` // if Format != ClearText
	Signatures []*MessageSignature `json:"sig,omitempty"` // signature
	// contains filtered or unexported fields
}

Bottle is a signed, encrypted message container. Any Format other than ClearText means the Message contains a Bottle that has been encrypted.

func AsCborBottle added in v0.1.3

func AsCborBottle(data []byte) *Bottle

AsCborBottle considers data to be a cbor-encoded Bottle, and will return a Bottle container matching this assumption

func AsJsonBottle added in v0.1.3

func AsJsonBottle(data []byte) *Bottle

AsJsonBottle considers data to be a json-encoded Bottle, and will return a Bottle container matching this assumption

func Marshal added in v0.2.1

func Marshal(data any) (*Bottle, error)

Marshal will use cbor to marshal data into a bottle

func MarshalJson added in v0.2.2

func MarshalJson(data any) (*Bottle, error)

MarshalJson will use json to marshal data into a bottle

func NewBottle added in v0.1.1

func NewBottle(data []byte) *Bottle

NewBottle will return a new clean bottle only containing the provided data

func (*Bottle) BottleUp added in v0.1.1

func (m *Bottle) BottleUp() error

BottleUp encodes the current message into itself, allowing application of extra layers

func (*Bottle) Child added in v0.2.4

func (b *Bottle) Child() (*Bottle, error)

Child is the reverse operation as BottleUp and will return the bottle's child. This will fail if the bottle is encrypted or does not contain another bottle.

func (*Bottle) Encrypt added in v0.1.1

func (m *Bottle) Encrypt(rand io.Reader, recipients ...crypto.PublicKey) error

Encrypt encrypts the message so only recipients can decrypt it

func (*Bottle) IsCleanBottle added in v0.1.1

func (m *Bottle) IsCleanBottle() bool

IsCleanBottle returns true if the Bottle is clean (ie. so signature has been scribbed on top) and contains another Bottle.

func (*Bottle) Sign added in v0.1.1

func (m *Bottle) Sign(rand io.Reader, key crypto.Signer, opts ...crypto.SignerOpts) error

Sign signs the message, and can be called multiple times. Any message can be signed, including a raw message. It is however recommanded to bottle up an encrypted message before signing in order to ensure the encryption information is signed too.

Attempting to apply encryption to a message with a signature will always cause it to be bottled up

type ECDHHandler

type ECDHHandler interface {
	ECDH(remote *ecdh.PublicKey) ([]byte, error)
}

type IDCard added in v0.1.1

type IDCard struct {
	Self    []byte            `json:"self" cbor:"1,keyasint"` // our own public key (PKIX)
	Issued  time.Time         `json:"iss" cbor:"2,keyasint"`  // issuance date. If two IDCard exist for the same public key, the most recent one will be taken into account
	SubKeys []*SubKey         `json:"sub" cbor:"3,keyasint"`  // known sub keys
	Revoke  []*SubKey         `json:"rev" cbor:"4,keyasint"`  // any key into the revoke list will be strongly rejected
	Groups  []*Membership     `json:"grp" cbor:"5,keyasint"`  // groups this key is member of
	Meta    map[string]string `json:"meta" cbor:"6,keyasint"` // self-defined metadata
}

IDCard is a basic ID for a given signature key that allows it to specify keys that can be used for encryption/etc

func NewIDCard added in v0.1.1

func NewIDCard(k crypto.PublicKey) (*IDCard, error)

NewIDCard generates a new ID card for the given public key

func (*IDCard) GetKeys added in v0.1.1

func (id *IDCard) GetKeys(purpose string) []crypto.PublicKey

func (*IDCard) SetKeyDuration added in v0.1.1

func (id *IDCard) SetKeyDuration(k crypto.PublicKey, t time.Duration) error

SetKeyDuration specifies the duration for the given key

func (*IDCard) SetKeyPurposes added in v0.1.1

func (id *IDCard) SetKeyPurposes(k crypto.PublicKey, purposes ...string) error

SetKeyPurposes specifies the purpose of a given key (sign, decrypt, etc)

func (*IDCard) Sign added in v0.1.1

func (id *IDCard) Sign(rand io.Reader, k crypto.Signer) ([]byte, error)

Sign will return a signed bottle containing this ID Card

func (*IDCard) UnmarshalBinary added in v0.1.1

func (id *IDCard) UnmarshalBinary(b []byte) error

UnmarshalBinary will read a signed ID card, returning an error if it wasn't signed

type Membership added in v0.1.4

type Membership struct {
	Subject   []byte            `json:"sub" cbor:"1,keyasint"` // must be == parent.Self (if empty, fill with parent.Self before sig)
	Key       []byte            `json:"key" cbor:"2,keyasint"` // group key (group identification)
	Status    string            `json:"sta" cbor:"3,keyasint"` // status of membership (valid|suspended)
	Issued    time.Time         `json:"iss" cbor:"4,keyasint"` // update time of membership info
	Info      map[string]string `json:"nfo" cbor:"5,keyasint"` // subject information (name, etc)
	SignKey   []byte            `json:"sky" cbor:"6,keyasint"` // signature generating key (must be listed as sign key for the Key's IDCard)
	Signature []byte            `json:"sig" cbor:"7,keyasint"` // signature of structure with sign=nil by group key
}

Membership is a membership in a group.

func NewMembership added in v0.1.4

func NewMembership(member *IDCard, key []byte) *Membership

func (*Membership) Sign added in v0.1.4

func (m *Membership) Sign(rand io.Reader, key crypto.Signer, opts ...crypto.SignerOpts) error

Sign signs the membership using the provided key

func (*Membership) SignatureBytes added in v0.1.4

func (m *Membership) SignatureBytes() ([]byte, error)

SignatureBytes returns a representation of Membership that can be used to sign or verify the structure

func (*Membership) Verify added in v0.2.3

func (m *Membership) Verify(groupId *IDCard) error

Verify ensures the signature is correct. If the group ID is known, it must be passed.

type MessageFormat added in v0.1.1

type MessageFormat int
const (
	ClearText  MessageFormat = iota
	CborBottle               // bottle in a bottle
	AES                      // AES+AEAD encrypted cbor bottle
	JsonBottle               // bottle in a bottle (json version)
)

type MessageRecipient added in v0.1.1

type MessageRecipient struct {
	Type      int    `json:"typ,omitempty"` // always 0 (for now)
	Recipient []byte `json:"key"`           // recipient's public key
	Data      []byte `json:"dat"`           // encrypted key payload (only recipient's eyes)
	// contains filtered or unexported fields
}

func (*MessageRecipient) OpenWith added in v0.1.1

func (r *MessageRecipient) OpenWith(k any) ([]byte, error)

type MessageSignature added in v0.1.1

type MessageSignature struct {
	Type   int    `json:"typ,omitempty"` // always 0 (for now)
	Signer []byte `json:"key"`           // signature's key
	Data   []byte `json:"dat"`           // signature payload, similar format to jwt (NOTE: ECDSA signatures are weird)
	// contains filtered or unexported fields
}

func (*MessageSignature) Verify added in v0.1.1

func (sig *MessageSignature) Verify(buf []byte, opts ...crypto.SignerOpts) error

type OpenResult added in v0.1.1

type OpenResult struct {
	Decryption int                 // number of performed decryptions
	Signatures []*MessageSignature // verified message signatures
	Bottles    []*Bottle
}

func (*OpenResult) Last added in v0.2.1

func (or *OpenResult) Last() *Bottle

Last returns the last (inside-most) bottle

type Opener added in v0.1.1

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

Opener allows opening a Bottle

func MustOpener added in v0.2.1

func MustOpener(keys ...any) *Opener

MustOpener returns an opener that can be used to open a Bottle and panics if it fails

func NewOpener added in v0.1.1

func NewOpener(keys ...any) (*Opener, error)

NewOpener returns an opener that can be used to open a Bottle using any or all of the given keys.

func (*Opener) Open added in v0.1.1

func (o *Opener) Open(b *Bottle) ([]byte, *OpenResult, error)

Open opens the given Bottle, decrypting any encrypted elements, checking all signatures and returning the embedded buffer in the end

func (*Opener) OpenCbor added in v0.1.3

func (o *Opener) OpenCbor(b []byte) ([]byte, *OpenResult, error)

OpenCbor opens the given Bottle encoded as cbor data.

func (*Opener) OpenJson added in v0.1.3

func (o *Opener) OpenJson(b []byte) ([]byte, *OpenResult, error)

OpenJson opens the given Bottle encoded as json data.

func (*Opener) Unmarshal added in v0.2.1

func (o *Opener) Unmarshal(b *Bottle, v any) (*OpenResult, error)

Unmarshal will open the given bottle and pour the contents into v

func (*Opener) UnmarshalCbor added in v0.2.1

func (o *Opener) UnmarshalCbor(b []byte, v any) (*OpenResult, error)

UnmarshalCbor will open the given cbor-encoded bottle and pour the contents into v

func (*Opener) UnmarshalJson added in v0.2.1

func (o *Opener) UnmarshalJson(b []byte, v any) (*OpenResult, error)

UnmarshalJson will open the given json-encoded bottle and pour the contents into v

type SubKey added in v0.1.1

type SubKey struct {
	Key      []byte     `json:"key" cbor:"1,keyasint"`                     // public key as PKIX
	Issued   time.Time  `json:"iss" cbor:"2,keyasint"`                     // issuance (addition) date
	Expires  *time.Time `json:"exp,omitempty" cbor:"3,keyasint,omitempty"` // expiration date (if any)
	Purposes []string   `json:"pur" cbor:"4,keyasint"`                     // purposes: can contain "sign", "decrypt"
}

SubKey is a key found in a given id card

Jump to

Keyboard shortcuts

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