© Daniel van Flymen 2020
D. van FlymenLearn Blockchain by Building Onehttps://doi.org/10.1007/978-1-4842-5171-3_6

6. Cryptography 101

Daniel van Flymen1 
(1)
New York, NY, USA
 

The study of the algorithms presented in this chapter are well beyond the scope of any book you can find or course you can take. They require years of understanding and treatment and build upon algebraic concepts familiar to specific fields of mathematics. But luckily theoretical insight into how cryptographic algorithms work isn’t a requirement for using these tools in practice, so long as you understand their purpose and implications. In other words, a working knowledge of how to use cryptographic libraries is what’s important here.

If you’re like me (not a cryptographer), the correct approach to this material is that of caution. I understand just enough cryptography to know that it’s a lifelong balance—a study of trade-offs between security, convenience, and speed—with shifting attack vectors as technology improves. As somebody learning this stuff for the first time, you should err on the side of battle-tested, well-known best practices and tools. There’s far too much at stake in our digital world to take shortcuts—the majority of breaches and attacks on the Internet are caused by simple mistakes: using bad implementations of things not quite understood or, even worse, personal stamps of approval. There’s an adage in the cryptography world: never roll your own brand of cryptography.

Cryptography is the crypto in cryptocurrency. And real cryptographers can get annoyed at the usage of the word crypto to mean cryptocurrency. Signing a check in real life is very similar to signing a blockchain transaction—but it’s even more secure, because the signature cannot be forged. In fact, it changes depending on the document you’re signing!

Sending messages with integrity

Before we dive into digital signatures and public key cryptography, I want to draw on your knowledge of hashing by showing you how they can be used to send unforgeable messages over an insecure medium, like the Internet.

Note

Note that this example is just a toy example and there are well-built libraries for doing this. In fact, the hmac library which ships with Python is built for just this purpose.

Let’s say that Alice wants to send a message to Bob. And let’s also say that Alice and Bob agree to share a secret password p@55w0rd with each other before the messages are sent.

Alice creates a message and concatenates it with p@55w0rd; then she computes a hash of the message:
from hashlib import sha256
message = "Hello Bob, Let's meet at the Kruger National Park on 2020-12-12 at 1pm."
hash_message = sha256(("p@55w0rd" + message).encode()).hexdigest()
The computed hash is 39aae6ffdb3c0ac1c1cc0f50bf08871a729052cf1133c4c9b44a5bab8fb66211. Alice then sends this message, including the hash to Bob, who will now verify that only Alice could’ve sent it:
from hashlib import sha256
alices_message = "Hello Bob, Let's meet at the Kruger National Park on 2020-12-12 at 1pm."
alices_hash = "39aae6ffdb3c0ac1c1cc0f50bf08871a729052cf1133c4c9b44a5bab8fb66211"
hash_message = sha256(("p@55w0rd" + alices_message).encode()).hexdigest()
if hash_message == alices_hash:
    print("Message has not been tampered with")

This is a trivial example of a digital signature to give you a taste of how they work. We’ll soon see that the libraries responsible for verifying and signing the messages are more robust and don’t require the use of a pre-shared key.

Symmetric cryptography

Symmetric cryptography is the oldest form of cryptography. It involves sharing a key (cipher) with the person you want to communicate with.

For example, let’s say you want to share your car with your brother. You make a copy of the key and give the key to him. Now, only you and your brother are able start the car. But while you’re on holiday, your brother calls to tell you that the key has been lost, and somebody may have stolen it.

This example illustrates some of the problems with symmetric cryptography—the primary problem being your placement of trust in the counter-party, and the overhead and maintenance of the list of authorized people who may drive your car. Also, you may not know when a particular key has been compromised. Let’s look at a classic example of symmetric cryptography.

Caesar’s Cipher

In Rome, circa 50 BC, Julius Caesar used a method of encryption for his personal correspondence. It’s a simple method of symmetric encryption that works by shifting the characters in a message by a fixed amount.
../images/475256_1_En_6_Chapter/475256_1_En_6_Fig1_HTML.jpg
Figure 6-1

A Caesar Cipher

Ahead of time, Caesar would give the recipient the cipher (key) of say 3. And a D would become an A in the encrypted message. The recipient would apply the reverse and an A would become a D.

The problem here is that the act of sending the cipher is insecure—any form of communication can be spied on and the key ascertained. We need a form of encryption free from the act of creating and sending shared keys. This is why public key cryptography was invented and solves the problem of shared trust.

Public key cryptography

