jwe

package
v1.2.25 Latest Latest
Warning

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

Go to latest
Published: May 23, 2022 License: MIT Imports: 32 Imported by: 17

README

JWE Go Reference

Package jwe implements JWE as described in RFC7516

  • Encrypt and Decrypt arbitrary data
  • Content compression and decompression
  • Add arbitrary fields in the JWE header object

How-to style documentation can be found in the docs directory.

Examples are located in the examples directory (jwe_example_test.go)

Supported key encryption algorithm:

Algorithm Supported? Constant in jwa
RSA-PKCS1v1.5 YES jwa.RSA1_5
RSA-OAEP-SHA1 YES jwa.RSA_OAEP
RSA-OAEP-SHA256 YES jwa.RSA_OAEP_256
AES key wrap (128) YES jwa.A128KW
AES key wrap (192) YES jwa.A192KW
AES key wrap (256) YES jwa.A256KW
Direct encryption YES (1) jwa.DIRECT
ECDH-ES YES (1) jwa.ECDH_ES
ECDH-ES + AES key wrap (128) YES jwa.ECDH_ES_A128KW
ECDH-ES + AES key wrap (192) YES jwa.ECDH_ES_A192KW
ECDH-ES + AES key wrap (256) YES jwa.ECDH_ES_A256KW
AES-GCM key wrap (128) YES jwa.A128GCMKW
AES-GCM key wrap (192) YES jwa.A192GCMKW
AES-GCM key wrap (256) YES jwa.A256GCMKW
PBES2 + HMAC-SHA256 + AES key wrap (128) YES jwa.PBES2_HS256_A128KW
PBES2 + HMAC-SHA384 + AES key wrap (192) YES jwa.PBES2_HS384_A192KW
PBES2 + HMAC-SHA512 + AES key wrap (256) YES jwa.PBES2_HS512_A256KW
  • Note 1: Single-recipient only

Supported content encryption algorithm:

Algorithm Supported? Constant in jwa
AES-CBC + HMAC-SHA256 (128) YES jwa.A128CBC_HS256
AES-CBC + HMAC-SHA384 (192) YES jwa.A192CBC_HS384
AES-CBC + HMAC-SHA512 (256) YES jwa.A256CBC_HS512
AES-GCM (128) YES jwa.A128GCM
AES-GCM (192) YES jwa.A192GCM
AES-GCM (256) YES jwa.A256GCM

SYNOPSIS

Encrypt data

func ExampleEncrypt() {
  privkey, err := rsa.GenerateKey(rand.Reader, 2048)
  if err != nil {
    log.Printf("failed to generate private key: %s", err)
    return
  }

  payload := []byte("Lorem Ipsum")

  encrypted, err := jwe.Encrypt(payload, jwa.RSA1_5, &privkey.PublicKey, jwa.A128CBC_HS256, jwa.NoCompress)
  if err != nil {
    log.Printf("failed to encrypt payload: %s", err)
    return
  }
  _ = encrypted
  // OUTPUT:
}

Decrypt data

func ExampleDecrypt() {
  privkey, encrypted, err := exampleGenPayload()
  if err != nil {
    log.Printf("failed to generate encrypted payload: %s", err)
    return
  }

  decrypted, err := jwe.Decrypt(encrypted, jwa.RSA1_5, privkey)
  if err != nil {
    log.Printf("failed to decrypt: %s", err)
    return
  }

  if string(decrypted) != "Lorem Ipsum" {
    log.Printf("WHAT?!")
    return
  }
  // OUTPUT:
}

Documentation

Overview

Package jwe implements JWE as described in https://tools.ietf.org/html/rfc7516

Index

Constants

View Source
const (
	AgreementPartyUInfoKey    = "apu"
	AgreementPartyVInfoKey    = "apv"
	AlgorithmKey              = "alg"
	CompressionKey            = "zip"
	ContentEncryptionKey      = "enc"
	ContentTypeKey            = "cty"
	CriticalKey               = "crit"
	EphemeralPublicKeyKey     = "epk"
	JWKKey                    = "jwk"
	JWKSetURLKey              = "jku"
	KeyIDKey                  = "kid"
	TypeKey                   = "typ"
	X509CertChainKey          = "x5c"
	X509CertThumbprintKey     = "x5t"
	X509CertThumbprintS256Key = "x5t#S256"
	X509URLKey                = "x5u"
)
View Source
const (
	AuthenticatedDataKey    = "aad"
	CipherTextKey           = "ciphertext"
	CountKey                = "p2c"
	InitializationVectorKey = "iv"
	ProtectedHeadersKey     = "protected"
	RecipientsKey           = "recipients"
	SaltKey                 = "p2s"
	TagKey                  = "tag"
	UnprotectedHeadersKey   = "unprotected"
	HeadersKey              = "header"
	EncryptedKeyKey         = "encrypted_key"
)

