Hacker News new | past | comments | ask | show | jobs | submit login
Tink – Cryptographic APIs that are secure, easy to use correctly (github.com/google)
153 points by todotask on May 17, 2020 | hide | past | favorite | 49 comments

Tink addresses things libsodium doesn't really do.

Native support for AWS Key Management System and its equivalent on other cloud platforms is a huge win; we should all be using more of these. But libsodium would have to start mandating a TLS library and an HTTP library and whatnot, interfering with people's existing setups; you can't really do that without C programmers getting angry at you.

It deals with not only key generation, but also key serialization. libsodium kind of strands you when it comes to the question how to actually store keys.

Deterministic nonces have also been something that libsodium appears to have rejected: https://github.com/jedisct1/libsodium/issues/392

If you're looking at it from a misuse-prevention perspective, Tink is probably a major step up that accounts for modern use cases. libsodium's kind of in a lower level niche and suffers from being held back by C and its notoriously anemic standard library.

> but also key serialization. libsodium kind of strands you when it comes to the question how to actually store keys.

Hmm. Is there really interesting work needed here? The keys are (should be treated as) an opaque blob and it'll probably generally be a mistake to do anything with them except load them back into (maybe a different language implementation of) Tink / libsodium.

If you're a cryptanalyst it can make sense to get a structure rather than a blob but I don't see a value in this for the intended users of Tink, and if it's just a blob -- who doesn't know how to serialize and de-serialize some bytes in their preferred language?

Disclaimer: I'm a maintainer of Tink.

From a user's point of view, keys are still binary blob. Internally Tink serializes keys using protobuf, but in principle it supports arbitrary key formats via the KeysetReader/KeysetWriter interfaces. Admittedly, this aspect of our design is somewhat clumsy. We're working on a new design.

The key differences (pun intended) between Tink and other libraries are:

1/ Tink works with keysets instead of individual keys. This enables key rotation and crypto agility. This is very important at Google because there are systems that generate too much data to encrypt with a single key. We want to be able to rotate keys and still be able to decrypt old ciphertext.

Also most crypto schemes we're using today would be broken eventually. We want to make sure we can add new schemes and retire old ones over time without users having to change their code. For example, a lot of libraries have functions containing algorithm names, e.g., aes_gcm_encrypt. When GCM is no longer adequate, users of these libraries would have a hard time upgrading to alternatives.

Tink interfaces don't contain the algorithm name. We name our APIs after generic crypto primitives rather than famous cryptographers or algorithms. For example, we provide a generic AEAD interface for symmetric key encryption. With proper key management, users don't have to know anything about any particular algorithms and can easily rotate to new ones without changing a single line of code (rather than upgrading Tink).

2/ A key in Tink contains not only the raw key material, but also all necessary parameters. It is equivalent to the result of a handshake. Before any data encryption can take place, both sides have to reach an agreement not only on a raw key, but also how to use that key to encrypt data. Since a key in Tink contains all parameters, Tink does not require in-band ciphersuite negotiation. That is no ciphertext in Tink contains any other metadata aside from a key ID.

This design sounds so simple but I've seen people get this wrong all the time. For example, the root cause of many embarrassing vulnerabilities in JWT [1] is in-band ciphersuite negotiation. That is, a JWT contains an alg field that dictates how the receiver should process it. This alg field should rather be included as part of the key.

JWT is not the only standard making this mistake. Many crypto libraries only ask users for the raw key material. This means the parameters are either implicitly assumed or under specified. Aside from the aforementioned vulnerabilities, this can also lead to key confusion, cross-protocol key reuse and make it hard to rotate keys or change algorithms.

To the best of my knowledge, Tink is the only high-level library that gets this right.

[1] https://auth0.com/blog/critical-vulnerabilities-in-json-web-...

Thanks for helping make cryptography usable and safe for the common person. Keep up the good work

And libsodium does things Tink doesn't do: provide a C API.

It doesn't, but it provides a first-class C++ API.

If I was starting a new project today, I'd probably go a little bit out of my way to try to use Tink instead of libsodium.

> It doesn't, but it provides a first-class C++ API.

