Documentation ¶
Overview ¶
Package jwe implements JWE as described in https://tools.ietf.org/html/rfc7516
Index ¶
- Constants
- func Compact(m *Message, _ ...CompactOption) ([]byte, error)
- func Decrypt(buf []byte, options ...DecryptOption) ([]byte, error)
- func DecryptError() error
- func Encrypt(payload []byte, options ...EncryptOption) ([]byte, error)
- func EncryptError() error
- func EncryptStatic(payload, cek []byte, options ...EncryptOption) ([]byte, error)
- func ParseError() error
- func RecipientError() error
- func RegisterCustomField(name string, object interface{})
- func Settings(options ...GlobalOption)
- type CompactOption
- type CustomDecodeFunc
- type CustomDecoder
- type DecryptOption
- func WithCEK(v *[]byte) DecryptOption
- func WithContext(v context.Context) DecryptOption
- func WithKeyProvider(v KeyProvider) DecryptOption
- func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) DecryptOption
- func WithKeyUsed(v interface{}) DecryptOption
- func WithMessage(v *Message) DecryptOption
- type EncryptDecryptOption
- type EncryptOption
- func WithCompact() EncryptOption
- func WithCompress(v jwa.CompressionAlgorithm) EncryptOption
- func WithContentEncryption(v jwa.ContentEncryptionAlgorithm) EncryptOption
- func WithJSON(options ...WithJSONSuboption) EncryptOption
- func WithMergeProtectedHeaders(v bool) EncryptOption
- func WithProtectedHeaders(h Headers) EncryptOption
- type GlobalDecryptOption
- type GlobalOption
- type Headers
- type KeyDecrypter
- type KeyEncrypter
- type KeyIDer
- type KeyProvider
- type KeyProviderFunc
- type KeySink
- type Message
- func (m *Message) AuthenticatedData() []byte
- func (m *Message) CipherText() []byte
- func (m *Message) InitializationVector() []byte
- func (m *Message) MarshalJSON() ([]byte, error)
- func (m *Message) ProtectedHeaders() Headers
- func (m *Message) Recipients() []Recipient
- func (m *Message) Set(k string, v interface{}) error
- func (m *Message) Tag() []byte
- func (m *Message) UnmarshalJSON(buf []byte) error
- func (m *Message) UnprotectedHeaders() Headers
- type Option
- type ParseOption
- type ReadFileOption
- type Recipient
- type WithJSONSuboption
- type WithKeySetSuboption
- type WithKeySuboption
Constants ¶
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" )
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 ¶
func Compact(m *Message, _ ...CompactOption) ([]byte, error)
Compact generates a JWE message in compact serialization format from a `*jwe.Message` object. The object contain exactly one recipient, or an error is returned.
This function currently does not take any options, but the function signature contains `options` for possible future expansion of the API
func Decrypt ¶
func Decrypt(buf []byte, options ...DecryptOption) ([]byte, error)
Decrypt takes encrypted payload, and information required to decrypt the payload (e.g. the key encryption algorithm and the corresponding key to decrypt the JWE message) in its optional arguments. See the examples and list of options that return a DecryptOption for possible values. Upon successful decryptiond returns the decrypted payload.
The JWE message can be either compact or full JSON format.
When using `jwe.WithKeyEncryptionAlgorithm()`, you can pass a `jwa.KeyAlgorithm` for convenience: this is mainly to allow you to directly pass the result of `(jwk.Key).Algorithm()`. However, do note that while `(jwk.Key).Algorithm()` could very well contain key encryption algorithms, it could also contain other types of values, such as _signature algorithms_. In order for `jwe.Decrypt` to work properly, the `alg` parameter must be of type `jwa.KeyEncryptionAlgorithm` or otherwise it will cause an error.
When using `jwe.WithKey()`, the value must be a private key. It can be either in its raw format (e.g. *rsa.PrivateKey) or a jwk.Key
When the encrypted message is also compressed, the decompressed payload must be smaller than the size specified by the `jwe.WithMaxDecompressBufferSize` setting, which defaults to 10MB. If the decompressed payload is larger than this size, an error is returned.
You can opt to change the MaxDecompressBufferSize setting globally, or on a per-call basis by passing the `jwe.WithMaxDecompressBufferSize` option to either `jwe.Settings()` or `jwe.Decrypt()`:
jwe.Settings(jwe.WithMaxDecompressBufferSize(10*1024*1024)) // changes value globally jwe.Decrypt(..., jwe.WithMaxDecompressBufferSize(250*1024)) // changes just for this call
func DecryptError ¶
func DecryptError() error
DecryptError returns an error that can be passed to `errors.Is` to check if the error is an error returned by `jwe.Decrypt`.
func Encrypt ¶
func Encrypt(payload []byte, options ...EncryptOption) ([]byte, error)
Encrypt generates a JWE message for the given payload and returns it in serialized form, which can be in either compact or JSON format. Default is compact.
You must pass at least one key to `jwe.Encrypt()` by using `jwe.WithKey()` option.
jwe.Encrypt(payload, jwe.WithKey(alg, key)) jwe.Encrypt(payload, jws.WithJSON(), jws.WithKey(alg1, key1), jws.WithKey(alg2, key2))
Note that in the second example the `jws.WithJSON()` option is specified as well. This is because the compact serialization format does not support multiple recipients, and users must specifically ask for the JSON serialization format.
Read the documentation for `jwe.WithKey()` to learn more about the possible values that can be used for `alg` and `key`.
Look for options that return `jwe.EncryptOption` or `jws.EncryptDecryptOption` for a complete list of options that can be passed to this function.
func EncryptError ¶
func EncryptError() error
EncryptError returns an error that can be passed to `errors.Is` to check if the error is an error returned by `jwe.Encrypt`.
func EncryptStatic ¶
func EncryptStatic(payload, cek []byte, options ...EncryptOption) ([]byte, error)
EncryptStatic is exactly like Encrypt, except it accepts a static content encryption key (CEK). It is separated out from the main Encrypt function such that the latter does not accidentally use a static CEK.
DO NOT attempt to use this function unless you completely understand the security implications to using static CEKs. You have been warned.
This function is currently considered EXPERIMENTAL, and is subject to future changes across minor/micro versions.
func ParseError ¶
func ParseError() error
ParseError returns an error that can be passed to `errors.Is` to check if the error is an error returned by `jwe.Parse` and related functions.
func RecipientError ¶
func RecipientError() error
RecipientError returns an error that can be passed to `errors.Is` to check if the error is an error that occurred while attempting to decrypt a JWE message for a particular recipient.
For example, if the JWE message failed to parse during `jwe.Decrypt`, it will be a `jwe.DecryptError`, but NOT `jwe.RecipientError`. However, if the JWE message could not be decrypted for any of the recipients, then it will be a `jwe.RecipientError` (actually, it will be _multiple_ `jwe.RecipientError` errors, one for each recipient)
func RegisterCustomField ¶
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 such case you would register a custom field as follows
jws.RegisterCustomField(`x-birthday`, time.Time{})
Then you can use a `time.Time` variable to extract the value of `x-birthday` field, instead of having to use `interface{}` and later convert it to `time.Time`
var bday time.Time _ = hdr.Get(`x-birthday`, &bday)
If you need a more fine-tuned control over the decoding process, you can register a `CustomDecoder`. For example, below shows how to register a decoder that can parse RFC1123 format string:
jwe.RegisterCustomField(`x-birthday`, jwe.CustomDecodeFunc(func(data []byte) (interface{}, error) { return time.Parse(time.RFC1123, string(data)) }))
Please note that use of custom fields can be problematic if you are using a library that does not implement MarshalJSON/UnmarshalJSON and you try to roundtrip from an object to JSON, and then back to an object. For example, in the above example, you can _parse_ time values formatted in the format specified in RFC822, but when you convert an object into JSON, it will be formatted in RFC3339, because that's what `time.Time` likes to do. To avoid this, it's always better to use a custom type that wraps your desired type (in this case `time.Time`) and implement MarshalJSON and UnmashalJSON.
func Settings ¶
func Settings(options ...GlobalOption)
Types ¶
type CompactOption ¶
type CompactOption interface { Option // contains filtered or unexported methods }
CompactOption describes options that can be passed to `jwe.Compact`
type CustomDecodeFunc ¶
type CustomDecodeFunc = json.CustomDecodeFunc
type CustomDecoder ¶
type CustomDecoder = json.CustomDecoder
type DecryptOption ¶
type DecryptOption interface { Option // contains filtered or unexported methods }
DecryptOption describes options that can be passed to `jwe.Decrypt`
func WithCEK ¶
func WithCEK(v *[]byte) DecryptOption
WithCEK allows users to specify a variable to store the CEK used in the message upon successful decryption. The variable must be a pointer to a byte slice, and it will only be populated if the decryption is successful.
This option is currently considered EXPERIMENTAL, and is subject to future changes across minor/micro versions.
func WithContext ¶
func WithContext(v context.Context) DecryptOption
WithContext specifies the context.Context object to use when decrypting a JWE message. If not provided, context.Background() will be used.
func WithKeyProvider ¶
func WithKeyProvider(v KeyProvider) DecryptOption
func WithKeySet ¶
func WithKeySet(set jwk.Set, options ...WithKeySetSuboption) DecryptOption
func WithKeyUsed ¶
func WithKeyUsed(v interface{}) DecryptOption
WithKeyUsed allows you to specify the `jwe.Decrypt()` function to return the key used for decryption. This may be useful when you specify multiple key sources or if you pass a `jwk.Set` and you want to know which key was successful at decrypting the CEK.
`v` must be a pointer to an empty `interface{}`. Do not use `jwk.Key` here unless you are 100% sure that all keys that you have provided are instances of `jwk.Key` (remember that the jwx API allows users to specify a raw key such as *rsa.PublicKey)
func WithMessage ¶
func WithMessage(v *Message) DecryptOption
WithMessage provides a message object to be populated by `jwe.Decrypt` Using this option allows you to decrypt AND obtain the `jwe.Message` in one go.
type EncryptDecryptOption ¶
type EncryptDecryptOption interface { Option // contains filtered or unexported methods }
EncryptDecryptOption describes options that can be passed to either `jwe.Encrypt` or `jwe.Decrypt`
func WithKey ¶
func WithKey(alg jwa.KeyAlgorithm, key interface{}, options ...WithKeySuboption) EncryptDecryptOption
WithKey is used to pass a static algorithm/key pair to either `jwe.Encrypt()` or `jwe.Decrypt()`. either a raw key or `jwk.Key` may be passed as `key`.
The `alg` parameter is the identifier for the key encryption algorithm that should be used. It is of type `jwa.KeyAlgorithm` but in reality you can only pass `jwa.KeyEncryptionAlgorithm` types. It is this way so that the value in `(jwk.Key).Algorithm()` can be directly passed to the option. If you specify other algorithm types such as `jwa.SignatureAlgorithm`, then you will get an error when `jwe.Encrypt()` or `jwe.Decrypt()` is executed.
Unlike `jwe.WithKeySet()`, the `kid` field does not need to match for the key to be tried.
type EncryptOption ¶
type EncryptOption interface { Option // contains filtered or unexported methods }
EncryptOption describes options that can be passed to `jwe.Encrypt`
func WithCompact ¶
func WithCompact() EncryptOption
WithCompact specifies that the result of `jwe.Encrypt()` is serialized in compact format.
By default `jwe.Encrypt()` will opt to use compact format, so you usually do not need to specify this option other than to be explicit about it
func WithCompress ¶
func WithCompress(v jwa.CompressionAlgorithm) EncryptOption
WithCompress specifies the compression algorithm to use when encrypting a payload using `jwe.Encrypt` (Yes, we know it can only be "" or "DEF", but the way the specification is written it could allow for more options, and therefore this option takes an argument)
func WithContentEncryption ¶
func WithContentEncryption(v jwa.ContentEncryptionAlgorithm) EncryptOption
WithContentEncryptionAlgorithm specifies the algorithm to encrypt the JWE message content with. If not provided, `jwa.A256GCM` is used.
func WithJSON ¶
func WithJSON(options ...WithJSONSuboption) EncryptOption
WithJSON specifies that the result of `jwe.Encrypt()` is serialized in JSON format.
If you pass multiple keys to `jwe.Encrypt()`, it will fail unless you also pass this option.
func WithMergeProtectedHeaders ¶
func WithMergeProtectedHeaders(v bool) EncryptOption
WithMergeProtectedHeaders specify that when given multiple headers as options to `jwe.Encrypt`, these headers should be merged instead of overwritten
func WithProtectedHeaders ¶
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.
There is no equivalent for unprotected headers in this implementation
type GlobalDecryptOption ¶
type GlobalDecryptOption interface { Option // contains filtered or unexported methods }
GlobalDecryptOption describes options that changes global settings and for each call of the `jwe.Decrypt` function
func WithMaxDecompressBufferSize ¶
func WithMaxDecompressBufferSize(v int64) GlobalDecryptOption
WithMaxDecompressBufferSize specifies the maximum buffer size for used when decompressing the payload of a JWE message. If a compressed JWE payload exceeds this amount when decompressed, jwe.Decrypt will return an error. The default value is 10MB.
This option can be used for `jwe.Settings()`, which changes the behavior globally, or for `jwe.Decrypt()`, which changes the behavior for that specific call.
type GlobalOption ¶
type GlobalOption interface { Option // contains filtered or unexported methods }
GlobalOption describes options that changes global settings for this package
func WithCBCBufferSize ¶
func WithCBCBufferSize(v int64) GlobalOption
WithCBCBufferSize specifies the maximum buffer size for internal calculations, such as when AES-CBC is performed. The default value is 256MB. If set to an invalid value, the default value is used. In v2, this option was called MaxBufferSize.
This option has a global effect.
func WithMaxPBES2Count ¶
func WithMaxPBES2Count(v int) GlobalOption
WithMaxPBES2Count specifies the maximum number of PBES2 iterations to use when decrypting a message. If not specified, the default value of 10,000 is used.
This option has a global effect.
type Headers ¶
type Headers interface { AgreementPartyUInfo() ([]byte, bool) AgreementPartyVInfo() ([]byte, bool) Algorithm() (jwa.KeyEncryptionAlgorithm, bool) Compression() (jwa.CompressionAlgorithm, bool) ContentEncryption() (jwa.ContentEncryptionAlgorithm, bool) ContentType() (string, bool) Critical() ([]string, bool) EphemeralPublicKey() (jwk.Key, bool) JWK() (jwk.Key, bool) JWKSetURL() (string, bool) KeyID() (string, bool) Type() (string, bool) X509CertChain() (*cert.Chain, bool) X509CertThumbprint() (string, bool) X509CertThumbprintS256() (string, bool) X509URL() (string, bool) // Get is used to extract the value of any field, including non-standard fields, out of the header. // // The first argument is the name of the field. The second argument is a pointer // to a variable that will receive the value of the field. The method returns // an error if the field does not exist, or if the value cannot be assigned to // the destination variable. Note that a field is considered to "exist" even if // the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set. Get(string, interface{}) error Set(string, interface{}) error Remove(string) error // Has returns true if the specified header has a value, even if // the value is empty-ish (e.g. 0, false, "") as long as it has been // explicitly set. Has(string) bool Encode() ([]byte, error) Decode([]byte) error Clone() (Headers, error) Copy(Headers) error Merge(Headers) (Headers, error) // Keys returns a list of the keys contained in this header. Keys() []string }
Headers describe a standard JWE Header set. It is part of the JWE message and is used to represent both Protected and Unprotected headers, which in turn can be found in each Recipient object. If you are not sure how this works, it is strongly recommended that you read RFC7516, especially the section that describes the full JSON serialization format of JWE messages.
In most cases, you likely want to use the protected headers, as this is the part of the encrypted content
func NewHeaders ¶
func NewHeaders() Headers
type KeyDecrypter ¶
type KeyDecrypter interface { // Decrypt decrypts the encrypted key of a JWE message. // // Make sure you understand how JWE messages are structured. // // For example, while in most circumstances a JWE message will only have one recipient, // a JWE message may contain multiple recipients, each with their own // encrypted key. This method will be called for each recipient, instead of // just once for a message. // // Also, header values could be found in either protected/unprotected headers // of a JWE message, as well as in protected/unprotected headers for each recipient. // When checking a header value, you can decide to use either one, or both, but you // must be aware that there are multiple places to look for. DecryptKey(alg jwa.KeyEncryptionAlgorithm, encryptedKey []byte, recipient Recipient, message *Message) ([]byte, error) }
KeyDecrypter is an interface for objects that can decrypt a content encryption key.
You can use this in place of a regular key (i.e. in jwe.WithKey()) to decrypt the encrypted key in a JWE message without having to expose the secret key in memory, for example, when you want to use hardware security modules (HSMs) to decrypt the key.
This API is experimental and may change without notice, even in minor releases.
type KeyEncrypter ¶
type KeyEncrypter interface { // Algorithm returns the algorithm used to encrypt the key. Algorithm() jwa.KeyEncryptionAlgorithm // EncryptKey encrypts the given content encryption key. EncryptKey([]byte) ([]byte, error) }
KeyEncrypter is an interface for object that can encrypt a content encryption key.
You can use this in place of a regular key (i.e. in jwe.WithKey()) to encrypt the content encryption key in a JWE message without having to expose the secret key in memory, for example, when you want to use hardware security modules (HSMs) to encrypt the key.
This API is experimental and may change without notice, even in minor releases.
type KeyIDer ¶
KeyIDer is an interface for things that can return a key ID.
As of this writing, this is solely used to identify KeyEncrypter objects that also carry a key ID on its own.
type KeyProvider ¶
KeyProvider is responsible for providing key(s) to encrypt or decrypt a payload. Multiple `jwe.KeyProvider`s can be passed to `jwe.Encrypt()` or `jwe.Decrypt()`
`jwe.Encrypt()` can only accept static key providers via `jwe.WithKey()`, while `jwe.Decrypt()` can accept `jwe.WithKey()`, `jwe.WithKeySet()`, and `jwe.WithKeyProvider()`.
Understanding how this works is crucial to learn how this package works. Here we will use `jwe.Decrypt()` as an example to show how the `KeyProvider` works.
`jwe.Encrypt()` is straightforward: the content encryption key is encrypted using the provided keys, and JWS recipient objects are created for each.
`jwe.Decrypt()` is a bit more involved, because there are cases you will want to compute/deduce/guess the keys that you would like to use for decryption.
The first thing that `jwe.Decrypt()` needs to do is to collect the KeyProviders from the option list that the user provided (presented in pseudocode):
keyProviders := filterKeyProviders(options)
Then, remember that a JWE message may contain multiple recipients in the message. For each recipient, we call on the KeyProviders to give us the key(s) to use on this CEK:
for r in msg.Recipients { for kp in keyProviders { kp.FetchKeys(ctx, sink, r, msg) ... } }
The `sink` argument passed to the KeyProvider is a temporary storage for the keys (either a jwk.Key or a "raw" key). The `KeyProvider` is responsible for sending keys into the `sink`.
When called, the `KeyProvider` created by `jwe.WithKey()` sends the same key, `jwe.WithKeySet()` sends keys that matches a particular `kid` and `alg`, and finally `jwe.WithKeyProvider()` allows you to execute arbitrary logic to provide keys. If you are providing a custom `KeyProvider`, you should execute the necessary checks or retrieval of keys, and then send the key(s) to the sink:
sink.Key(alg, key)
These keys are then retrieved and tried for each recipient, until a match is found:
keys := sink.Keys() for key in keys { if decryptJWEKey(recipient.EncryptedKey(), key) { return OK } }
type KeyProviderFunc ¶
KeyProviderFunc is a type of KeyProvider that is implemented by a single function. You can use this to create ad-hoc `KeyProvider` instances.
type KeySink ¶
type KeySink interface {
Key(jwa.KeyEncryptionAlgorithm, interface{})
}
KeySink is a data storage where `jwe.KeyProvider` objects should send their keys to.
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 Parse ¶
func Parse(buf []byte, _ ...ParseOption) (*Message, error)
Parse parses the JWE message into a Message object. The JWE message can be either compact or full JSON format.
Parse() currently does not take any options, but the API accepts it in anticipation of future addition.
func ParseReader ¶
ParseReader is the same as Parse, but takes an io.Reader.
func ParseString ¶
ParseString is the same as Parse, but takes a string.
func (*Message) AuthenticatedData ¶
func (*Message) CipherText ¶
func (*Message) InitializationVector ¶
func (*Message) MarshalJSON ¶
func (*Message) ProtectedHeaders ¶
func (*Message) Recipients ¶
func (*Message) UnmarshalJSON ¶
func (*Message) UnprotectedHeaders ¶
type ParseOption ¶
type ParseOption interface { Option // contains filtered or unexported methods }
ReadFileOption is a type of `Option` that can be passed to `jwe.Parse`
type ReadFileOption ¶
type ReadFileOption interface { Option // contains filtered or unexported methods }
ReadFileOption is a type of `Option` that can be passed to `jwe.ReadFile`
func WithFS ¶
func WithFS(v fs.FS) ReadFileOption
WithFS specifies the source `fs.FS` object to read the file from.
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
type WithJSONSuboption ¶
type WithJSONSuboption interface { Option // contains filtered or unexported methods }
JSONSuboption describes suboptions that can be passed to `jwe.WithJSON()` option
func WithPretty ¶
func WithPretty(v bool) WithJSONSuboption
WithPretty specifies whether the JSON output should be formatted and indented
type WithKeySetSuboption ¶
type WithKeySetSuboption interface { Option // contains filtered or unexported methods }
WithKeySetSuboption is a suboption passed to the WithKeySet() option
func WithRequireKid ¶
func WithRequireKid(v bool) WithKeySetSuboption
WithRequiredKid specifies whether the keys in the jwk.Set should only be matched if the target JWE message's Key ID and the Key ID in the given key matches.
type WithKeySuboption ¶
type WithKeySuboption interface { Option // contains filtered or unexported methods }
func WithPerRecipientHeaders ¶
func WithPerRecipientHeaders(hdr Headers) WithKeySuboption
WithPerRecipientHeaders is used to pass header values for each recipient. Note that these headers are by definition _unprotected_.