When runtime safety is turned on, `Ed25519.fromSecretKey()` can
currently hit an assertion if the format of the secret key is
invalid.
Return an error instead, so that applications can recover.
readAtLeast is greedy and will read the entire length of the buffer if it can. However, reading past the end of the cert in this case is useless, so reading the full length of the buffer just puts an increasingly large (due to the growth algorithm of ArrayList) collection of wasted bytes after each cert in cb.bytes.
In practical terms, this ends up saving potentially millions of bytes of wasted reads/allocations. In my testing, after reading the keychain files on my machine, cb.bytes ends up with these capacities:
- Before: cb.bytes.capacity = 32720747
- After: cb.bytes.capacity = 251937
That's a decrease of 99.2%
Additionally, swaps to readNoEof since it should be an error to hit EOF without reading the full cert size.
* std.crypto: add the ability to explicitly tag a value as secret
It turns out that Valgrind can be a very useful tool to check that secrets
are not leaked via side channels involving lookups or conditional jumps.
Valgrind tracks uninitialized data, and memcheck reports operations
involving uninitialized values. By permanently or temporarily telling
Valgrind that a memory region containing secrets is uninitialized, we can
detect common side-channel vulnerabilities.
For example, the following code snippets would immediately report that the
result is not computed in constant time:
```zig
classify(&key);
const len = std.mem.indexOfScalar(u8, &key, 0);
```
```zig
classify(&key);
const idx = key[0];
x += idx;
```
```zig
var x: [4]u8 = undefined;
std.crypto.random.bytes(&x);
classify(&x);
if (std.mem.eql(u8, "test", &x)) return;
```
This is not fool-proof, but it can help a lot to detect unwanted compiler
optimizations.
Also, right now, this is relying on Valgrind primitives, but these
annotations can be used to do more interesting things later, especially with
our own code generation backends.
* Update for Zig 0.14
* Remove checks for Valgrind enablement
* bcrypt: make silently_truncate_password a member of Params
This removes the need for having both `bcrypt()` and
`bcryptWithTruncation()` in the public API.
And whether truncation happens or not becomes even more explicit.
* Update crypto benchmark
In the original PR that implemented this (https://github.com/ziglang/zig/pull/14325), it included a list of references for the keychain format. Multiple of those references include the checks that are added in this commit, and empirically this fixes the loading of a real keychain file that was previously failing (it had both a record with offset 0 and a record with cert_size 0).
Fixes#22870
In the MAC finalization function, concatenated tags at odd positions
were not absorbed into the correct lane.
Spotted by a Tigerbeetle regression test and reported by Rafael Batiati
(@batiati) — Thanks!
* fix merge conflicts
* rename the declarations
* reword documentation
* extract FixedBufferAllocator to separate file
* take advantage of locals
* remove the assertion about max alignment in Allocator API, leaving it
Allocator implementation defined
* fix non-inline function call in start logic
The GeneralPurposeAllocator implementation is totally broken because it
uses global state but I didn't address that in this commit.
heap.zig: define new default page sizes
heap.zig: add min/max_page_size and their options
lib/std/c: add miscellaneous declarations
heap.zig: add pageSize() and its options
switch to new page sizes, especially in GPA/stdlib
mem.zig: remove page_size
The spec is ambiguous, and it's too late to change it.
So the most reasonable thing to do in order to avoid generating
strings that could be parsed differently by other implementations
is to forbid parameters named "v" at compile-time.
See https://github.com/P-H-C/phc-string-format/issues/8
This was done by regex substitution with `sed`. I then manually went
over the entire diff and fixed any incorrect changes.
This diff also changes a lot of `callconv(.C)` to `callconv(.c)`, since
my regex happened to also trigger here. I opted to leave these changes
in, since they *are* a correct migration, even if they're not the one I
was trying to do!
They way OpenSSH does key derivation to protect keys using a password
is not the standard PBKDF2, but something funky, picking key material
non-linearly.
* std.crypto.aes: introduce AES block vectors
Modern Intel CPUs with the VAES extension can handle more than a
single AES block per instruction.
So can some ARM and RISC-V CPUs. Software implementations with
bitslicing can also greatly benefit from this.
Implement low-level operations on AES block vectors, and the
parallel AEGIS variants on top of them.
AMD Zen4:
aegis-128x4: 73225 MiB/s
aegis-128x2: 51571 MiB/s
aegis-128l: 25806 MiB/s
aegis-256x4: 46742 MiB/s
aegis-256x2: 30227 MiB/s
aegis-256: 8436 MiB/s
aes128-gcm: 5926 MiB/s
aes256-gcm: 5085 MiB/s
AES-GCM, and anything based on AES-CTR are also going to benefit
from this later.
* Make AEGIS-MAC twice a fast
* crypto.keccak.State: don't unconditionally permute after a squeeze()
Now, squeeze() behaves like absorb()
Namely,
squeeze(x[0..t]);
squeeze(x[t..n)); with t <= n
becomes equivalent to squeeze(x[0..n]).
* keccak: in debug mode, track transitions to prevent insecure ones.
Fixes#22019
Our key pair creation API was ugly and inconsistent between ecdsa
keys and other keys.
The same `generate()` function can now be used to generate key pairs,
and that function cannot fail.
For deterministic keys, a `generateDeterministic()` function is
available for all key types.
Fix comments and compilation of the benchmark by the way.
Fixes#21002
By default, programs built in debug mode that open a https connection
will append secrets to the file specified in the SSLKEYLOGFILE
environment variable to allow protocol debugging by external programs.
This was preventing TLSv1.2 from working in some cases, because servers
are allowed to send multiple handshake messages in the first handshake
record, whereas this inital loop was assuming that it only contained a
server hello.
This is mostly nfc cleanup as I was bisecting the client hello to find
the problematic part, and the only bug fix ended up being
key_share.x25519_kp.public_key ++
key_share.ml_kem768_kp.public_key.toBytes()
to
key_share.ml_kem768_kp.public_key.toBytes() ++
key_share.x25519_kp.public_key)
and the same swap in `KeyShare.exchange` as per some random blog that
says "a hybrid keyshare, constructed by concatenating the public KEM key
with the public X25519 key". I also note that based on the same blog
post, there was a draft version of this method that indeed had these
values swapped, and that used to be supported by this code, but it was
not properly fixed up when this code was updated from the draft spec.
Closes#21747
Note that the removed `error.TlsIllegalParameter` case is still caught
below when it is compared to a fixed-length string, but after checking
the proper protocol version requirement first.
This commit reworks how anonymous struct literals and tuples work.
Previously, an untyped anonymous struct literal
(e.g. `const x = .{ .a = 123 }`) was given an "anonymous struct type",
which is a special kind of struct which coerces using structural
equivalence. This mechanism was a holdover from before we used
RLS / result types as the primary mechanism of type inference. This
commit changes the language so that the type assigned here is a "normal"
struct type. It uses a form of equivalence based on the AST node and the
type's structure, much like a reified (`@Type`) type.
Additionally, tuples have been simplified. The distinction between
"simple" and "complex" tuple types is eliminated. All tuples, even those
explicitly declared using `struct { ... }` syntax, use structural
equivalence, and do not undergo staged type resolution. Tuples are very
restricted: they cannot have non-`auto` layouts, cannot have aligned
fields, and cannot have default values with the exception of `comptime`
fields. Tuples currently do not have optimized layout, but this can be
changed in the future.
This change simplifies the language, and fixes some problematic
coercions through pointers which led to unintuitive behavior.
Resolves: #16865
The old `CallingConvention` type is replaced with the new
`NewCallingConvention`. References to `NewCallingConvention` in the
compiler are updated accordingly. In addition, a few parts of the
standard library are updated to use the new type correctly.
Most of these changes seem like improvements. The PDB thing had a TODO
saying it used to crash; I anticipate it works now, we'll see what CI
does.
The `std.os.uefi` field renames are a notable breaking change.
The compiler actually doesn't need any functional changes for this: Sema
does reification based on the tag indices of `std.builtin.Type` already!
So, no zig1.wasm update is necessary.
This change is necessary to disallow name clashes between fields and
decls on a type, which is a prerequisite of #9938.
In a `memoized_call`, store how many backwards braches the call
performs. Add this to `sema.branch_count` when using a memoized call. If
this exceeds the quota, perform a non-memoized call to get a correct
"exceeded X backwards branches" error.
Also, do not memoize calls which do `@setEvalBranchQuota` or similar, as
this affects global state which must apply to the caller.
Change some eval branch quotas so that the compiler itself still builds correctly.
This commit manually changes a file in Aro which is automatically
generated. The sources which generate the file are not in this repo.
Upstream Aro should make the suitable changes on their end before the
next sync of Aro sources into the Zig repo.