Variables

This section is empty.

Functions

func Compact added in v1.0.0

func Compact(m *Message, _ ...SerializerOption) ([]byte, error)

Compact encodes the given message into a JWE compact serialization format.

Currently `Compact()` does not take any options, but the API is set up as such to allow future expansions

func Decrypt

func Decrypt(buf []byte, alg jwa.KeyEncryptionAlgorithm, key interface{}, options ...DecryptOption) ([]byte, error)

Decrypt takes the key encryption algorithm and the corresponding key to decrypt the JWE message, and returns the decrypted payload. The JWE message can be either compact or full JSON format.

`key` must be a private key. It can be either in its raw format (e.g. *rsa.PrivateKey) or a jwk.Key

func Encrypt

func Encrypt(payload []byte, keyalg jwa.KeyEncryptionAlgorithm, key interface{}, contentalg jwa.ContentEncryptionAlgorithm, compressalg jwa.CompressionAlgorithm, options ...EncryptOption) ([]byte, error)

Encrypt takes the plaintext payload and encrypts it in JWE compact format. `key` should be a public key, and it may be a raw key (e.g. rsa.PublicKey) or a jwk.Key

Encrypt currently does not support multi-recipient messages.

func JSON added in v1.0.0

func JSON(m *Message, options ...SerializerOption) ([]byte, error)

JSON encodes the message into a JWE JSON serialization format.

If `WithPrettyFormat(true)` is passed as an option, the returned value will be formatted using `json.MarshalIndent()`

func RegisterCustomField added in v1.1.2

func RegisterCustomField(name string, object interface{})

RegisterCustomField allows users to specify that a private field be decoded as an instance of the specified type. This option has a global effect.

For example, suppose you have a custom field `x-birthday`, which you want to represent as a string formatted in RFC3339 in JSON, but want it back as `time.Time`.

In that case you would register a custom field as follows

jwe.RegisterCustomField(`x-birthday`, timeT)

Then `hdr.Get("x-birthday")` will still return an `interface{}`, but you can convert its type to `time.Time`

bdayif, _ := hdr.Get(`x-birthday`)
bday := bdayif.(time.Time)

Types

type DecryptCtx added in v1.2.2

type DecryptCtx interface {
	Algorithm() jwa.KeyEncryptionAlgorithm
	SetAlgorithm(jwa.KeyEncryptionAlgorithm)
	Key() interface{}
	SetKey(interface{})
	Message() *Message
	SetMessage(*Message)
}

DecryptCtx is used internally when jwe.Decrypt is called, and is passed for hooks that you may pass into it.

Regular users should not have to touch this object, but if you need advanced handling of messages, you might have to use it. Only use it when you really understand how JWE processing works in this library.

type DecryptOption added in v1.2.2

type DecryptOption interface {
	Option
	// contains filtered or unexported methods
}

func WithMessage added in v1.2.2

func WithMessage(m *Message) DecryptOption

WithMessage provides a message object to be populated by `jwe.Decrpt` Using this option allows you to decrypt AND obtain the `jwe.Message` in one go.

Note that you should NOT be using the message object for anything other than inspecting its contents. Particularly, do not expect the message reliable when you call `Decrypt` on it. `(jwe.Message).Decrypt` is slated to be deprecated in the next major version.

func WithPostParser added in v1.2.2

func WithPostParser(p PostParser) DecryptOption

WithPostParser specifies the handler to be called immediately after the JWE message has been parsed, but before decryption takes place during `jwe.Decrypt`.

This option exists to allow advanced users that require the use of information stored in the JWE message to determine how the decryption should be handled.

For security reasons it is highly recommended that you thoroughly study how the process works before using this option. This is especially true if you are trying to infer key algorithms and keys to use to decrypt a message using non-standard hints.

type Decrypter added in v1.0.6

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

Decrypter is responsible for taking various components to decrypt a message. its operation is not concurrency safe. You must provide locking yourself

func NewDecrypter added in v1.0.6

func NewDecrypter(keyalg jwa.KeyEncryptionAlgorithm, ctalg jwa.ContentEncryptionAlgorithm, privkey interface{}) *Decrypter

NewDecrypter Creates a new Decrypter instance. You must supply the rest of parameters via their respective setter methods before calling Decrypt().

