Cryptography for newcomers

The hitchhiker's guide to cipher in devs

Users do not know how to protect themselves

Any sensitive data must
be transferred and stored
in an encrypted form

We Need Cryptography!

Cryptography is a matter of:

  • Hash
  • Encryption
  • Key Exchange
  • Signature

Crypto, History, and main flaws

Crypto is as old as war

is as old as Encryption!

Flaw #1: Too Simple Key

Shift Cipher Wheel


  • Long-length keys
  • Make them hard to forge

Flaw #2: Repetitions

Vigenère Cipher

Plain text:  ATTACK AT DAWN
Cipher key:  LEMONL EM ONLE
Cipher text: LXFOPV EF RNHR


  • Avoid Common Denominator
  • Use Unique Keys

Flaw #3: Brute Force Attack

Enigma, virtually unbreakable

No pattern is strong enough to resist to an endless attack

Hashing, Salting, Cooking

Hashing is
Data Obfuscation


Simple Rainbow Table - Wikimedia


  • Entropy
  • Avoid repetitions
  • Must be unique and random
from base64 import b64encode
import secrets
import argon2
import hmac
from haslib import sha256

salt = secrets.token_bytes(64)
hash = argon2.low_level.hash_secret_raw('b'*password, salt,
    time_cost=1, memory_cost=8, parallelism=1, hash_len=8,

record = "$argon2$t=1,m=8,p=1$%s%s" % (b64encode(salt), b64encode(hash))
ph = argon2.PasswordHasher()
record = ph.hash(password)
digest =, 'b'*record, digestmod=sha256).digest()

A properly hashed password with
no repetition and a time-controlled execution
decrease the risk of brute-force hacking

Key-based encryption

How Encryption Works?

  • Based on Maths
  • Use a Key as input
  • Compute Substitutions
  • Rely on Randomness

Block Ciphers

  • DES (Data Encryption Standard)
  • AES (Advanced Encryption Standard)
  • IDEA
  • BlowFish

Block modes of operation

  • ECB (Electronic Code Book)
  • CBC (Cipher Block Chaining)
  • AEAD (Authenticated Encryption with Associated Data)
    (OCB, EAX, …)

Computers aren’t
truly random!

Padding, Randomness, IV

  • Unpredictible, non-deterministic values
  • CSPRNG functions
    rather than direct /dev/urandom access
  • IV (Initialization Vector)
    blocks used to init a cipher function and put it in a unique state

Stream Ciphers

  • RC4
  • ChaCha20 ?
  • Panama ?

Dealing with Keys

Symmetric Keys

  • Same key used for all tasks
  • Fast
  • Suitable for huge amount off data

A symmetric key
must be shared,
which means it could leak

Diffie-Hellman Key Exchange

Asymmetric Keys

  • One private key
  • One (or more) public key(s)
  • “Public” is used for encryption
  • Very strong and very slow

RSA or Eliptic Curves?


  • Prime Number Factors
  • Widely deployed
  • Very Fast on encryption and Signature
  • Easy to implement / understand
  • Very slow in decryption


  • Eliptic Curves Discrete Logarithm
  • Small keys, ciphertexts, signatures
  • Fast
  • Complicated to implement
  • The strongest, the slowest

→ Better rely on ECC when available

Key Wrapping

import secrets
from struct import pack
from Crypto.Cipher import Blowfish
from Crypto.PublicKey import RSA

iv = secrets.randbits(Blowfish.block_size)
plen = Blowfish.block_size - divmod(len(msg), Blowfish.block_size)[1]
padding = [plen]*plen

token = secrets.token_bytes(32)
cipher =, Blowfish.MODE_CBC, iv)

key = RSA.importKey(recipient_key)
encToken = key.public_key.encrypt(token, 32)

wrap = pack(b'---', encToken, iv + cipher.encrypt(msg + pack('b'*plen, *padding)))


  • Reversed Asymmetric Cipher
  • For trusting purposes only
x.509 Certificates