Sure; I get that. There are C projects where that isn't acceptable, while libsodium is. It makes a lot of sense to use Tink if you're working in Go (which I know you're fond of) or Java or other high-level languages Tink supports. I tend to work with a lot of C (not C++) codebases, and I wouldn't choose or recommend C++ in a new project today.

Can't really argue with the makers of proprietary microcontrollers about what tooling they provide though.

Yeah, and also it is actually really easy to use. I justed checked the Python how-to for Tink and it's a lot more verbose than NaCl.

Unless there’s significant clearly defined differences - in my opinion (2018) should be added to the title.


Disclaimer: I'm a maintainer of Tink.

We've added tons of new features since 2018, including support for two new languages Golang and Python.

The team has grown from 4 20% contributors to 5 full-time and countless contributors.

Please checkout the following release notes for a list of changes:



First of all, thank you for your work on Tink!

Is there a chance that a Dart port might be added in the foreseeable future? I totally understand that it's a ton of work to support another language and I really appreciate all the work that has already been put in, but I just have to ask since right now there is no high level cryptographic library for Dart mature enough that I would trust it for real use.

(Tink seems perfect for usage in mobile and web apps that Dart & Flutter target, and given that Dart is the only language heavily used by Google without Tink support it would make a great addition. If no native Dart implementation is planned, maybe a wrapper could be considered, using the Java/C++ bindings on mobile/native and the upcoming Javascript bindings for Dart/Flutter web support?)

That post was from when v1.2.0 came out, they are getting close to 1.4.0 (on RC2 right now). Nothing too big has been added, but there have been improvements across the library for all the languages they support. You can peak at the releases pages for differences. https://github.com/google/tink/releases

I know they've added a Go port since that release.

Does anyone know how this compares to other libraries such as NaCl and libsodium? Neither the readme nor the slides seem to mention other projects in this space.

I think the first comment from 2018 might still answer your question.


Native-language reimplementations for each high-level language platform instead of wrapping a C library, for a start. In some respects they have similar objectives but different targets and scope.

Disclaimer: I'm one of the maintainers of Tink.

I'm not sure if NaCl itself is production ready, but I'm a great fan of libsodium. If I weren't working on Tink, I'd use libsodium for my personal projects. Did you know that Frank Denis [1] the creator of libsodium is not working full time on crypto or security? He's a professional photographer. I can't figure out how he manages to single-handedly maintain such a high-profile high-quality library as a side project. We have a team of full time cryptographers and engineers working on Tink, but we've struggled a lot.

We started Tink because all existing libraries that we had at Google didn't meet our requirements.

Business-wise, we need an open source library that can work on all major platforms that Google products run on including web, iOS, Android, Borg and GCP. There are many Google products that need crypto integration with external partners. While we can take care of the crypto implementation on our side, we found that many partners got it wrong. It'd be very nice if they can use the same library that we're using internally.

We learned very early that a single ciphersuite wouldn't work for everybody. Some would need short ciphertext. Some would need speed. Some would need FIPS certified. We want a library that can support a wide range of options. It should be easy to add new options and remove old ones.

Security-wise, we found that most libraries are either too high-level or too low.

The latter ask users for security-critical input such as nonces or randomness. In most crypto schemes, using a wrong kind of nonces can totally break an otherwise secure scheme. Based on our experience working with tens of thousands of engineers at Google, we found that most engineers can't tell why the IV must be non-repeated in some schemes but unpredictable in others. More importantly, we found that this level of control is not needed when using crypto to implement security/privacy features in most of our products. Tink aims to eliminate as many potential misuses as possible. For example, if the underlying encryption mode requires nonces and is insecure if nonces are reused, then Tink does not allow the passing of nonces by the user.

Why is too high-level also a bad idea? We found that many libraries provide a single API for different kinds of crypto primitive. For example, sign() is used for both MAC and digital signatures, and encrypt() for both AEAD and public key encryption. This reduces readability, making code review much harder because the crypto APIs can't provide accurate information on the security guarantees of the implementations.

Last but not least, Tink encourages the usage of key management system. Most libraries don't care where the keys come from, and as a result many users use hardcoded keys. Tink encourages developers to store keys encrypted or within a KMS. It provides security teams mechanisms to enforce this requirement. For example, at Google developers can't use Tink in production with keys stored outside our KMS, unless they got an explicit approval from us.

Further explanations of these design goals can be found in [2].

To wrap this up, IMHO libsodium and Tink are targeting different groups of audience. libsodium is great for personal projects, when you know what you're doing and can take care of yourself. Tink provides more bells and whistles which are useful when you want to do crypto in an enterprise setting.

[1] https://00f.net/

[2] https://github.com/google/tink/blob/master/docs/SECURITY-USA...

NaCl/sodium uses Bernstein-crypto by default, Tink uses NIST (e.g. AES-GCM)?

Tink does EAX, SIV, and Chapoly as well as GCM.

There is also libhydrogen [1] which is a "small, easy-to-use, hard-to-misuse cryptographic library".

[1] https://github.com/jedisct1/libhydrogen/blob/master/README.m...

The obvious question about Tink is how it compares to libsodium. It's great that so many people ask, because it suggests that libsodium has successfully lodged itself into our collective consciousness. Both of these projects are forces for good in the world: they replace error-prone low-level crypto libraries with high-level interfaces designed for use by generalist developers.

I've reviewed projects that used Tink but never built one myself. So, grain of Nacl (haha i kill me). I've used libsodium in anger many times. Here's roughly my comparison:

* Both libsodium and Tink will do authenticated ("seal/unseal") cryptography using GCM (the deficient but de facto standard) or Chapoly (Bernstein's primitives). Tink will also do EAX, an AES AEAD that's less fragile in some ways than GCM, and, on the C++ platform, AES-GCM-SIV, which is both fast and misuse-resistant.

* Both libsodium and Tink will do streaming authenticated encryption (efficiently sealing and unsealing files and streams that are too large to buffer entirely in memory before transforming).

* Tink will do deterministic authenticated encryption with AES-SIV; Tink provides this feature for building things like encrypted search features but I think it's more commonly used as a safety feature for scenarios where nonce reuse is likely and revealing duplicate messages is not a major threat.

* Both libsodium and Tink will do ED25519 signatures. Tink will also do P-curve signatures and RSA.

* Both libsodium and Tink will do hybrid encryption (what libsodium would call "box"). libsodium uses Curve25519 and Chapoly; Tink uses P-curves and either GCM or CTR+HMAC (both of them AEAD modes).

* Tink has direct support for a bunch of platforms, notably including Java; unlike Tink, libsodium is, and thus has direct support for, C projects, and is provided for other languages through its C bindings. Tink has first-class C++ support (and its Python support is bindings to its C++ version), but not C.

* libsodium has much better documentation and a much bigger community. Tink is a Google project (it's the evolution of Keyczar, Google's first high-level cryptography library). On the other hand, Daniel Bleichenbacher is on the Tink team. I don't love P-curve crypto, but I'll use an implementation Bleichenbacher put his name on.

* Tink has better key management features and direct support for GCP and AWS KMS. It's not hard to build that feature for libsodium, but it's there already in Tink. Tink may get support for Android Strongbox (it already has support for the Android key storage API); it's probably a really strong choice for Android applications already.

They're both valid choices. If I was making a recommendation to a stranger without much context, I'd almost always recommend libsodium, unless you're doing Android. If it was me, on a new project, I might lean towards Tink at this point.

Happy to be corrected if I got any of this wrong.

Previous discussion (2018) : https://news.ycombinator.com/item?id=17877616

There is an open issue for adding Tink information into Wikipedia, if anyone who is knowledgable to take this task will be appreciated.


Hmm it seems you haven't finished your sentence? "The following article..." what about it?

I hoped this one wouldn't depend on WebCrypto (in Javascript), but seems like it is dependent :( No cryptography without https, still.

I just don't get it: why can't I use `ed25519.sign` without being on secure origin.

The only reason I can think of is: don't allow people to create p2p networks without CA control and approval. I'm talking about this https://github.com/w3c/webcrypto/issues/28 . Because of that requirement, you can't use WebCrypto primitives on http sites.

So I can't implement my own security on network channel (in web app) without first getting approval from Big Guys, who can revoke it at their will.

The only reason you can think of is a weird conspiracy?

WebCrypto only arguably skirts Mozilla's original (2015) definition of new features that shouldn't be enabled for insecure contexts.

(Mozilla says you might want to allow new features that could anyway be polyfilled, and though a polyfilled WebCrypto would be slow and under powered it could be built)

You can't bootstrap your "security on network channel (in web app)" without a secure origin because it's a house built on sand.

Some of the things people want to do in that issue are merely daft (e.g. people who are sad that they can't access a crypto-hash for their problem which would be much better suited to a fast non-crypto hash) but a bunch of them, like yours, involve hand-waving the real problem and then insisting you need "security" on a fundamentally insecure basis. If you actually trust that network then you don't need "security on network channel" and if (as is much more likely) you don't or shouldn't trust it then the exercise is hopeless because that network can trivially betray every element of your hoped-for WebCrypto feature set if you don't have a secure origin.

Well, I'm not just hand-waving (at least I don't think I am), I'm actually got burnt by this. I was building a demo of my app on top of libp2p, and then I discovered that I need to issue domain name and certificate for each node in my p2p network.

This wasn't hard – caddy2 makes it super easy. But I see it as a pretty weird requirement. I don't understand, why can't I sign some data with public key without being on secure origin.

> The only reason you can think of is a weird conspiracy? I didn't mean to assume conspiracy theories, I agree that this is a pretty unprobable story. I'm just saying: "It's so weird that my only sound explanation is a weird conspiracy theory", meaning that I don't understand how this came to be, and motivation behind that :)

> why can't I sign some data with public key without being on secure origin.

I'm guessing you mean sign with a private key.

In a secure context the Browser gets to promise the context that this private key stays private if it wants. For example, should the the private key be posted to Twitter?

In a secure context you get to decide, because only code your wrote runs in that context, if you don't add "post private key to Twitter" code then it doesn't happen.

But in insecure contexts any on-path attacker can substitute their own code for yours. Now your "private" key is in a Twitter post, hilarious.

How do you implement your own security on a network channel if the first network request is over http and subject to man in the middle attack?

Does ed25519.sign not work on origins with self signed certs?

If you don't trust the CAs, then getting a certificate from one of them so that https is enabled and crypto works is no worse than no encryption at all, is it?

I understand it might give people a false sense of security, or perhaps they trust the CA system and it's not false in their eyes, but if distrust of CAs is the reason to use plaintext connections instead, I'm not sure that's the best choice.

I think the issue is that your use of the crypto functions is dependent on permission from a CA. Depending on the nature of the application you're serving over HTTPS, a CA could be compelled under DMCA to revoke your certificate, and thus your permission to use the crypto APIs.

I suppose that's a valid point, even if it seems far-fetched that this would be the most effective way of killing someone's software.

I know it's going to be more effort, but is anything physically stopping you from running whatever crypto you like as a wasm module? I'm sure one could do NaCl-over-wasm?

I agree it's not the same convenience as having an API built in though.

There's a great wasm-crypto library out there, and while its authors are doing amazing work, there's much more effort put in WebCrypto by a lot more people.

There's also an option to compile some e.g. Rust library to wasm, and use it, but it could hide some exotic security vulnerabilities that arise only in this narrowly-adopted use case, so it's a pretty high risk.

It’s a neat library but features across languages aren’t exactly the same. Also, documentation could be improved.

I’ve used a single Go module for AES key wrapping (RFC-5649) and I appreciated the native Go code

Not to be confused with Tinc, an open-source, self-routing, mesh networking protocol and software implementation used for compressed and encrypted virtual private networks.

Would anyone happen to know why Tink isn’t listed in PyPi.org?

I don’t see it on npm either. Their docs recommend people use bazel.

When using a library pushes you to use their build toolchain, I start to wonder what their motive is.

Hi, I'm currently working on Tink for JavaScript. (Formerly as part of a rotation on Google's cryptography team; that rotation has ended so I'm now doing this on weekends.)

Tink for JavaScript is being used in production systems internally at Google, but the open source release isn't fully baked yet. npm compatibility is a big part of that; our internal codebase doesn't use npm, but we absolutely want open source users to be able to install and use Tink from npm without installing Bazel (though Bazel will most likely continue to be required in order to contribute to Tink). This is why JavaScript is not currently listed among the production-ready languages. Right now I'm fixing it by migrating the codebase to TypeScript so that it can use the TypeScript Bazel rules, which facilitate compatibility with npm.

The biggest complicating factor here is that Tink, like many Google software projects, internally uses Protocol Buffers to serialize data (primarily keys) in a way that's compatible across all the different languages that it supports. Protocol Buffers work really nicely with Bazel and significantly less nicely with most other build systems. Again, though, Bazel won't be required in order to depend on the package, only to build it from source.

It's coming and will be part of 1.4.0: https://github.com/google/tink/issues/358.

We have a test package for Linux with Python 3.7 or 3.8

pip3 install -i https://test.pypi.org/simple/ tink

They're working on it

Not to be confused with Tink, an open-banking fintech from Stockholm. https://tink.com/

Or tink.de a smart home store. I do not think there are any 4 letter words that do not clash with a company.

How does this compare to libsodium or Bouncy Castle?

Bouncy Castle has an "old style" API where there's lots of switches to twiddle and some combinations produce insecure ciphers. Tink, like libsodium (the two are competitors, though in a friendly way), has a smaller API which exposes basically Mac and AEAD, and no way to accidentally set ECB mode or something like that.

The big difference between Tink and sodium is that the latter uses Bernstein's primitives (chaca, salsa, 25519) whereas Tink, from the slides, goes with AES-GCM.

This comment was great up until:

> The big difference between Tink and sodium is that the latter uses Bernstein's primitives (chaca, salsa, 25519) whereas Tink, from the slides, goes with AES-GCM.

Tink has Bernstein's primitives as well.

Tink does EAX on most platforms, and Chapoly and I think SIV (deterministic, misuse-resistant) on all of them.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact