Cryptography and Your Apps

System frameworks encrypt both data at rest and data in transit in a transparent way for you. This functionality is available by simply setting an attribute. However you may want to do more to protect your users' data. CryptoKit is a new Swift framework that makes it easier and safer than ever to perform cryptographic operations, whether you simply need to compute a hash or are implementing a more advanced authentication protocol.

Related Videos

WWDC 2019

Kidding. Welcome to Cryptography
and Your Apps session.
Today, my colleague, Frederic,
and I are here to show you that
using cryptography on Apple
products has never been easier.

I am Yannick Sierra.
I manage the Cryptographic
Engineering Team at Apple.

So today on one hand we have a
set of great system features
which solve a set of common
security problems.
On the other hand, we have an
exciting new Swift API for
cryptographic operation.
We're really excited about it.
If you here, it's probably
because there's some information
you want to protect, right.
We know that you as developers
and as users find it really
important to protect user's
information, your information.

There are different kind of
information, which are all
sensitive.

It starts with profile
information such as phone
numbers and email addresses.

Your applications may also be
handling user information such
as photos or music by using an
application to process and
improve.
Your application may also be
handling business assets.
This could be paid content your
app is making available to
users.
Or account information like in
the mobile banking scenarios.

For all of this information, it
is critical to keep them secure,
and you need to have great tools
for that.
At Apple, security and privacy
are core values.

We built it in all of the
features that we work on.
Cryptography is a big part of
it.
For example, with device
integrity we use cryptography to
validate the integrity of the
software running on the platform
to make sure it has not been
tampered with and guarantee its
security properties are not
changed.

We use cryptography to protect
data at rest.
We use cryptography across a
wide variety of applications
users love, use extensively for
capturing very personal moments
and sharing them.
This is a case of Messages,
Safari, and iCloud.

With over a billion device, we
operation cryptography at a huge
scale.

The stakes, as you can imagine,
are really high too.
Performance is critical for a
great user experience.
Energy is fundamental for that
full-day battery life, and
security, it's a cornerstone
here.
Now, let's have a closer look at
cryptography.
Cryptography is really a tool.
It provides solution to a set of
basic properties.
It starts with authentication as
an example, knowing who sent you
a message.
Encryption, knowing that that
message only you can decrypt it.

And Integrity, knowing that no
one else could have modified the
content of that message before
it got to you.
To solve broader security
problem, we combine
cryptographic functions into
cryptographic protocol, and
that's no easy task.

Actually, many of you, most of
you have probably heard the
saying, "don't roll your own
crypto", right.
There are good reasons for that.
A lot of things can go wrong.

It starts with maybe not picking
the right primitives and
therefore not getting the
security you want to achieve.
It may also be adding the right
primitives but not using them
the right way, and the lowest
level, the implementation may
give away the secrets or the
keys.
That could be the case of timing
attacks or padding oracle
attacks.
This is why cryptography is
incredibly difficult.

There are endless examples of
failures of cryptographic
protocols in the news, and the
worst thing is, security
vulnerabilities may take a while
to be discovered.

It may take years before someone
reports finding an issue.
This is why the risks are really
high, and so it's an effort to
get it right.
Designing a robust protocol
takes a lot of time, skills, and
expertise you need to be a
cryptographer.

Even when you got the protocol,
the work is not done yet.
There is a continuous amount of
work to monitor new attacks, see
what is applicable to your own
code, and then respond to it,
but sometimes it's not even that
easy.
It can be dependencies.

Those libraries that you picked
to integrate in your app.
And in some situation, you also
need to revise and carry the
protocol and manage all kind of
interpretability scenarios.

All of this is a lot of work,
and it's taking time and energy
away of the big ideas you may
have or the next cool features.
This is why you can truly
benefit from native features.

