For this lab, you will be using basic cryptographic functions provided by the Sodium crypto library (libsodium), which is a portable fork of NaCl, the "Not Another Crypto Library" developed by Daniel J. Bernstein (DJB).  Libsodium has API bindings for common programming languages beyond C/C++.  You can implement the lab in any language you desire, although Python is the suggested language if you want instructor assistance.


Python 3 setup instructions using PyNaCl wrapper library:

$ sudo apt-get install python3-pip
$ sudo apt-get install python3
$ pip3 install --upgrade pip
$ pip3 install pynacl
#  sudo pip3 install --upgrade pynacl   # To upgrade PyNaCl later

C/C++ setup instructions using native Libsodium:

$ sudo apt-get install build-essential
$ wget https://download.libsodium.org/libsodium/releases/LATEST.tar.gz
$ tar -xzf LATEST.tar.gz
$ cd libsodium-stable
$ ./configure
$ make && make check
# Should see following printed after test suite runs:  PASS:  70
$ sudo make install

Other languages

# If you use another language, record your setup instructions and tell me!

Part 1 - One-Time Pad

Professor Shafer wishes to send a message to the class using a one-time pad because it has the property of perfect secrecy.

Two files are provided:

  1. The encrypted message (originally ASCII text) - part1.ciphertext.bin
  2. The one-time pad, cryptographically random - part1.otp.bin


  • Write a Python3 program named part1.py that reverses the one-time pad and prints the plaintext message to the screen.

Part 2 - Symmetric Key Cryptography

Professor Shafer finds a one-time pad is too cumbersome of a secret to manage and distribute. Instead, he wishes to send a message to the class using symmetric key encryption.  He uses the Salsa20 stream cipher with Poly1305 message authentication code provided by the Libsodium library.

Two files are provided:

  1. The encrypted message (originally ASCII text) - part2.ciphertext.bin
  2. The symmetric key, cryptographically random - part2.key.bin


  • Write a Python3 program named part2.py that decrypts and prints the plaintext message to the screen.

Part 3 - Public Key Cryptography

Professor Shafer doesn't like having to distribute a secret symmetric key to the students to allow them to receive his messages. Instead, he wishes to send a message to the class using public key encryption and only distribute public keys, while keeping his secret key secret. He will use Curve25519 high-speed elliptic curve cryptography to accomplish this.

Your program must transmit to the cyberlab.pacific.edu:12001 server the following payload in a “HTTP-like" format as an ASCII string:

Name: Your Name\r\n
PublicKey: <Base16 string of your public key>\r\n

After transmitting a packet to the server, your program must also receive a TCP reply from the server with the following payload:

Name:  Jeff Shafer\r\n
PublicKey: <Base16 string of Shafer's public key>\r\n
Ciphertext:  <Base16 string of ciphertext>\r\n


  • Write a Python 3 program named part3.py that communicates with the server, receives the ciphertext, and prints the plaintext message to the screen.
Tip: Does the server "respond" with a message of length 0?  That means that you sent an invalid request.  Upon receiving an invalid request, the server closes the socket immediately, which you will notice as recv() returning with a byte array of length 0.
Tip: Example Request and Reply:
Name: Any Student
PublicKey: A52F3EADF37ED99F29A5F17F7C1491DE0A1C1DCFA840ABBF2BB9D5489A0D1D4D

Name: Jeff Shafer
PublicKey: 2C9EC205E93A2506EF257B8220A77D754BDCD26BE5918BF9E05D23314894E14A
Ciphertext: DF6976FB64F189BEE7357D3E2740F80E520589EBB134765D1906CD274051E203AFBADD903CB5D5DC9EE9094C6473E0E4B399D880E0051213C228EBEE8E1B3B4F8FC9E6787CA1D510D999497D83C7F370F9E5516FBBC4FCC68633C0A73E84A0E54999187479A49315B9D7A47484408F6064F1938F22D21E45231D04EC59F8A1513D7269A75A8F9BE2668C365E4AF98736607EEF23F6803DF1F907465C5474ADBB3D5745D9F8157FC0C8B8C3F4F1

Part 4 - Password Storage

Professor Shafer is tired of dealing with keys, and would rather deal with human friendly passwords. He has encrypted his secret data via the following process:

  1. Use scrypt password-hashing mechanism to produce 32-byte key from password.   CPU and memory difficulty levels (iterations) were changed from the default values to SCRYPT_OPSLIMIT_INTERACTIVE and SCRYPT_MEMLIMIT_INTERACTIVE to provide a balance between difficulty and time.
  2. Generate a random key and protect it via symmetric key encryption (Salsa20/Poly1305 MAC) with the password-derived key. This is the "outer box".
  3. Take the secret payload and protect it via symmetric key encryption with the random key. This is the "inner box".  This allows the password to be changed in the future without needing to re-encrypt the entire secret payload.

One file is provided:  part4.ciphertext.bin. This encrypted file has been saved to disk in the following format:

  1. Password salt: 32 bytes
  2. Outer box, encrypted: 72 bytes (32 byte key + 24 byte nonce + 16 byte auth). The outer box contains the random key
  3. Inner box, encrypted: Variable length (variable-length payload + 24 byte nonce + 16 byte auth). The inner box contains the secret payload.

Note that this secret payload is NOT ASCII text. Rather, it is mystery data and you should discover what it is using any available tools at your disposal.

You'll need the super secret password to get started. (Enter it in lowercase)


  • Write a Python3 program named part4.py that decrypts the secret payload and saves the resulting file to disk. Your program should print the following output on screen:
  • The filename of the decrypted secret payload that was written to disk
  • A human description of what kind of file was produced (in your own words)
  • A human description of what kind of viewer could be used to display the file. Name one specific viewer program that would work
  • The SHA-256 hash of the secret payload file. Use the Libsodium library or the Python hashlib library to compute this hash, not a standalone command line utility
  • Write a Python 3 program named part4_pw_change.py that allows the user to change the password without needing to re-encrypt the entire payload. Use the new password "cyberlab". The new output file should be named part4.ciphertext-new.bin.
Tip: Unsure if your part4_pw_change.py script is working correctly?  You can test it by temporarily making the following changes to your part4.py script:  (1) Change the input filename to part4.ciphertext-new.bin, and (2) Change the password to "cyberlab".  If you get the same secret payload as before, then you know your password change script works!   Be sure to restore the original functionality of part4.py before turning it in.