privkey must be a private key in its "raw" format (i.e. something like *rsa.PrivateKey, instead of jwk.Key)

You should consider this object immutable once you assign values to it.

func (*Decrypter) AgreementPartyUInfo added in v1.0.6

func (d *Decrypter) AgreementPartyUInfo(apu []byte) *Decrypter

func (*Decrypter) AgreementPartyVInfo added in v1.0.6

func (d *Decrypter) AgreementPartyVInfo(apv []byte) *Decrypter

func (*Decrypter) AuthenticatedData added in v1.0.6

func (d *Decrypter) AuthenticatedData(aad []byte) *Decrypter

func (*Decrypter) BuildKeyDecrypter added in v1.0.6

func (d *Decrypter) BuildKeyDecrypter() (keyenc.Decrypter, error)

func (*Decrypter) ComputedAuthenticatedData added in v1.0.6

func (d *Decrypter) ComputedAuthenticatedData(aad []byte) *Decrypter

func (*Decrypter) ContentCipher added in v1.0.6

func (d *Decrypter) ContentCipher() (content_crypt.Cipher, error)

func (*Decrypter) ContentEncryptionAlgorithm added in v1.0.6

func (d *Decrypter) ContentEncryptionAlgorithm(ctalg jwa.ContentEncryptionAlgorithm) *Decrypter

func (*Decrypter) Decrypt added in v1.0.6

func (d *Decrypter) Decrypt(recipientKey, ciphertext []byte) (plaintext []byte, err error)

func (*Decrypter) DecryptKey added in v1.0.6

func (d *Decrypter) DecryptKey(recipientKey []byte) (cek []byte, err error)

func (*Decrypter) InitializationVector added in v1.0.6

func (d *Decrypter) InitializationVector(iv []byte) *Decrypter

func (*Decrypter) KeyCount added in v1.0.6

func (d *Decrypter) KeyCount(keycount int) *Decrypter

func (*Decrypter) KeyInitializationVector added in v1.0.6

func (d *Decrypter) KeyInitializationVector(keyiv []byte) *Decrypter

func (*Decrypter) KeySalt added in v1.0.6

func (d *Decrypter) KeySalt(keysalt []byte) *Decrypter

func (*Decrypter) KeyTag added in v1.0.6

func (d *Decrypter) KeyTag(keytag []byte) *Decrypter

func (*Decrypter) PublicKey added in v1.0.6

func (d *Decrypter) PublicKey(pubkey interface{}) *Decrypter

PublicKey sets the public key to be used in decoding EC based encryptions. The key must be in its "raw" format (i.e. *ecdsa.PublicKey, instead of jwk.Key)

func (*Decrypter) Tag added in v1.0.6

func (d *Decrypter) Tag(tag []byte) *Decrypter

type EncryptOption added in v1.1.2

type EncryptOption interface {
	Option
	// contains filtered or unexported methods
}

func WithProtectedHeaders added in v1.1.2

func WithProtectedHeaders(h Headers) EncryptOption

Specify contents of the protected header. Some fields such as "enc" and "zip" will be overwritten when encryption is performed.

type HeaderPair added in v1.0.0

type HeaderPair = mapiter.Pair

type Headers added in v1.0.0

type Headers interface {
	json.Marshaler
	json.Unmarshaler
	AgreementPartyUInfo() []byte
	AgreementPartyVInfo() []byte
	Algorithm() jwa.KeyEncryptionAlgorithm
	Compression() jwa.CompressionAlgorithm
	ContentEncryption() jwa.ContentEncryptionAlgorithm
	ContentType() string
	Critical() []string
	EphemeralPublicKey() jwk.Key
	JWK() jwk.Key
	JWKSetURL() string
	KeyID() string
	Type() string
	X509CertChain() []string
	X509CertThumbprint() string
	X509CertThumbprintS256() string
	X509URL() string
	Iterate(ctx context.Context) Iterator
	Walk(ctx context.Context, v Visitor) error
	AsMap(ctx context.Context) (map[string]interface{}, error)
	Get(string) (interface{}, bool)
	Set(string, interface{}) error
	Remove(string) error
	Encode() ([]byte, error)
	Decode([]byte) error
	// PrivateParams returns the map containing the non-standard ('private') parameters
	// in the associated header. WARNING: DO NOT USE PrivateParams()
	// IF YOU HAVE CONCURRENT CODE ACCESSING THEM. Use AsMap() to
	// get a copy of the entire header instead
	PrivateParams() map[string]interface{}
	Clone(context.Context) (Headers, error)
	Copy(context.Context, Headers) error
	Merge(context.Context, Headers) (Headers, error)
}