Our philosophy has been to
provide full solutions for a set
of common problems so that we do
the hard work and you don't have
to.
For you, it raises the risk and
the effort, and we can even
achieve better security through
the assistance of delegated
hardware features we have on our
platforms.
Now, we actually look through a
set of very common scenarios
many of you may be familiar
with.

We're going to start with how to
protect data on a device.
Then we can look at protecting
credentials and keys.
After that, sharing data across
devices and users.

Then, securing network
connections, and finally,
verifying remote parties with
certificates.
Now, I'm going to look into the
first example.

Like I'm sure many of you have
found that scenario and find
yourself trying to protect data
on device.
Well, the best advice is not to
just copy and paste what you
find on some of those websites.
You're better off using data
protection.

Data protection combines the
strengths of the passcode with
the hardware technologies in the
Secure Enclave to make sure the
keys are well secured, and the
encrypted data cannot be used to
brute-force the passcode.
But there's even more.
Data protection provides post
compromise recovery.
Post compromise recovery, also
known as forward secrecy,
guarantees that if adversary
gets his hand on the keys on the
device and the users change the
passcode, well, all the data
encrypted after that cannot be
recovered from those old keys.

This is important, critical, and
if you want to learn more,
there's even more data
protection does, and you can
look at the iOS security white
paper to get more information.

The one thing you need to know
is that there are different
protection attributes you can
set when your app fails.
It starts from until first
authentication.

Even the data is protected until
the first time the user unlocks
the phone after boot.

It's great.
Today is a lot better you can
do.

There is the complete file
protection.
Complete file protection means
the data is only available after
the user unlocks his phone.
As soon as the user locks his
phone back, put it back in the
pocket or in a bag, the data is
secure again.

And it's really easy to use.
Here's an example.
The only thing you need to use
is this option,
completeFileProtection.
It can't be easier than that,
right.
If you're not using this option
yet, please go ahead and look in
your application where you could
use it to get that best level of
security.

Now, in addition to files, there
may be more sensitive
information that you may want to
protect.
There could be credentials like
authentication tokens used to
authenticate on services or
cryptography keys.
But for those, please don't
write them in defaults that you
could see on all the platforms.
Instead, there is Keychain.

Keychain in the Secitem APIs
allows you to write those items
as in the local Keychain, which
means they stay on that one
device or on iCloud Keychain
where they synchronize across
all of the devices for a
seamless experience in the user
account.

This requires user accounts with
two-factor authentication
enabled.

For Keychain, you find very
similar protection as for the
files that I mentioned before
and a few extra ones.
Here, again, I will recommend
you to look at the documentation
to learn more.
In addition to when a key is
cryptographically available,
sometimes important for you to
know how the user authenticated
it and when.

This is why we have
LocalAuthentication.
LocalAuthentication allows you
to put restrictions as to when
an operation can be executed.
For example, you could define
that it is required for the user
to authenticate with biometrics
with Face ID.

It can be very handy, and in
this world, on macOS we have
some exciting news.

On macOS, you're used to device
authentication properties, and
it gives two way for the user to
authenticate, the password or
biometrics for Macs which
support biometrics with Touch
ID.
This year we're really excited
to announce that now without any
chance in your application, the
user can authenticate with Apple
Watch and a double-click on Apple
Watch.
It's a great new experience,
which is going to reduce the use
of the password and reduce the
friction, improves user
experience.

Now, with these new capabilities
we added two new policies.
The first one, to reduce the
authentication to biometrics
only and Watch.
And the second one to the Watch
alone.
We are looking forward to see
how you're going to use those in
your application on macOS.
Now, I mentioned the Keychain,
there is an easy way to
synchronize items across all of
the devices of an account.
What if you have data?
Well, for data we have a great
solution too.
CloudKit. CloudKit allows you to
encrypt assets in the Private
CloudKit Database, and the data
will be available across all of
the devices without the user
having to sign in into the
application.

It is great, and even more, you
can also use it to share to all
the users.