Use it day to day


  • Network SSL/TLS, chain of trust
  • Passwords → Hashing functions
  • Data → Asymmetric Cipher w/ Key Wrapping, HSM

Low-level languages

  • OS modules
  • Librairies (OpenSSL)
  • Hardware (AES-NI, Co-processor)


  • Python: Cryptography / PyCrypto
  • Ruby: RbNaCl
  • Node.js: Crypto built-in module
  • PHP: Mcrypt
  • Java: JCE Framework
  • etc.

Multi-platform libraries

  • Low-level for fast perfomances
  • Agnostic
  • Portable
  • Available using bindings

Encrypt before sending to the client

import nacl
from nacl.public import PrivateKey, Box
import User

def get_secret(username, nonce):
    skfile = open("sk_server.key", "r")
    skserver = PrivateKey(skfile, nacl.encoding.RawEncoder)

    user = User.query.filter_by(username=username).first()

    box = Box(skserver,

    message = b"Never Gonna Give You Up!"
    encrypted = box.encrypt(message, nonce)

    return encrypted


  • WebCrypto
  • Browser libs
  • iOS: CryptoKit
  • Libsodium!

Decrypt a blob from the server

const _sodium = require('libsodium-wrapper')

(async () => {
  await _sodium.ready
  const sodium = _sodium

  const nonce = sodium.randombytes_buf(sodium.crypto_secretbox_NONCEBYTES)

  await res = fetch(`/secret/${}/${sodium.to_string(nonce)}`)
  const encrypted = res.text()

  const decrypted = sodium.crypto_box_open_easy(encrypted, nonce, SERVER_PK,
  const message = sodium.to_string(decrypted)
  // Never Gonna Give You Up!

Auth High-level API

A public-key cryptography based API that allow
passwordless authentication on platforms

WebAuthn: register

@app.route('/webauthn_begin_activate', methods=['POST'])
def webauthn_begin_activate():
    # ...
    rp_name = 'localhost'
    challenge = util.generate_challenge(32)

    make_credential_options = webauthn.WebAuthnMakeCredentialOptions(
        challenge, rp_name, RP_ID, ukey, username, display_name,

    return jsonify(make_credential_options.registration_dict)

WebAuthn: challenge

@app.route('/webauthn_begin_assertion', methods=['POST'])
def webauthn_begin_assertion():
    webauthn_user = webauthn.WebAuthnUser(
        user.ukey, user.username, user.display_name, user.icon_url,
        user.credential_id, user.pub_key, user.sign_count, user.rp_id)

    webauthn_assertion_options = webauthn.WebAuthnAssertionOptions(
        webauthn_user, challenge)

    return jsonify(webauthn_assertion_options.assertion_dict)

WebAuthn: login

@app.route('/verify_assertion', methods=['POST'])
def verify_assertion():
    # ...
    webauthn_user = webauthn.WebAuthnUser(
        user.ukey, user.username, user.display_name, user.icon_url,
        user.credential_id, user.pub_key, user.sign_count, user.rp_id)

    webauthn_assertion_response = webauthn.WebAuthnAssertionResponse(
        webauthn_user, assertion_response, challenge,
        ORIGIN, uv_required=False)  # User Verification

        sign_count = webauthn_assertion_response.verify()
    except Exception as e:
        return jsonify({'fail': 'Assertion failed. Error: {}'.format(e)})

Think Cryptographically 😎

Never be a Sorcerers Apprentice

Never forget that

  1. Security has an inverse relation to the ease of use
  2. Security has a cost
m4dz's avatar

Paranoïd Web Dino · Tech Evangelist

alwaysdata logo



m4dz, CC BY-SA 4.0

Interleaf images

Courtesy of Unsplash and Pexels contributors


  • Layout icons are from Entypo+
  • Content icons are from FontAwesome


  • Cover Title: Sinzano
  • Titles: Argentoratum
  • Body: Mohave
  • Code: Fira Code


Powered by Reveal.js

Source code available at