Public key cryptography is an example of asymmetric cryptography. It’s the type of cryptography that secures almost all modern systems on the Internet. We’re going to look at it from a simple level so that you get a gist of how and why it works, and then we’ll get more technical and granular with some examples mixed in.

Public key cryptography involves not one but two (or more) key pairs, one of which is kept secret. There are many different public key cryptography algorithms, but we’ll be using the popular RSA (Rivest, Shamir, Adleman—the creators) algorithm (in the case of Bitcoin, the ECDSA (Elliptic Curve Digital Signature Algorithm) is used instead). These algorithms are complicated mathematical gems beyond the scope of this book, and they ship in a variety of flavors prized for certain properties: some are thought to be quantum computing-resistant; others are chosen for their speed or ease. But the output of any of these algorithms is the same: a correlated pair of keys, A and B, that you can use for the purposes of encrypting a message to be sent over an insecure channel.

Note the word correlated—the keys A and B are linked in a mathematical way. A must be kept secret, known only to you. But B is your public key—you can publicize it on the Internet, and someone can use it to encrypt a message that only you can decrypt (using A). You can effectively send your B to anyone wishing to communicate with you in a secure manner, but you should guard A like Frodo did the Ring. We use public key cryptography all the time—mostly without realizing it—when you access a website over https, you’re using the website’s B to encrypt your outgoing data so that only the website may read it.

Additionally—and this is really important—you can use your private key A to sign a message, and B (known to the public) can verify the signature. This is how transactions on a blockchain are validated. But more on that later. Let’s first look at some examples to get this sticking.

An Example in Python

Here’s a fantastic analogy from the excellent open source Python NaCL library:

Imagine Alice wants something valuable shipped to her. Because it’s valuable, she wants to make sure it arrives securely (i.e., hasn’t been opened or tampered with) and that it’s not a forgery (i.e., it’s actually from the sender she’s expecting it to be from and nobody’s pulling the old switcheroo).

One way she can do this is by providing the sender (let’s call him Bob) with a high- security box of her choosing. She provides Bob with this box, and something else: a padlock, but a padlock without a key. Alice is keeping that key all to herself. Bob can put items in the box then put the padlock onto it. But once the padlock snaps shut, the box cannot be opened by anyone who doesn’t have Alice’s private key.

Here’s the twist though: Bob also puts a padlock onto the box. This padlock uses a key Bob has published to the world, such that if you have one of Bob’s keys, you know a box came from him because Bob’s keys will open Bob’s padlocks (let’s imagine a world where padlocks cannot be forged even if you know the key). Bob then sends the box to Alice.

In order for Alice to open the box, she needs two keys: her private key that opens her own padlock and Bob’s well-known key. If Bob’s key doesn’t open the second padlock, then Alice knows that this is not the box she was expecting from Bob, it’s a forgery.

This bidirectional guarantee around identity is known as mutual authentication.

We’re going to be using PyNaCl to walk through an example of the preceding analogy in Python. First things first, let’s install PyNaCl:

Note

By the way, PyNaCl is a great example of a well-tested library to use in your own projects. Most importantly—for a cryptographic library—it has great documentation littered with examples. You can read more about it here: https://pynacl.readthedocs.io/en/stable/public/

poetry add pynacl
Then let’s activate our virtual environment and spawn a Python interpreter:
poetry shell
ipython

We’re going to use the given analogy to drive the concepts home. Bob and Alice will both generate their own public-private key pairs, and Bob will encrypt a message to Alice, for her to decrypt. PyNaCl supplies us with a very useful Box class which mimics the preceding analogy.

Let’s go:
from nacl.public import PrivateKey, Box
# Generate secret keys for Alice and Bob
alices_private_key = PrivateKey.generate()
bobs_private_key = PrivateKey.generate()
# Public keys are generated from the private keys
alices_public_key = alices_private_key.public_key
bobs_public_key = bobs_private_key.public_key
# Bob will send Alice a message...
# So he makes a Box with his private key and Alice's public key
bobs_box = Box(bobs_private_key, alices_public_key)
# We encrypt Bob's secret message (bytes)...
encrypted = bobs_box.encrypt(b"I am Satoshi")
# Alice creates a second box with her private key and Bob's public key so that she can decrypt the message
alices_box = Box(alices_private_key, bobs_public_key)
# Now Alice can decrypt the message:
plaintext = alices_box.decrypt(encrypted)
print(plaintext.decode('utf-8'))
I am Satoshi

PyNaCl will raise an exception if the message was tampered with or couldn’t be decrypted.

Digital signatures