The way it works is Apple as a
trusted party help manage the
iCloud identities and the
control to the data.
And I have an example here
again, to show it's easy to set
up.
From the file, we create an
asset.

With this asset, we created a
record.
And then we upload this record
into the Private CloudKit
Database.
And this is it, and if you want
to add sharing to other users,
it is possible for a set of defined
APIs.

If you haven't looked into
CloudKit before, it's great time
to go have a look at the
documentation and see how
powerful it can be for you.
Now, with this, we talked about
protecting data inside of
devices, share it across
devices, even devices from
another user, what when you want
it done on data from your own
server for example.

Where for that you want to
establish a secure connection.
A secure connection is really,
really important because it
helps guaranteeing the
confidentiality of all of the
information that the user is
accessing through your
application as well as guarantee
the trustworthiness of that
information, make sure it does
not be tampered with.

And the first thing you should
not do here again, you're just
trying to use your custom own
protocol.
There is a great solution.
It's a standard solution.

Transport Layer Security.
And it's really easy to use on
our platforms.

We have two great APIs that make
that really easy.
The first one is network
framework, which you may have
discovered last year with a
great talk at WWDC.

The second one is URL Sessions,
which you may know about as part
of the App Transport Security.

For URL Session, the only thing
you need to do is use an https
endpoint.

In either of those cases, it
relies on our implementation of TLS with
great defaults underneath.

Defaults ensures cypher suites are chosen to
provide strong security
including perfect forward secrecy as
well as the algorithm that would
be the most efficient on Apple
products.

Or implementation of TLS also
use TLS 1.3 by default.
If you're not familiar with TLS
1.3, it has a lot of
improvements from the previous
revisions, a lot better security
and even better efficiency by
reducing some of those round
trips.

If you are not using TLS 1.3,
please go ahead and try to
deploy that on your servers and
without any change of the
Code of your application, you
will have the benefit of it in
your app.
And now, to show you it's really
easy, I have two examples to
show you with Network Framework
and URL Session, but before
jumping into those, I want to
highlight that Secure Transport
is not the recommended way
anymore, and we ask you to
migrate to Network Framework and
URL Sessions if you're already
using Secure Transport.

With that, here's a couple of
examples.
With Network Framework, when you
establish a connection, the only
thing you need to do is using
:.tls, and here we go, you add
that TLS connection, providing
great security and performance.
For URL Session, the only thing
here, it's https endpoint, and
this is it.
In some situation, you may not
have the possibility to use TLS.
For example, if you have trying
to secure data through a content
delivery network, for example.
In this case, you manage those
certificates, and for
certificates, one of the things
to avoid is using it on parser
or trying to take a parser you
find somewhere on a website.
Parsers are incredibly
vulnerable by providing a great
attack exposure.
They're critical.
On a platform, we have SecTrust
for that.
SecTrust provides you an easy
way to validate the certificate
against a trust policy.
The trust policy may contain
information about expiration,
revocation, and until
certificate has been validated,
you know that you can use a key.

Note that if using TLS you don't
have a need to worry about
certificate.

It's all handled for you
underneath.
Now, in this release, we're
happy to introduce a new
function in SecTrust.
This new function combines two
things you were able to do
before.
On one hand, it's a function,
which allows to asynchronously
through an explicit action, do a
certificate validation so that
your application can do
something else while the
certificate is being validated.

But also this function gives you
a richer handling.
So, as a developer, you know
what is going on in case of
failure, and you can debug it.
But also, you can build logic
into your application to respond
to different error scenarios.
So this new function is going to
make things even more convenient
and easier for you to debug.
We're looking forward to you
adopting it.
So, with this, I just walked you
through a set of five different
scenarios for which we have
really easy to use solutions,
which provide great security by
defaults or you're only a few
attributes away from great
security.