Headers describe a standard Header set.

func NewHeaders added in v1.0.0

func NewHeaders() Headers

type Iterator added in v1.0.0

type Iterator = mapiter.Iterator

type Message

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

Message contains the entire encrypted JWE message. You should not expect to use Message for anything other than inspecting the state of an encrypted message. This is because encryption is highly context sensitive, and once we parse the original payload into an object, we may not always be able to recreate the exact context in which the encryption happened.

For example, it is totally valid for if the protected header's integrity was calculated using a non-standard line breaks:

{"a dummy":
  "protected header"}

Once parsed, though, we can only serialize the protected header as:

{"a dummy":"protected header"}

which would obviously result in a contradicting integrity value if we tried to re-calculate it from a parsed message.

func NewMessage

func NewMessage() *Message

NewMessage creates a new message

func Parse

func Parse(buf []byte) (*Message, error)

Parse parses the JWE message into a Message object. The JWE message can be either compact or full JSON format.

func ParseReader added in v1.1.0

func ParseReader(src io.Reader) (*Message, error)

ParseReader is the same as Parse, but takes an io.Reader.

func ParseString

func ParseString(s string) (*Message, error)

ParseString is the same as Parse, but takes a string.

func ReadFile added in v1.1.0

func ReadFile(path string, _ ...ReadFileOption) (*Message, error)

func (*Message) AuthenticatedData

func (m *Message) AuthenticatedData() []byte

func (*Message) CipherText

func (m *Message) CipherText() []byte

func (*Message) Decrypt

func (m *Message) Decrypt(alg jwa.KeyEncryptionAlgorithm, key interface{}) ([]byte, error)

Decrypt decrypts the message using the specified algorithm and key.

`key` must be a private key in its "raw" format (i.e. something like *rsa.PrivateKey, instead of jwk.Key)

This method is marked for deprecation. It will be removed from the API in the next major release. You should not rely on this method to work 100% of the time, especially when it was obtained via jwe.Parse instead of being constructed from scratch by this library.

func (*Message) InitializationVector

func (m *Message) InitializationVector() []byte

func (*Message) MarshalJSON added in v1.0.0

func (m *Message) MarshalJSON() ([]byte, error)

func (*Message) ProtectedHeaders added in v1.0.0

func (m *Message) ProtectedHeaders() Headers

func (*Message) Recipients

func (m *Message) Recipients() []Recipient

func (*Message) Set added in v1.0.2

func (m *Message) Set(k string, v interface{}) error

func (*Message) Tag

func (m *Message) Tag() []byte

func (*Message) UnmarshalJSON added in v1.0.0

func (m *Message) UnmarshalJSON(buf []byte) error

func (*Message) UnprotectedHeaders added in v1.0.0

func (m *Message) UnprotectedHeaders() Headers

type Option added in v1.0.0

type Option = option.Interface

type PostParseFunc added in v1.2.2

type PostParseFunc func(DecryptCtx) error

PostParseFunc is a PostParser that is represented by a single function

func (PostParseFunc) PostParse added in v1.2.2

func (fn PostParseFunc) PostParse(ctx DecryptCtx) error

type PostParser added in v1.2.2

type PostParser interface {
	PostParse(DecryptCtx) error
}

PostParser is used in conjunction with jwe.WithPostParser(). This hook is called right after the JWE message has been parsed but before the actual decryption takes place during `jwe.Decrypt()`.

type ReadFileOption added in v1.1.0

type ReadFileOption interface {
	Option
	// contains filtered or unexported methods
}

ReadFileOption describes options that can be passed to ReadFile. Currently there are no options available that can be passed to ReadFile, but it is provided here for anticipated future additions

type Recipient

type Recipient interface {
	Headers() Headers
	EncryptedKey() []byte
	SetHeaders(Headers) error
	SetEncryptedKey([]byte) error
}

Recipient holds the encrypted key and hints to decrypt the key

func NewRecipient

func NewRecipient() Recipient

NewRecipient creates a Recipient object

type SerializerOption added in v1.1.0

type SerializerOption interface {
	Option
	// contains filtered or unexported methods
}

func WithPrettyFormat added in v1.1.0

func WithPrettyFormat(b bool) SerializerOption

WithPrettyFormat specifies if the `jwe.JSON` serialization tool should generate pretty-formatted output

type Visitor added in v1.0.0

type Visitor = iter.MapVisitor

type VisitorFunc added in v1.0.0

type VisitorFunc = iter.MapVisitorFunc

Directories

Path Synopsis
internal
cmd/genheader Module

Jump to

Keyboard shortcuts

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