Digital signatures exist for many of the same reasons you may sign something in real life: they leave the recipient no room to doubt the authenticity of the document. They satisfy three useful claims:
  1. 1.

    Authenticity: “This could’ve only been signed by Daniel.”

     
  2. 2.

    Integrity: “This data wasn’t forged or tampered with.”

     
  3. 3.

    Non-repudiation: “Daniel can’t deny having sent the data.”

     

Digital signatures make use of public key cryptography to satisfy these claims. Much like in our example, where Alice creates a “box” with Bob’s public key, we use Bob’s public key to verify that only Bob could’ve sent and signed a piece of data. The idea is simple: anyone with my public key can quickly verify that I did indeed sign a message.

Here’s a diagram of the given idea.
../images/475256_1_En_6_Chapter/475256_1_En_6_Fig2_HTML.jpg
Figure 6-2

Digitally signing a document

  1. 1.

    First, our unencrypted, plaintext data is hashed (prevents tampering).

     
  2. 2.

    Then the hash is encrypted using the private key.

     
  3. 3.

    Then we attach (concatenate) the encrypted hash to the data.

     
Let’s see what this looks like in Python. First, from Bob’s perspective, we’ll create a key pair; then sign a message with it. After, we’ll see how anyone can use that public key to verify the message.
 1  import nacl.encoding
 2  import nacl.signing
 3
 4  # Generate a new key-pair for Bob
 5  bobs_private_key = nacl.signing.SigningKey.generate()
 6  bobs_public_key = bobs_private_key.verify_key
 7
 8  # Since it's bytes, we'll need to serialize the key to a readable format before publishing it:
 9  bobs_public_key_hex = bobs_public_key.encode(encoder=nacl.encoding.HexEncoder)
10
11  # Now, let's sign a message with it
12  signed = bobs_private_key.sign(b"Send $37 to Alice")
The public key (in hex) generated on line 10 was
e7ff10ede8a691b982516059a0627d369504e3633e0297e28ec5fc71994577d3
Firstly, let’s see what the signed message looks like on line 12. As you can see, the message is not encrypted! But it is padded with bytes containing the signature:
b'x9fqx02xe1oxb8y2xc7xe7@9$xc4[xb2xa4xe1+97.> xcaGGx8a
Yx86xc3xfexb9W{xc4x9cx87x00(x1dxe9}jxe4xedxd2x0bxcbx88x87Jxecyx04GQ
Hxeaxccxc2xe7x03Send $37 to Alice'

Verification

The verification process uses the signer’s public key to check the signature.
../images/475256_1_En_6_Chapter/475256_1_En_6_Fig3_HTML.jpg
Figure 6-3

Verifying a digital signature

Let’s see how we can use the public key to verify that the message was signed by Bob:
 1  import nacl.encoding
 2  import nacl.signing
 3
 4
 5  # From the above example...
 6  bobs_public_key = b'e7ff10ede8a691b982516059a0627d369504e3633e0297e28ec5fc71994577d3'
 7
 8  # We generate the verify_key
 9  verify_key = nacl.signing.VerifyKey(bobs_public_key, encoder=nacl.encoding.HexEncoder)
10
11  signed_message = b'x9fqx02xe1oxb8y2xc7xe7@9$xc4[xb2xa4xe1+97.> xca GGx8a Yx86xc3xfexb9W{xc4x9cx87x00(x1dxe9}jxe4xedxd2x0bxcbx88x87 Jxecyx04GQHxeaxccxc2xe7x03Send $37 to Alice'
12
13  # Now we attempt to verify the message
14  # Any invalidation will result in an Exception being thrown
15  verify_key.verify(signed_message)
Note

Does the preceding example make sense? It’s good to take a pause and play around in the Python interpreter until you get the gist of using NaCl. It’s going to become important as we go through the next chapter on transactions.

Wallets on the Blockchain

Unlike Bitcoin, Ethereum is an account-based model—meaning each “user” on the Blockchain would have an account. Bitcoin doesn’t have the notion of an account; instead, it’s a system that closely resembles the way cash flows in and out of a physical wallet. The Bitcoin system is called UTXO (Unspent Transaction Outputs), and it’s an elegant data structure for modeling transactions. We’ll talk about UTXOs in the next chapter, but for now let’s focus on the account-based model of Ethereum.

When you initially interact with Ethereum, the first thing you usually do is generate a key pair. Your Ethereum address is just your public key. Your private key is stored somewhere safe, either in some sort of software or on a hardware wallet. For someone to send you money over the Ethereum blockchain, they just need to know your public key. But only you can access that money because only you hold the private key.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.174.168