And here again, we benefit from
deep integration with the
hardware to provide security
features which otherwise are
very challenging to provide.
So, in any of the scenarios,
when you encounter them, go
ahead and use the system
frameworks, and if you already
do, go ahead and make sure
you're using those best
attributes so that you can
protect users and business
assets the best possible way.
And we understand that in some
situations it may not be
practical for you to use the
system features.

For example, you may need to
have interoperability outside of
the Apple ecosystem.

You may to authenticate with
your service or simply you're
given a specification you will
need to implement.
For all of these cases, we now
have a great solution for you.

Apple CryptoKit.
Apple CryptoKit is new Swift
cryptographic API which has been
designed to follow the same
philosophy as for those features
we talked about and give you an
easy access to cryptographic
functions and hard to misuse
functions.

We're really excited to give
that in this release.
And now, I'm going to hand over
to Frederic who is going to tell
you all about this exciting new
API.

So please join me in welcoming
Frederic on stage.
Thanks Yannick.
Hello everyone.
My name is Frederic Jacobs, and
I'm working on the Cryptographic
Engineering Team here at Apple.
I'm excited to tell you more
today about Apple CryptoKit.
We think you're really going to
like implementing cryptographic
protocols in Swift.
There are four aspects of Apple
CryptoKit I would like to share
with you this afternoon.
First, we are going to talk
about CryptoKit and Swift.

Second, we will talk about the
curated set of algorithms that
is available in CryptoKit.

Third, we are going to discuss
about the Secure Enclave and
biometric authentication, and
finally, we'll talk about
performance.
Let's dive right in.

In the past, you might have had
to write code that looks like
this when you were calling into
C crypto API from Swift.
You had to allocate buffers,
figure out for each of the
buffers what size it had to be,
and there were values such as
the nonce that you might have to
search what the safe value for
that value was.
And then you have all of these
nested calls into the encryption
function where you're passing
pointers, and there are no
argument labels that help you
figure out which pointer needs
to go into which argument.

In contrast, with Apple
CryptoKit, you can do exactly
the same operation with a single
line of code.
In this-- isn't this cool?
So, in order to do so, you're
passing the data you want to
encrypt to cipher.

In this case we're using
AES.GCM, and you're using the
key you want to encrypt the data
with and that's it.
Something else you might have
had to do is generating your own
cryptographic key when you were
calling into a C crypto API from
Swift.

And that involved first
converting a number of bits and
bytes because cryptographic keys
are commonly expressed in bits.
Then you have to allocate a
buffer for that amount of bytes
and use the system, random
number generator to fill that
buffer with cryptographically
secure random numbers.
Then, if an error occurred you
had to handle that.

You're then finally ready to use
that key, and when you're done
with that key, you don't have to
forget to zeroize it to remove
it from memory.
In contrast the CryptoKit,
generating a key is just a
single line of code.
You call the SymmetricKey
initializer, and you pass the
number of bits you want the key
to hold.

We're able to zeroize this key
on release for you because
knowing about the auto reference
counting of this value whenever
it is getting deallocated, we're
zeroizing that buffer for you.

So, CryptoKit and Swift.
We have a strongly typed API,
and whenever you're initializing
a value, we are verifying that
the data you're passing is a
strong value for that argument.

Thanks to Swift's memory
management model, we're able to
zeroize on release all of the
secret values allocated within
CryptoKit.
We perform equitable
conformances for values like
message authentication code if
you're familiar with that
content so that you're able to
verify two-message
authentication codes in constant
time by just using the equals
equals operator.
CryptoKit also defines protocols
so that you can write generic
code over a hash function H, and
if in multiple places of your
code base you have to pass
different hash functions, you
can write the code once and then
parametrize the function call on
a different hash function.
So, we talked about CryptoKit
and Swift, and now I want to
dive into the curated set of
algorithms that is supported in
CryptoKit.
All algorithms are standard and
peer-reviewed algorithms.

