Commit graph

98 commits

Author SHA1 Message Date
Frank Denis
ca96d853ff std.crypto: add hybrid post-quantum/traditional key encapsulation
Hybrid KEMs combine a post-quantum secure KEM with a traditional
elliptic curve Diffie-Hellman key exchange.

The hybrid construction provides security against both classical and quantum
adversaries: even if one component is broken, the combined scheme remains
secure as long as the other component holds.

The implementation follows the IETF CFRG draft specification for concrete
hybrid KEMs:

https://datatracker.ietf.org/doc/draft-irtf-cfrg-concrete-hybrid-kems/
2025-11-27 12:10:17 +01:00
Frank Denis
ce355e0ba5
Add ML-DSA post-quantum signatures (#25862)
ML-DSA is a post-quantum signature scheme that was recently
standardized by NIST.

Keys and signatures are pretty large, not making it a drop-in
replacement for classical signature schemes.

But if you are shipping keys that may still be used in 10 years
or whenever large quantum computers able to break ECC arrive,
it that ever happens, and you don't have the ability to replace
these keys, ML-DSA is for you.

Performance is great, verification is faster than Ed25519 / ECDSA.

I tried manual vectorization, but it wasn't worth it, the compiler
does at good job at auto-vectorization already.
2025-11-10 14:11:30 +01:00
aarvay
2f3234c76a
std.crypto: add AES-CCM and CBC-MAC (#25526)
* std.crypto: add AES-CCM and CBC-MAC

Add AES-CCM (Counter with CBC-MAC) authenticated encryption and
CBC-MAC message authentication code implementations to the standard
library.

AES-CCM combines CTR mode encryption with CBC-MAC authentication as
specified in NIST SP 800-38C and RFC 3610. It provides authenticated
encryption with support for additional authenticated data (AAD).

CBC-MAC is a simple MAC construction used internally by CCM, specified
in FIPS 113 and ISO/IEC 9797-1.

Includes comprehensive test vectors from RFC 3610 and NIST SP 800-38C.

* std.crypto: add CCM* (encryption-only) support to AES-CCM

Implements CCM* mode per IEEE 802.15.4 specification, extending
AES-CCM to support encryption-only mode when tag_len=0. This is
required by protocols like ZigBee, Thread, and WirelessHART.

Changes:
- Allow tag_len=0 for encryption-only mode (no authentication)
- Skip CBC-MAC computation when tag_len=0 in encrypt/decrypt
- Correctly encode M'=0 in B0 block for CCM* mode
- Add Aes128Ccm0 and Aes256Ccm0 convenience instances
- Add IEEE 802.15.4 test vectors and CCM* tests

* std.crypto: add doc comments for AES-CCM variants
2025-10-14 12:00:44 +02:00
Andrew Kelley
b782cdb9b3
Merge pull request #25249 from jedisct1/siv
std.crypto: add AES-SIV and AES-GCM-SIV
2025-09-17 20:05:23 -07:00
Frank Denis
4406127cca
std.crypto: add Ascon-AEAD, Ascon-Hash, Ascon-CHash (#25239)
Ascon is the family of cryptographic constructions standardized by NIST
for lightweight cryptography.

The Zig standard library already included the Ascon permutation itself,
but higher-level constructions built on top of it were intentionally
postponed until NIST released the final specification.

That specification has now been published as NIST SP 800-232:
https://csrc.nist.gov/pubs/sp/800/232/final

With this publication, we can now confidently include these constructions
in the standard library.
2025-09-17 19:59:55 -07:00
Frank Denis
dd46e07fb9 std.crypto: add AES-SIV and AES-GCM-SIV
The Zig standard library lacked schemes that resist nonce reuse.

AES-SIV and AES-GCM-SIV are the standard options for this.

AES-GCM-SIV can be very useful when Zig is used to target embedded
systems, and AES-SIV is especially useful for key wrapping.

Also take it as an opportunity to add a bunch of test vectors to
modes.ctr and make sure it works with block ciphers whose size is
not 16.
2025-09-16 12:45:08 +02:00
Andrew Kelley
96a4e9b866 std.crypto: fix Sha1 namespace 2025-07-14 00:14:21 -07:00
Andrew Kelley
e7b18a7ce6 std.crypto: remove inline from most functions
To quote the language reference,

It is generally better to let the compiler decide when to inline a
function, except for these scenarios:

* To change how many stack frames are in the call stack, for debugging
  purposes.
* To force comptime-ness of the arguments to propagate to the return
  value of the function, as in the above example.
* Real world performance measurements demand it. Don't guess!

Note that inline actually restricts what the compiler is allowed to do.
This can harm binary size, compilation speed, and even runtime
performance.

`zig run lib/std/crypto/benchmark.zig -OReleaseFast`
[-before-] vs {+after+}

              md5:        [-990-]        {+998+} MiB/s
             sha1:       [-1144-]       {+1140+} MiB/s
           sha256:       [-2267-]       {+2275+} MiB/s
           sha512:        [-762-]        {+767+} MiB/s
         sha3-256:        [-680-]        {+683+} MiB/s
         sha3-512:        [-362-]        {+363+} MiB/s
        shake-128:        [-835-]        {+839+} MiB/s
        shake-256:        [-680-]        {+681+} MiB/s
   turboshake-128:       [-1567-]       {+1570+} MiB/s
   turboshake-256:       [-1276-]       {+1282+} MiB/s
          blake2s:        [-778-]        {+789+} MiB/s
          blake2b:       [-1071-]       {+1086+} MiB/s
           blake3:       [-1148-]       {+1137+} MiB/s
            ghash:      [-10044-]      {+10033+} MiB/s
          polyval:       [-9726-]      {+10033+} MiB/s
         poly1305:       [-2486-]       {+2703+} MiB/s
         hmac-md5:        [-991-]        {+998+} MiB/s
        hmac-sha1:       [-1134-]       {+1137+} MiB/s
      hmac-sha256:       [-2265-]       {+2288+} MiB/s
      hmac-sha512:        [-765-]        {+764+} MiB/s
      siphash-2-4:       [-4410-]       {+4438+} MiB/s
      siphash-1-3:       [-7144-]       {+7225+} MiB/s
   siphash128-2-4:       [-4397-]       {+4449+} MiB/s
   siphash128-1-3:       [-7281-]       {+7374+} MiB/s
  aegis-128x4 mac:      [-73385-]      {+74523+} MiB/s
  aegis-256x4 mac:      [-30160-]      {+30539+} MiB/s
  aegis-128x2 mac:      [-66662-]      {+67267+} MiB/s
  aegis-256x2 mac:      [-16812-]      {+16806+} MiB/s
   aegis-128l mac:      [-33876-]      {+34055+} MiB/s
    aegis-256 mac:       [-8993-]       {+9087+} MiB/s
         aes-cmac:       2036 MiB/s
           x25519:      [-20670-]      {+16844+} exchanges/s
          ed25519:      [-29763-]      {+29576+} signatures/s
       ecdsa-p256:       [-4762-]       {+4900+} signatures/s
       ecdsa-p384:       [-1465-]       {+1500+} signatures/s
  ecdsa-secp256k1:       [-5643-]       {+5769+} signatures/s
          ed25519:      [-21926-]      {+21721+} verifications/s
          ed25519:      [-51200-]      {+50880+} verifications/s (batch)
 chacha20Poly1305:       [-1189-]       {+1109+} MiB/s
xchacha20Poly1305:       [-1196-]       {+1107+} MiB/s
 xchacha8Poly1305:       [-1466-]       {+1555+} MiB/s
 xsalsa20Poly1305:        [-660-]        {+620+} MiB/s
      aegis-128x4:      [-76389-]      {+78181+} MiB/s
      aegis-128x2:      [-53946-]      {+53495+} MiB/s
       aegis-128l:      [-27219-]      {+25621+} MiB/s
      aegis-256x4:      [-49351-]      {+49542+} MiB/s
      aegis-256x2:      [-32390-]      {+32366+} MiB/s
        aegis-256:       [-8881-]       {+8944+} MiB/s
       aes128-gcm:       [-6095-]       {+6205+} MiB/s
       aes256-gcm:       [-5306-]       {+5427+} MiB/s
       aes128-ocb:       [-8529-]      {+13974+} MiB/s
       aes256-ocb:       [-7241-]       {+9442+} MiB/s
        isapa128a:        [-204-]        {+214+} MiB/s
    aes128-single:  [-133857882-]  {+134170944+} ops/s
    aes256-single:   [-96306962-]   {+96408639+} ops/s
         aes128-8: [-1083210101-] {+1073727253+} ops/s
         aes256-8:  [-762042466-]  {+767091778+} ops/s
           bcrypt:      0.009 s/ops
           scrypt:      [-0.018-]      {+0.017+} s/ops
           argon2:      [-0.037-]      {+0.060+} s/ops
      kyber512d00:     [-206057-]     {+205779+} encaps/s
      kyber768d00:     [-156074-]     {+150711+} encaps/s
     kyber1024d00:     [-116626-]     {+115469+} encaps/s
      kyber512d00:     [-181149-]     {+182046+} decaps/s
      kyber768d00:     [-136965-]     {+135676+} decaps/s
     kyber1024d00:     [-101307-]     {+100643+} decaps/s
      kyber512d00:     [-123624-]     {+123375+} keygen/s
      kyber768d00:      [-69465-]      {+70828+} keygen/s
     kyber1024d00:      [-43117-]      {+43208+} keygen/s
2025-07-13 18:26:13 +02:00
Linus Groh
eb37552536 Remove numerous things deprecated during the 0.14 release cycle
Basically everything that has a direct replacement or no uses left.

Notable omissions:

- std.ArrayHashMap: Too much fallout, needs a separate cleanup.
- std.debug.runtime_safety: Too much fallout.
- std.heap.GeneralPurposeAllocator: Lots of references to it remain, not
  a simple find and replace as "debug allocator" is not equivalent to
  "general purpose allocator".
- std.io.Reader: Is being reworked at the moment.
- std.unicode.utf8Decode(): No replacement, needs a new API first.
- Manifest backwards compat options: Removal would break test data used
  by TestFetchBuilder.
- panic handler needs to be a namespace: Many tests still rely on it
  being a function, needs a separate cleanup.
2025-07-11 08:17:43 +02:00
Frank Denis
a7122b7323
std.crypto: add constant-time codecs (#23420)
std.crypto: add constant-time codecs

Add constant-time hex/base64 codecs designed to process cryptographic
secrets, adapted from libsodium's implementations.

Introduce a `crypto.codecs` namespace for crypto-related encoders and
decoders. Move ASN.1 codecs to this namespace.

This will also naturally accommodate the proposed PEM codecs.
2025-04-12 20:13:45 +02:00
Andrew Kelley
ed7004a2ee
Merge pull request #19976 from clickingbuttons/asn1
std.crypto: Add ASN1 module with OIDs and DER
2025-02-22 20:21:09 -05:00
Frank Denis
295c5a64f5
Reinstantiates AEGIS-MAC with the final construction (#22205)
This reverts commit c9d6f8b505.
2024-12-11 18:52:43 +01:00
Frank Denis
c9d6f8b505
Remove parallel variants of AEGIS-MAC (#22146)
The construction is likely to change before standardization
2024-12-04 22:45:07 +00:00
Frank Denis
636308a17d
std.crypto.aes: introduce AES block vectors (#22023)
* 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
2024-11-22 10:00:49 +01:00
Frank Denis
b131b6dd36 Rename the namespace for ml_kem variants of Kyber to nist 2024-08-22 07:54:12 +02:00
Andrew Kelley
54151428e5 std.crypto: better names for everything in utils
std.crypto has quite a few instances of breaking naming conventions.
This is the beginning of an effort to address that.

Deprecates `std.crypto.utils`.
2024-08-09 19:47:06 -07:00
clickingbuttons
330d353d6e std.crypto: Add ASN1 module with OIDs and DER
Add module for mapping ASN1 types to Zig types. See
`asn1.Tag.fromZig` for the mapping. Add DER encoder and decoder.

See `asn1/test.zig` for example usage of every ASN1 type.

This implementation allows ASN1 tags to be overriden with `asn1_tag`
and `asn1_tags`:
```zig
const MyContainer = (enum | union | struct) {
    field: u32,

    pub const asn1_tag = asn1.Tag.init(...);

    // This specifies a tag's class, and if explicit, additional encoding
    // rules.
    pub const asn1_tags = .{
        .field = asn1.FieldTag.explicit(0, .context_specific),
    };
};
```

Despite having an enum tag type, ASN1 frequently uses OIDs as enum
values. This is supported via an `pub const oids` field.
```zig
const MyEnum = enum {
    a,

    pub const oids = asn1.Oid.StaticMap(MyEnum).initComptime(.{
        .a = "1.2.3.4",
    });
};
```

Futhermore, a container may choose to implement encoding and decoding
however it deems fit. This allows for derived fields since Zig has a far
more powerful type system than ASN1.
```zig
// ASN1 has no standard way of tagging unions.
const MyContainer = union(enum) {
    derived: PowerfulZigType,

    const WeakAsn1Type = ...;

    pub fn encodeDer(self: MyContainer, encoder: *der.Encoder) !void {
        try encoder.any(WeakAsn1Type{...});
    }

    pub fn decodeDer(decoder: *der.Decoder) !MyContainer {
        const weak_asn1_type = try decoder.any(WeakAsn1Type);
        return .{ .derived = PowerfulZigType{...} };
    }
};
```
An unfortunate side-effect is that decoding and encoding cannot have
complete complete error sets unless we limit what errors users may
return. Luckily, PKI ASN1 types are NOT recursive so the inferred
error set should be sufficient.

Finally, other encodings are possible, but this patch only implements
a buffered DER encoder and decoder.

In an effort to keep the changeset minimal this PR does not actually
use the DER parser for stdlib PKI, but a tested example of how it may
be used for Certificate is available
[here.](https://github.com/clickingbuttons/asn1/blob/69c5709d/src/Certificate.zig)

Closes #19775.
2024-05-15 15:59:24 -04:00
Andrew Kelley
cb4e087fda
Merge pull request #19239 from jedisct1/ml-kem
std.crypto: add support for ML-KEM
2024-03-11 18:48:08 -07:00
Andrew Kelley
aa852f737b improve documentation in std
A lot of these "shorthand" doc comments were redundant, low quality
filler content. Better to let the actual modules speak for themselves
with top level doc comments rather than trying to document their
aliases.
2024-03-10 18:13:30 -07:00
Frank Denis
1ca3a48b87 std.crypto: add support for ML-KEM
ML-KEM is the Kyber post-quantum secure key encapsulation mechanism,
as being standardized by NIST.

Too bad, they decided to rename it; the "Kyber" name was so much
better!

This implements the current draft (NIST FIPS-203), which is already
being deployed even though the specification is not finalized.
2024-03-10 15:48:38 +01:00
Jacob Young
8f69e977f1 x86_64: implement 128-bit builtins
* `@clz`
 * `@ctz`
 * `@popCount`
 * `@byteSwap`
 * `@bitReverse`
 * various encodings used by std
2023-10-23 22:42:18 -04:00
Jacob Young
27fe945a00 Revert "Revert "Merge pull request #17637 from jacobly0/x86_64-test-std""
This reverts commit 6f0198cadb.
2023-10-22 15:46:43 -04:00
Andrew Kelley
6f0198cadb Revert "Merge pull request #17637 from jacobly0/x86_64-test-std"
This reverts commit 0c99ba1eab, reversing
changes made to 5f92b070bf.

This caused a CI failure when it landed in master branch due to a
128-bit `@byteSwap` in std.mem.
2023-10-22 12:16:35 -07:00
Jacob Young
2e6e39a700 x86_64: fix bugs and disable erroring tests 2023-10-21 10:55:41 -04:00
Frank Denis
89f622fc68
std.crypto.ff - Alloc-free, constant-time field arithmetic for crypto (#15795)
A minimal set of simple, safe functions for Montgomery arithmetic,
designed for cryptographic primitives.

Also update the current RSA cert validation to use it, getting rid
of the FixedBuffer hack and the previous limitations.

Make the check of the RSA public key a little bit more strict by
the way.
2023-05-22 16:11:06 +02:00
Frank Denis
391663e497
AEGIS MAC: add support for 128-bit tags (#15379)
When used as a MAC, 256-bit tags are recommended.
But in interactive protocols, 128 bits may be acceptable.
2023-04-21 19:52:33 +00:00
Frank Denis
b42562be74
std.crypto.aegis: support 256-bit tags (#15276) 2023-04-14 11:20:36 +02:00
Frank Denis
dff4bbfd24
Remove Gimli and Xoodoo from the standard library (#14928)
These are great permutations, and there's nothing wrong with them
from a practical security perspective.

However, both were competing in the NIST lightweight crypto
competition.

Gimli didn't pass the 3rd selection round, and is not much used
in the wild besides Zig and libhydrogen. It will never be
standardized and is unlikely to get more traction in the future.

Xoodyak, that Xoodoo is the permutation of, was a finalist.

It has a lot of advantages and *might* be standardized without NIST.
But this is too early to tell, and too risky to commit to it
in a standard library.

For lightweight crypto, Ascon is the one that we know NIST will
standardize and that we can safely rely on from a usage perspective.

Switch to a traditional ChaCha-based CSPRNG, with an Ascon-based one
as an option for constrained systems.

Add a RNG benchmark by the way.

Gimli and Xoodoo served us well. Their code will be maintained,
but outside the standard library.
2023-03-21 04:54:10 +00:00
Bas Westerbaan
4414f9c46e
Add Kyber post-quantum key encapsulation mechanism (#14902)
Implementation of the IND-CCA2 post-quantum secure key encapsulation
mechanism (KEM) CRYSTALS-Kyber, as submitted to the third round of the NIST
Post-Quantum Cryptography (v3.02/"draft00"), and selected for standardisation.

Co-authored-by: Frank Denis <124872+jedisct1@users.noreply.github.com>
2023-03-15 03:50:45 +00:00
Frank Denis
5a12d00708
Move std.crypto.config options to std.options (#14906)
Options have been moved to a single namespace.
2023-03-14 06:40:23 +00:00
Frank Denis
9622991578
Add configurable side channels mitigations; enable them on soft AES (#13739)
* Add configurable side channels mitigations; enable them on soft AES

Our software AES implementation doesn't have any mitigations against
side channels.

Go's generic implementation is not protected at all either, and even
OpenSSL only has minimal mitigations.

Full mitigations against cache-based attacks (bitslicing, fixslicing)
come at a huge performance cost, making AES-based primitives pretty
much useless for many applications. They also don't offer any
protection against other classes of side channel attacks.

In practice, partially protected, or even unprotected implementations
are not as bad as it sounds. Exploiting these side channels requires
an attacker that is able to submit many plaintexts/ciphertexts and
perform accurate measurements. Noisy measurements can still be
exploited, but require a significant amount of attempts. Wether this
is exploitable or not depends on the platform, application and the
attacker's proximity.

So, some libraries made the choice of minimal mitigations and some
use better mitigations in spite of the performance hit. It's a
tradeoff (security vs performance), and there's no one-size-fits all
implementation.

What applies to AES applies to other cryptographic primitives.

For example, RSA signatures are very sensible to fault attacks,
regardless of them using the CRT or not. A mitigation is to verify
every produced signature. That also comes with a performance cost.
Wether to do it or not depends on wether fault attacks are part of
the threat model or not.

Thanks to Zig's comptime, we can try to address these different
requirements.

This PR adds a `side_channels_protection` global, that can later
be complemented with `fault_attacks_protection` and possibly other
knobs.

It can have 4 different values:

- `none`: which doesn't enable additional mitigations.
"Additional", because it only disables mitigations that don't have
a big performance cost. For example, checking authentication tags
will still be done in constant time.

- `basic`: which enables mitigations protecting against attacks in
a common scenario, where an attacker doesn't have physical access to
the device, cannot run arbitrary code on the same thread, and cannot
conduct brute-force attacks without being throttled.

- `medium`: which enables additional mitigations, offering practical
protection in a shared environement.

- `full`: which enables all the mitigations we have.

The tradeoff is that the more mitigations we enable, the bigger the
performance hit will be. But this let applications choose what's
best for their use case.

`medium` is the default.

Currently, this only affects software AES, but that setting can
later be used by other primitives.

For AES, our implementation is a traditional table-based, with 4
32-bit tables and a sbox.

Lookups in that table have been replaced by function calls. These
functions can add a configurable noise level, making cache-based
attacks more difficult to conduct.

In the `none` mitigation level, the behavior is exactly the same
as before. Performance also remains the same.

In other levels, we compress the T tables into a single one, and
read data from multiple cache lines (all of them in `full` mode),
for all bytes in parallel. More precise measurements and way more
attempts become necessary in order to find correlations.

In addition, we use distinct copies of the sbox for key expansion
and encryption, so that they don't share the same L1 cache entries.

The best known attacks target the first two AES round, or the last
one.

While future attacks may improve on this, AES achieves full
diffusion after 4 rounds. So, we can relax the mitigations after
that. This is what this implementation does, enabling mitigations
again for the last two rounds.

In `full` mode, all the rounds are protected.

The protection assumes that lookups within a cache line are secret.
The cachebleed attack showed that it can be circumvented, but
that requires an attacker to be able to abuse hyperthreading and
run code on the same core as the encryption, which is rarely a
practical scenario.

Still, the current AES API allows us to transparently switch to
using fixslicing/bitslicing later when the `full` mitigation level
is enabled.

* Software AES: use little-endian representation.

Virtually all platforms are little-endian these days, so optimizing
for big-endian CPUs doesn't make sense any more.
2023-03-13 22:18:26 +01:00
Frank Denis
28364166e8
crypto.hash.sha3: make permutation generic and public, add SHAKE (#14756)
Make the Keccak permutation public, as it's useful for more than
SHA-3 (kMAC, SHAKE, TurboSHAKE, TupleHash, etc).

Our Keccak implementation was accepting f as a comptime parameter,
but always used 64-bit words and 200 byte states, so it actually
didn't work with anything besides f=1600.

That has been fixed. The ability to use reduced-round versions
was also added in order to support M14 and K12.

The state was constantly converted back and forth between bytes
and words, even though only a part of the state is actually used
for absorbing and squeezing bytes. It was changed to something
similar to the other permutations we have, so we can avoid extra
copies, and eventually add vectorized implementations.

In addition, the SHAKE extendable output function (XOF) was
added (SHAKE128, SHAKE256). It is required by newer schemes,
such as the Kyber post-quantum key exchange mechanism, whose
implementation is currently blocked by SHAKE missing from our
standard library.

Breaking change: `Keccak_256` and `Keccak_512` were renamed to
`Keccak256` and `Keccak512` for consistency with all other
hash functions.
2023-03-02 06:13:40 +00:00
Chris Boesch
438b71155a
crypto: add AES-CMAC (RFC 4493) (#14545)
* crypto: add AES-CMAC

Co-authored-by: Frank Denis <124872+jedisct1@users.noreply.github.com>
2023-02-16 21:18:20 +01:00
Frank Denis
f62e3b8c0d std.crypto: add the Ascon permutation
Ascon has been selected as new standard for lightweight cryptography
in the NIST Lightweight Cryptography competition.

Ascon won over Gimli and Xoodoo.

The permutation is unlikely to change. However, NIST may tweak
the constructions (XOF, hash, authenticated encryption) before
standardizing them. For that reason, implementations of those
are better maintained outside the standard library for now.

In fact, we already had an Ascon implementation in Zig:
`std.crypto.aead.isap` is based on it. While the implementation was
here, there was no public API to access it directly.

So:

- The Ascon permutation is now available as `std.crypto.core.Ascon`,
with everything needed to use it in AEADs and other Ascon-based
constructions
- The ISAP implementation now uses std.crypto.core.Ascon instead of
keeping a private copy
- The default CSPRNG replaces Xoodoo with Ascon. And instead of an
ad-hoc construction, it's using the XOFa mode of the NIST submission.
2023-02-13 02:22:24 -05:00
Andrew Kelley
c71c562486 remove std.crypto.der
Only a little bit of generalized logic for DER encoding is needed and so
it can live inside the Certificate namespace.

This commit removes the generic "parse object id" function which is no
longer used in favor of more specific, smaller sets of object ids used
with ComptimeStringMap.
2023-01-02 16:57:15 -07:00
Andrew Kelley
29475b4518 std.crypto.tls: validate previous certificate 2023-01-02 16:57:15 -07:00
Andrew Kelley
bbc074252c introduce std.crypto.CertificateBundle
for reading root certificate authority bundles from standard
installation locations on the file system. So far only Linux logic is
added.
2023-01-02 16:57:15 -07:00
Andrew Kelley
93ab8be8d8 extract std.crypto.tls.Client into separate namespace 2023-01-02 16:57:15 -07:00
Andrew Kelley
ba44513c2f std.http reorg; introduce std.crypto.Tls
TLS is capable of sending a Client Hello
2023-01-02 16:57:15 -07:00
Andrew Kelley
3bf97bfd46 std: remove OOM workarounds
No longer needed since stage1 is deleted.
2022-12-14 11:42:28 -05:00
Frank Denis
ea05223b63
std.crypto.auth: add AEGIS MAC (#13607)
* Update the AEGIS specification URL to the current draft

* std.crypto.auth: add AEGIS MAC

The Pelican-based authentication function of the AEGIS construction
can be used independently from authenticated encryption, as a faster
and more secure alternative to GHASH/POLYVAL/Poly1305.

We already expose GHASH, POLYVAL and Poly1305 for use outside AES-GCM
and ChaChaPoly, so there are no reasons not to expose the MAC from AEGIS
as well.

Like other 128-bit hash functions, finding a collision only requires
~2^64 attempts or inputs, which may still be acceptable for many
practical applications.

Benchmark (Apple M1):

    siphash128-1-3:       3222 MiB/s
             ghash:       8682 MiB/s
    aegis-128l mac:      12544 MiB/s

Benchmark (Zen 2):

    siphash128-1-3:       4732 MiB/s
             ghash:       5563 MiB/s
    aegis-128l mac:      19270 MiB/s
2022-11-22 18:16:04 +01:00
Frank Denis
c45c6cd492 Add the POLYVAL universal hash function
POLYVAL is GHASH's little brother, required by the AES-GCM-SIV
construction. It's defined in RFC8452.

The irreducible polynomial is a mirror of GHASH's (which doesn't
change anything in our implementation that didn't reverse the raw
bits to start with).

But most importantly, POLYVAL encodes byte strings as little-endian
instead of big-endian, which makes it a little bit faster on the
vast majority of modern CPUs.

So, both share the same code, just with comptime magic to use the
correct endianness and only double the key for GHASH.
2022-11-20 18:13:19 -05:00
Frank Denis
907f3ef887
crypto.salsa20: make the number of rounds a comptime parameter (#13442)
...instead of hard-coding it to 20.

- This is consistent with the ChaCha implementation
- NaCl and libsodium, that this API is designed to interop with,
also support 8 and 12 round variants. The 12 round variant, in
particular, provides the same security level as the 20 round variant,
but is obviously faster.
- scrypt currently uses its own non optimized version of Salsa, just
because it use 8 rounds instead of 20. This will help remove code
duplication.

No behavior nor public API changes. The Salsa20 and XSalsa20 still
represent the 20-round variant.
2022-11-06 23:52:41 +01:00
Frank Denis
ee01dd4032
crypto: add the Xoodoo permutation, prepare for Gimli deprecation (#11866)
Gimli was a game changer. A permutation that is large enough to be
used in sponge-like constructions, yet small enough to be compact
to implement and fast on a wide range of platforms.

And Gimli being part of the Zig standard library was awesome.

But since then, Gimli entered the NIST Lightweight Cryptography
Competition, competing againt other candidates sharing a similar set
of properties.

Unfortunately, Gimli didn't pass the 3rd round.

There are no practical attacks against Gimli when used correctly, but
NIST's decision means that Gimli is unlikely to ever get any traction.

So, maybe the time has come to move Gimli from the standard library
to another repository.

We shouldn't do it without providing an alternative, though.
And the best candidate for this is probably Xoodoo.

Xoodoo is the core function of Xoodyak, one of the finalists of the
NIST LWC competition, and the most direct competitor to Gimli. It is
also a 384-bit permutation, so it can easily be used everywhere Gimli
was used with no parameter changes.

It is the building block of Xoodyak (for actual encryption and hashing)
as well as Charm, that some Zig applications are already using.

Like Gimli that it was heavily inspired from, it is compact and
suitable for constrained environments.

This change adds the Xoodoo permutation to std.crypto.core.

The set of public functions includes everything required to later
implement existing Xoodoo-based constructions.

In order to prepare for the Gimli deprecation, the default
CSPRNG was changed to a Xoodoo-based that works exactly the same way.
2022-07-01 13:18:08 +02:00
Frank Denis
48fd92365a
std.crypto.hash: allow creating hash functions from compositions (#11965)
A hash function cascade was a common way to avoid length-extension
attacks with traditional hash functions such as the SHA-2 family.

Add `std.crypto.hash.composition` to do exactly that using arbitrary
hash functions, and pre-define the common SHA2-based ones.

With this, we can now sign and verify Bitcoin signatures in pure Zig.
2022-07-01 11:37:41 +02:00
Frank Denis
234ccb4a50
std.crypto.ecc: add support for the secp256k1 curve (#11880)
std.crypto.ecc: add support for the secp256k1 curve

Usage of the secp256k1 elliptic curve recently grew exponentially,
since this is the curve used by Bitcoin and other popular blockchains
such as Ethereum.

With this, Zig has support for all the widely deployed elliptic curves
today.
2022-06-29 15:11:33 +02:00
Frank Denis
27610b0a0f
std/crypto: add support for ECDSA signatures (#11855)
ECDSA is the most commonly used signature scheme today, mainly for
historical and conformance reasons. It is a necessary evil for
many standard protocols such as TLS and JWT.

It is tricky to implement securely and has been the root cause of
multiple security disasters, from the Playstation 3 hack to multiple
critical issues in OpenSSL and Java.

This implementation combines lessons learned from the past with
recent recommendations.

In Zig, the NIST curves that ECDSA is almost always instantied with
use formally verified field arithmetic, giving us peace of mind
even on edge cases. And the API rejects neutral elements where it
matters, and unconditionally checks for non-canonical encoding for
scalars and group elements. This automatically eliminates common
vulnerabilities such as https://sk.tl/2LpS695v .

ECDSA's security heavily relies on the security of the random number
generator, which is a concern in some environments.

This implementation mitigates this by computing deterministic
nonces using the conservative scheme from Pornin et al. with the
optional addition of randomness as proposed in Ericsson's
"Deterministic ECDSA and EdDSA Signatures with Additional Randomness"
document. This approach mitigates both the implications of a weak RNG
and the practical implications of fault attacks.

Project Wycheproof is a Google project to test crypto libraries against
known attacks by triggering edge cases. It discovered vulnerabilities
in virtually all major ECDSA implementations.

The entire set of ECDSA-P256-SHA256 test vectors from Project Wycheproof
is included here. Zero defects were found in this implementation.

The public API differs from the Ed25519 one. Instead of raw byte strings
for keys and signatures, we introduce Signature, PublicKey and SecretKey
structures.

The reason is that a raw byte representation would not be optimal.
There are multiple standard representations for keys and signatures,
and decoding/encoding them may not be cheap (field elements have to be
converted from/to the montgomery domain).

So, the intent is to eventually move ed25519 to the same API, which
is not going to introduce any performance regression, but will bring
us a consistent API, that we can also reuse for RSA.
2022-06-15 08:55:39 +02:00
Frank Denis
26aea8cfa1
crypto: add support for the NIST P-384 curve (#11735)
After P-256, here comes P-384, also known as secp384r1.

Like P-256, it is required for TLS, and is the current NIST recommendation for key exchange and signatures, for better or for worse.

Like P-256, all the finite field arithmetic has been computed and verified to be correct by fiat-crypto.
2022-05-31 17:29:38 +02:00
Andrew Kelley
75bbc74d56 a small crusade against std.meta.declarations 2022-01-31 22:25:49 -07:00
Meghan
f1b79c9a44 std.crypto.random: Randoms are no longer passed by reference 2022-01-25 13:00:39 -05:00