| Commit message (Collapse) | Author | Age | Files | Lines |
... | |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Implements a protocol for delegated access to a shared secret key
of a token whose private key we do not possess. This builds directly
on top of the existing token resealing mechanisms.
The primary benefit of the resealing protocol is that none of the
data exchanged can reveal anything about the underlying secret.
Security note: neither resealing requests nor responses are explicitly
authenticated (this is a property inherited from the sealed shared
key tokens themselves). It is assumed that an attacker can observe
all requests and responses in transit, but cannot modify them.
|
| |
|
| |
|
| |
|
|
|
|
| |
versions" (#25436)
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This is to get around the limitation where AES GCM can only produce
a maximum of 64 GiB of ciphertext for a particular <key, IV> pair before
its security properties break down. ChaCha20-Poly1305 does not have any
practical limitations here.
ChaCha20-Poly1305 uses a 256-bit key whereas the shared key is 128 bits.
A HKDF is used to internally expand the key material to 256 bits.
To let token based decryption be fully backwards compatible, introduce
a token version 2. V1 tokens will be decrypted with AES-GCM 128, while
V2 tokens use ChaCha20-Poly1305.
As a bonus, cryptographic operations will generally be _faster_ after
this cipher change, as we use BouncyCastle ciphers and these do not use
any native AES instructions. ChaCha20-Poly1305 is usually considerably
faster when running without specialized hardware support. An ad-hoc
experiment with a large ciphertext showed a near 70% performance increase
over AES-GCM 128.
|
|
|
|
| |
No functional changes, just bugged me to have used the wrong order.
|
|
|
|
| |
Wrong base was "close enough" that test seemingly worked most of the time...!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This resolves two issues:
* `javax.crypto.OutputCipherStream` swallows MAC tag mismatch exceptions
when the stream is closed, which means that corruptions (intentional
or not) are not caught. This is documented behavior, but still very
surprising and a rather questionable default. BC's interchangeable
`CipherOutputStream` throws as expected. To avoid regressions, add an
explicit test that both ciphertext and MAC tag corruptions are propagated.
* The default-provided `AES/GCM/NoPadding` `Cipher` instance will not emit
decrypted plaintext per `update()` chunk, but buffer everything until
`doFinal()` is invoked when the stream is closed. This means that decrypting
very large ciphertexts can blow up memory usage since internal output
buffers are reallocated and increased per iteration...! Instead use an
explicit BC `GCMBlockCipher` which has the expected behavior (and actually
lets cipher streams, well, _stream_). Add an `AeadCipher` abstraction to
avoid leaking BC APIs outside the security module.
|
|
|
|
|
|
|
|
|
| |
Adds underlying support--and tooling--for resealing a token for
another recipient. This allows for delegating decryption to another
party without having to reveal the private key of the original
recipient (or having to send the raw underlying secret key over a
potentially insecure channel). Key ID can/should change as part of
this operation.
|
|
|
|
|
|
|
|
| |
* Base62 minimizes extra size overhead relative to Base64.
* Base58 removes ambiguous characters from key encodings.
Common for both bases is that they do not emit any characters that
interfer with easily selecting them on web pages or in the CLI.
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Adds a codec that enables easy conversion from an array of bytes to any
numeric base in [2, 256) and back again, using a supplied custom alphabet.
Implemented by treating the input byte sequence to encode verbatim as a
big-endian `BigInteger` and iteratively doing a `divmod` operation until
the quotient is zero, emitting the modulus mapped onto the alphabet for
each iteration.
Decoding reverses this process, ending up with the same `BigInteger` as
in the initial encoding step.
|
| |
|
|
|
|
| |
Enforces invariants and avoids having to pass raw byte arrays around.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
This makes key IDs vastly more expressive. Max size is 255 bytes,
and UTF-8 form is enforced by checking that the byte sequence can be
identity-transformed to and from a string with UTF-8 encoding.
In addition, we now protect the integrity of the key ID by supplying
it as the AAD parameter to the key sealing and opening operations.
Reduce v1 token max length of `enc` part to 255, since this is always
an X25519 public key, which is never bigger than 32 bytes (but may
be _less_ if the random `BigInteger` is small enough, so we still have
to encode the length).
|
|
|
|
|
|
|
| |
Adds support for:
* X25519 key pair generation
* HPKE stream encryption with public key and token generation
* HPKE stream decryption with private key
|
| |
|
|
|
|
|
| |
Also use AES-128 instead of AES-256 for the one-time key since the underlying
HPKE AEAD cipher protecting the key itself is AES-128.
|
|
|
|
|
|
|
| |
Avoids the need to pass the full key pair when opening a sealed piece
of ciphertext, since we can just extract the public key on-demand.
Uses BouncyCastle X25519 utils under the hood.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
HPKE is a hybrid encryption scheme that builds around three primitives:
* A key encapsulation mechanism (KEM)
* A key derivation function (KDF)
* An "authenticated encryption with associated data" (AEAD) algorithm
The 3-tuple (KEM, KDF, AEAD) is known as the HPKE _ciphersuite_.
This implementation has certain (intentional) limitations:
* Only the `DHKEM(X25519, HKDF-SHA256), HKDF-SHA256, AES-128-GCM`
ciphersuite is implemented. This is expected to be a good default
choice for any internal use of this class.
* Only the "base mode" (unauthenticated sender) is supported, i.e.
no PSK support and no secret exporting. This implementation is
only expected to be used for anonymous one-way encryption.
* The API only offers single-shot encryption to keep anyone from
being tempted to use it to build their own multi-message protocol
on top. This entirely avoids the risk of nonce reuse caused by
accidentally repeating sequence numbers.
**Deprecation notice:** once BouncyCastle (or the Java crypto API)
supports HPKE, this particular implementation can safely be deprecated
and sent off to live on a farm.
|
|
|
|
|
| |
Lets arrays be compared without leaking information about their
contents caused by early exits etc.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The HKDF is initialized ("extracted") from a (non-secret) salt and a secret key.
From this, any number of secret keys can be derived ("expanded") deterministically.
When multiple keys are to be derived from the same initial keying/salting material,
each separate key should use a distinct "context". This ensures that there exists
a domain separation between the keys. Using the same context as another key on a
HKDF initialized with the same salt+key results in the exact same derived key
material as that key.
This implementation only offers HMAC-SHA256-based key derivation.
Tested with all HMAC-SHA256 test vectors in RFC-5869, with added edge case tests.
Analogous to BouncyCastle's `HKDFBytesGenerator`, but with a simpler API that
tries to be very explicit in its operation, as well as fully thread safe due to
not storing intermediate calculations in member fields.
|
|
|
|
|
|
|
| |
For some reason requires passing in and keeping an explicit IV. Not sure
why this is the case, since symmetric keys used in the context of a hybrid
crypto scheme are generally derived via a KDF from the shared secret.
This stuff is practically entirely undocumented... :I
|
|\
| |
| | |
Upgrade BouncyCastle to 1.72 [run-systemtest]
|
| |
| |
| |
| | |
Migrate to artifact names used by 1.71+
|
| |
| |
| |
| |
| | |
* Make `SecureRandom` a shared static field
* Just take in `PrivateKey` instead of `KeyPair` for key unsealing
|
|/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Lets a sender generate a random, single-use symmetric key and securely
share this with a receiver, with the sender only knowing the public
key of the receiver. The shared key is exchanged via an opaque token
that can only be decoded by having the private key corresponding to
the public key used for encoding it.
This is implemented using ECIES, a hybrid encryption scheme using
Elliptic Curve Diffie-Hellman (ECDH) for ephemeral key exchange combined
with a symmetric cipher using the ephemeral key for actual plaintext
encryption/decryption.
In addition to the key exchange itself, utilities for creating
encryption and decryption ciphers for AES-GCM-256 from the shared keys
are included.
**Security note**: since the key is intended to be used for producing a
single piece of ciphertext, a fixed Initialization Vector (IV) is used.
The key MUST NOT be used to produce more than one ciphertext, lest the
entire security model breaks down entirely.
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|
|
|
|
|
| |
Bound key-value pairs from SSL handshake session are now copied to the final SSL session object.
This simplifies the dataflow - not need to retrieve the instance right after our custom trust manager is invoked.
|
| |
|
|
|
|
|
| |
Add peerSpec to Target/Connection. Always provide ConnectionAuthContext.
Add helper for creating default, all-granting ConnectionAuthContext.
|
| |
|
| |
|
| |
|
| |
|
|
|
|
| |
Facilitate improved encapsulation of Vespa mTLS related classes
|
| |
|
| |
|
| |
|
| |
|
| |
|
| |
|