Let's see what's available in
CryptoKit.
We have support for hash
functions, message
authentication codes,
authenticated encryption, key
agreement, and signatures.
Some of these algorithms are
algorithms we have supported
before in frameworks such as
Common Crypto or SecKey, but
some of these algorithms are
algorithms we're supporting for
the first time.
Those are highlighted in green
on the slide.
Note that we also have an
insecure module.

This module provides algorithms
such as MD5 and SHA1 so that you
can adopt CryptoKit even if you
need to be using some algorithms
that no longer meet the best
security standards.

Let's focus on a few examples to
see how CryptoKit works.
Let's start with hash functions.

Hash functions produced
deterministic fixed-size output
that is called a digest, and
unlike hashable in Swift, hash
functions in CryptoKit provide
cryptographic properties such as
collision resistance.
This means that it is hard to
find two inputs that will hash
to the same digest.
In order to compute the hash, it
is as easy as calling the hash
method on the hash function you
want to use, passing the data
you want to hash.

Here, I have some audio data I
want to hash, and I use the
SHA256 hash function to compute
a digest.
If you're streaming a file, you
might be reading it from an
input stream.
In that case, you want to
compute the digest
incrementally.
You start by initializing a
hasher by calling the MT
initializer on the hash
function.
You then pass the data you want
to hash, and you call the update
method one or multiple times in
order to do so.

And when you want the digest to
be computed, you just call the
finalize method on the hash for
instance, and that will return
the digest.
Next, let's talk about
authenticated encryption.
This is something you've long
been asking for.

As its name suggests, it
provides both authentication and
encryption.

The lack of authentication in
cryptographic protocols can lead
to a variety of attacks, and
manually combining
authentication with encryption
can lead to things like padding
oracle attacks.
So, instead we're really happy
to provide it to you as a single
API call.
I'm working on the site project.
It's a hiking app.

Most of the content on the app
is free, but there's additional
content you can purchase through
the in-app purchase.
Once you purchase the content,
you can retrieve the additional
content.
I'm using a content delivery
network in order to keep the
downloads fast, as my user base
grows.
In order to obtain the content,
I first check with my server if
the in-app purchase is valid.
Then, the key is retrieved from
the server and passed on the
phone.
I download the encrypted data
from the content delivery
network, and I use the key in
order to decrypt the encrypted
content.
And if the key is right, and the
data wasn't tampered with on the
content delivery network, I'm
able to retrieve the map data.
Let's see how this translates to
code.
First, we start by initializing
a SymmetricKey from the key data
that was retrieved from the
server.
Then we are initializing a
sealed box.
In this case, it doesn't really
matter what's in the sealed box,
but know that if you're working
on implementing a specification
that requires you to combine the
nonce, the cipher text and the
tag in a specific way, you can
use the sealed box to do that.

If you're implementing a
protocol that requires you to
pass specific nonce values we're
also able to support that.
But, in this example, we'll
focus on the simple case.

So, we're passing the downloaded
data as a combined
representation to the sealed
box, and now that we have a box,
we can simply open it by calling
the open method on the cipher.

And we're passing the key.
It's that easy.
Next, let's talk about
signatures.
Signatures are used to
authenticate data using a
private key, and using the
signature, we are able to verify
data using the associated public
key.
Let's take an example where we
want to use the signature in
order to authorize and
operation.
The operation here can be a
two-factor log-in or some
sensitive transaction such as
wiring money to another user of
the application.
In order to do so, we start by
generating a private key on the
device.
We then retrieve the associated
public key.

The associated public key is
registered with your service,
and once we want to perform that
operation, we're using the
private key to generate the
signature on the transaction
data and then sending over the
transaction data and the
signature to the server.

The server will verify that the
signature is correct, and if the
signature is right, it will
proceed to doing the operation.
Let's see what this code looks
like.

In order to generate a
cryptographically strong private
key, we call the PrivateKey
initializer.
Then we want to register some
public key data on the server.

We start by retrieving the
public key by just calling
public key on the private key,
and then we want to say what
representation we want to get
from the public key.

