Beta

The Messenger's Oracle

Description:

Your Background

As a master spy, you have been embedded in a rival kingdom in order to monitor communications between their top General and the monarch and risen to the role of messenger between the two of them.

Unfortunately, the messages you've been delivering are all encrypted. You have gathered some intel (listed below) in your time here, as the General can be quite talkative whilst decoding their messages, but you have been unable to find a list of the keys in use. Worried that your cover might be starting to wear thin you need to find another way to read the messages from the intel you have.

Gathered Intel

Mood of the General

The General's mood does not seem to be affected by the quantity of messages they receive. However, you have noticed that when the General receives a message they seem to have one of following three reactions:

  • If the message has been signed by the monarch then they always seem to be happy;
  • If the message has come from someone else and so has not been signed by the monarch then they seem to be angry and just discard it;
  • If the message doesn't seem to have been written correctly then they seem to be confused;

Decryption Process

  1. The messages you deliver first need to be base64 decoded
  2. The result is then split with the first 16 bytes noted as the initialisation vector (IV) for the decryption
  3. The message is then decrypted using the IV from step 2 and a key from a secret book the General always keeps on themselves. The encryption method is AES-128 CBC
  4. Finally there's always some padding to be removed, the General looks at the value of the last byte and removes that many copies of the byte from the end of the message (it's at this point the General occasionally seems confused)

In code, this equates to:

@key "Secret 16 bytes!"

def decrypt_message(message) do
    # Base 64 decode (1) and split into IV and message data (2)
    << iv::binary-16, data::binary >> = Base.decode64!(message)
    # Perform AES-128 CBC decryption (3)
    :crypto.block_decrypt(:aes_cbc128, @key, iv, data)
    |> OracleHelpers.unpad() # Remove padding using helper function (4) and return
end
import base64
from Crypto.Cipher import AES

KEY = b"Secret 16 bytes!"

def decrypt_message(message):
    # Base 64 decode (1)
    data = base64.decodebytes(message)
    # Split into IV and message data (2)
    iv, data = data[:16], data[16:]
    # Perform AES-128 CBC decryption (3)
    cipher = AES.new(KEY, AES.MODE_CBC, iv)
    # Remove padding using helper function (4) and return
    return OracleHelpers.unpad(cipher.decrypt(data))

Note: this is the process when you know the key, sadly you haven't got your hands on the book of keys so won't be able to use it this way in this kata

Known Examples

You have found a handful of early examples of encoded/decoded messages along with their key which has allowed you to verify the encryption process (these make up the example tests). From this you know that the monarch's signature is " - HRH" at the end of a message.

Solving This Kata

In order to solve this kata you must provide a function spy_on_message/2 the arguments to this function will be:

  1. message - a base64 encoded string representing the message to decode;
  2. deliver_fn/1 - a function that allows you to deliver a message to the General and observe their response. The response will be one of:
    [:angry, :confused, :happy]
    
    ["angry", "confused", "happy"]
    

The output of the function should be the decrypted message with no added padding.

There is a utility function available to you OracleHelpers.unpad/1 which follows the process detailed above to remove message padding (so you don't have to write it yourself). It will return the unpadded message if all is fine, or :nil / None if something was wrong with the padding.

If you wish to work on this via a local IDE, the example test section should have everything you need to get started with testing your code.

Note: For python, predefined kata functions output/receive bytes rather than strings.

Test Constraints

  • The decrypted messages may be any length from 0 bytes to 160 bytes long;
  • The decrypted messages will sometimes result in a readable string but most of the time they will not.
Cryptography
Puzzles
Algorithms
Security

Stats:

CreatedJul 19, 2020
PublishedJul 19, 2020
Warriors Trained66
Total Skips7
Total Code Submissions41
Total Times Completed7
Elixir Completions1
Python Completions7
Total Stars7
% of votes with a positive feedback rating88% of 4
Total "Very Satisfied" Votes3
Total "Somewhat Satisfied" Votes1
Total "Not Satisfied" Votes0
Total Rank Assessments4
Average Assessed Rank
3 kyu
Highest Assessed Rank
2 kyu
Lowest Assessed Rank
4 kyu
Ad
Contributors
  • Greatlemer Avatar
  • hobovsky Avatar
Ad