Multiple representations of
public keys exist, and we have
support in CryptoKit for a lot
of them.
In this case, we're taking the
compact representation.

As always, we're storing the
private key in the Keychain.
Sample code in order to do that
will be available on the
developer portal.
In order to produce the
signature, we are calling the
signature method on the private
key, and we're passing the
transaction data we wish to
sign, and this returns the
signature.

Now, this key that protects
these operations is of high
value, so we want to give it the
best security it can.
That's where the Secure Enclave
comes in.

The Secure Enclave is s
hardware-based key manager
that's isolated from the main
processor to provide an extra
layer of security.
It is used as part of critical
system features, such as Touch
ID or Face ID.
Let's see how to improve on or
code that uses signatures to
take advantage of the Secure
Enclave.

We start by checking if a Secure
Enclave is available on the
device.

We do so by calling isAvailable
on SecureEnclave.
And from there, we can use
exactly the same code as before
in order to produce, to generate
the key and produce the
signature within the Secure
Enclave.
Note that in order to do so, we
simply prefix or call to the
PrivateKey initializer call that
generates the key, and we prefix
it with Secure Enclave dot.
It's that easy to take advantage
of the Secure Enclave.

An advantage of using the Secure
Enclave is that you can
constrain key usage.

In this case, we want to say
that the key that we're
generating on the Secure Enclave
is only accessible when the
device is unlocked and that this
key will be available on this
device only.
We can further constrain key
usage by saying that when we're
performing an operation with the
private key, we want to require
user presence.

Requiring user presence means
that the user will either be
prompted for biometric
authentication or they will be
requested for their device
password.

Now that we have composed an
access control policy, we are
simply passing it to the
initializer of the key we're
generating, and that policy will
be enforced.

You might want to give some
additional context to your users
about why they're required to
authenticate.
In order to do so, you can pass
a LocalAuthentication context.

In this case, we say that we
want the LocalAuthentication
context to be valid for ten
seconds, so the user will not be
required to reauthenticate
during that amount of time, and
we want to tell the user that
they're required to authenticate
because they're authorizing a
$10 transfer to Bob.
In order to use that
authentication context, you
simply pass it to the key's
initializer.
Finally, let's talk about
performance.
CryptoKit is built on top of
corecrypto.

Corecrypto is Apple's native
cryptographic library that
features all of the system
frameworks that Yannick has
described before.
With the help of the team that
brought you the Accelerate
framework and the CPU design
team, corecrypto has hand-tuned
assembly code, squeezing every
cycle out of each of the support
micro architectures.

In addition to that, because it
uses corecrypto, it takes
advantage of security
mitigations in corecrypto such
as side-channel resistance, and
because corecrypto is FIPS
validated, that means that you
can use CryptoKit in the FIPS
compliant way.

Yannick opened with this slide
showing large categories of bug
classes that are available in
cryptographic protocols and
implementations.
With CryptoKit, we are starting
to eliminate some of these bug
classes, but CryptoKit remains a
low-level crypto API that's
powerful to let you implement a
wide range of protocols, even
broken ones.

Not all cryptographic weaknesses
can be addressed at the level of
the cryptographic library.

Therefore, we strongly recommend
you to rely on higher level
system frameworks when you can.

This is only the beginning, and
we want to continue helping you
ship the safest apps as possible
by delivering on APIs that help
you prevent secure legal
vulnerabilities in your
applications.
We can't wait for you to start
adopting CryptoKit in your apps.

On the page of this session,
you'll find a link to the
CryptoKit documentation, and it
comes with Xcode Playground.
Download it, play with it for an
hour, and see what's available.

See how you could take advantage
of CryptoKit in your apps.
We will be at the labs tomorrow
to answer any of your questions,
and we're looking forward to
your feedback.

Thank you.

Looking for something specific? Enter a topic above and jump straight to the good stuff.