CryptoPals Crypto Challenges Using Rust: Fixed XOR

This is Challenge 2 of Cryptopals challenges implemented in Rust language.



Context

Given two hex encoded strings of similar length we have to return xor of it.
XOR (or, Exclusive OR) is a binary operation (like AND, OR) on bits. XOR gives true/1 as when the two inputs differ, otherwise false/0:

|  A  |  B  |XOR(A^B)|
|-----|-----|--------|
|  0  |  0  |    0   |
|  0  |  1  |    1   |
|  1  |  0  |    1   |
|  1  |  1  |    0   |

So, theoretically you can convert hex to binary and xor them to get output, like:

10110011 ^ 01101011 = 11011000

To solve the challenge with Rust, we can make use of hex crate to decode hex strings to bytes vec, zip the two vecs, then perform xor byte by byte to get XORed bytes. And finally encode xored bytes to hex:

use hex::decode, encode;

pub fn fixed_xor(hex1: &str, hex2: &str) -> String (&b1, &b2)

And we’re done.

See the code on Github.

Find me on:
Twitter – @heyNvN

naveeen.com




Source link

SafeCloset, a Secret Safe – Why and how I made it in Rust

Like everybody, I have small secrets to store, like door codes, some passwords, where I buried the body, etc.

They must be kept away from other eyes but, more importantly, they must be available, even if I’m traveling far from my computers.

And they must be easily backed up without risk.

In the past, I’ve dealt with such secret storage with various solutions, like having files decrypted, edited with my favorite editor, then encrypted again.

They were full of weaknesses:

  • temporary clear files that could be inadvertently backed up, or staying here if I had to leave or in case of crash
  • editor weaknesses, like backup files and plugins
  • OS specificity making them inaccessible when far from my computers

The temporary clear files where the most dangerous problem. I’ve had to hunt for my clear files after a badly parameterized backup rule.
Editor plugins were a real threat too, especially as I started using an AI plugin storing whole extracts of my texts for better auto-completion.

So I had to find or build better.

The obvious requirements for my new solution were:

  • an encrypted storage file, with a strong algorithm
  • a storage format making it possible to keep the file on non secure disks
  • a multi-platform application, that can be easily carried too
  • totally open-source, so that the program can be fixed or rewritten
  • no clear file ever created, no data sent to external API, so the application is an editor too
  • pure Rust, to avoid most nasty bugs

I added a few less obvious requirements:

  • easy fuzzy key search
  • fast opening, instant closing
  • auto-closing (dead man switch)
  • focus on ergonomics, I want to feel comfortable editing in the application

And in case I inadvertently become a secret agent:

  • plausible deniability by putting drawers (storage units) inside other ones
  • non observability of deep drawers (having several versions of the file doesn’t let you know whether there were changes and in which deep drawer)

Now, let’s see the technical choices.



Programming language: Rust

As I said, this was obvious to me. Such program can’t really be written today in another language. Rust doesn’t prevent all bugs, but it makes it possible to avoid the nasty ones which stay hidden and compromise security.



Cryptographic algorithm and library : AES-GCM

I never considered rolling my own algorithm or using a lightly tested library.

I choose an AEDS crate from the RustCrypto group: AES-GCM in its SIV variant (the SIV variant isn’t really needed but it doesn’t cost much).



File format

The minimal unit of secret in SafeCloset is an entry, which is made of a name and a value, for example “VISA Card code” and “9875”.

Entries are stored together in a drawer.

SafeCloset uses the metaphor of closets and drawers:
A SafeCloset file contains something which is called a closet.
A closet contains several drawers. Each drawer is separately encrypted, with its own passphrase (and nonce).

A drawer also contains a closet, which contains deeper drawers.

To ensure plausible deniability, drawers are automatically created, including deep ones, and nothing distinguishes drawers that you created and you can open from the ones which were automatically created and that you can’t open (you could if you knew their password but they aren’t displayed on creation and they only contain random bytes anyway).

Drawers are serialized using the serde crate which is kind of standard in the Rust world and is very convenient. For the encoding format, I choose MessagePack which, like JSON, allows field addition but is much more compact. Having optional fields is very important to allow evolution of the file format while ensuring old files will stay compatible with newer versions of the application.

Combining the chosen encryption scheme and the serialization encoding with the list of structures and fields, the complete file format is described in the community page to allow replacement of the application if needed.



Making an UI in the terminal

There are many low level libraries whose features go from the basic (and easy) task of coloring and styling the text you print in the terminal to handling events, terminal size, alternate screen, etc. I personally like Crossterm which is cross platform and well designed.

I combine it with Termimad, a crate I made to manage skins, generate texts without mixing the style and the content, handle text inputs, even with wide characters, and a lot of small TUI related problems.

Termimad allows fancy things like editing texts in small areas of your terminal and fading the view behind the menus or dialogs:

the fancy color fading

As the author of Termimad I feel comfortable to not recommend you use it for your own TUI. Not that it’s bad, I like it, but it’s a strange beast covering much more than what a library should do, and at a much lower level than your typical framework. If you’re not used to low level TUI libraries and well versed in Rust, I suggest you look at other higher level TUI crates.
If you still hesitate, come to my chat and I’ll tell you whether Termimad might be the right choice for your application.



The result: SafeCloset

Here it is: https://dystroy.org/safecloset/

If I may say so, I’d say SafeCloset is convenient and pleasant to use.
It lets me find and read my secrets in a few keystrokes.
And it seems to be the most secure solution I ever used.
I designed it to be intuitive for other users too, and I hope I succeeded.

To better introduce it, I made a website explaining how it works, how to install it, how to use it: https://dystroy.org/safecloset/

The current version is a candidate for a release as 1.0, there’s nothing important missing right now, but I’ll let some time run to be sure.

I’d welcome your opinion!


Source link

Caesar Cipher: A Simple Encryption System in PicoLisp

Welcome to the “Classic Algorithms” series. Here we will discuss code examples from the Rosetta Code Project and explain step by step how the implementation works. Our first task will be the “Caesar Cipher”.

In this post, we will meet many of the “List and Strings” functions that we know from the Beginner’s-series.



The Task

If you want to try by yourself first, here is the task description:

Implement a Caesar cipher, both encoding and decoding. The key is an integer from 1 to 25. This cipher rotates (either towards left or right) the letters of the alphabet (A to Z). The encoding replaces each letter with the 1st to 25th next letter in the alphabet (wrapping Z to A). So key 2 encrypts “HI” to “JK”, but key 20 encrypts “HI” to “BC”.



How the Caesar Cipher encryption works

If you ever studied cryptographic algorithms, you will probably have come across the Caesar Cipher as it is easy to understand (and easy to break, too).

It is named after the Roman emperor Julius Caesar as there is some evidence that he used this encryption system to transport secret messages. For more historical background, see here.

caesarstatue.jpg

The idea is that every letter in the alphabet is shifted by a fixed number of steps, which is the “encoding key”. For example, if the key is 2, then you write “C” for “A”, “D” for “B”, “E” for “C” and so on. At the end of the alphabet, “Y” becomes “A” and “Z” becomes “B”. Obviously it is not a very safe encryption because it’s easy to crack using statistical methods, or by checking all possible shifts.

Nevertheless, the implementation of the Caesar Cipher in PicoLisp is a nice example to start our Rosetta code series. It illustrates some interesting concepts such as circular lists, mapping, and anonymous functions. Many of the functions were already introduced in the “PicoLisp for Beginners” series, and the code is elegant and short.

Let’s go!



An intuitive approach to the algorithm

How should we implement this algorithm? It is clear that the order of the letters is very important, and it needs to be circular since the end of the alphabet should be mapped to its beginning. The picture from the cover sheet illustrates the principle very well:

caesar.jpg

The inner circle is the plain character, the outer circle is the encryption. Let’s try to implement this in PicoLisp now.



Step 1 – Creating the alphabet list

The first thing we need is the list of all alphabet characters. One main idea is to make the list “circular”, i. e. after “Z” comes “A” (like the tool on the pic above). In PicoLisp, this can be done by the . symbol, for example (1 2 3 .) or using the circ function. Let’s form the list:

The straightforward way: Of course, we can just type each letter by hand.

(setq *Letters '("A" "B" "C" ... "Z" .))

The elegent way: The solution above is quite error-prone. A better way would be to use ASCII encoding to create this list. Uppercase letters are encoded by the numbers 65 to 90. So let’s do the following:

  1. create a list from 65 to 90 using (range 65 90) –> (65 66 67 … 90).
  2. Numbers can be converted to characters by char, for example (char 65) = A. Let’s apply the char function to our list with (mapcar char (range 65 90)). –> (“A” “B” “C” … “Z”).
  3. Now make the list circular by applying the circ function to each letter. (apply circ (mapcar char(...)))
    –> (“A” “B” “C” … “Z” .), where . shows that after “Z” comes “A” again.
  4. Set this list to the global variable *Letters (with uppercase and asterisk according to naming convention).

We get:

:(setq *Letters (apply circ (mapcar char (range 65 90))))
-> ("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" .)



Step 2 – Encoding a single character

Let’s try to get the string we want to encode. As first step, let’s convert all letters to uppercase with uppc and use the chop function to transform the string into a list of characters:

:(chop (uppc "in vino veritas")) 
->("I" "N" " " "V" "I" "N" "O" " " "V" "E" "R" "I" "T" "A" "S")

Now to encode these letters, we need to create a function that takes any character and returns the encoded one. Let’s go through it step by step.

  1. First we check if the character is within the *Letters list by using the member function, which returns the list starting from that character if it exists, otherwise NIL.

    : (member "U" *Letters)                                   
    -> ("U" "V" "W" "X" "Y" "Z" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" .)
    : (member "D" *Letters)
    -> ("D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "A" "B" "C" .)
    
  2. As you can see, the member function returns the *Letters list starting at the respective letter. Now we want to get the encoded letter, which is shifted in position by the encryption code key. In order to shift the list, we use the nth function, which takes a list and integer value and returns the tail of the list starting from that value:

:(nth (member "U" *Letters) 2))
-> ("V" "W" "X" "Y" "Z" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" .)
:(nth (member "D" *Letters) 6)
-> ("I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" "A" "B" "C" "D" "E" "F" "G" "H" .)
  1. It’s getting close, but when we check the list returned by nth, we actually want the second item in the shifted list, because the nth function is only shifting by (key -1) positions. To get this second item, we use cadr, which is short for cdr and car. (Re-read this post if you’re not sure what car and cdr mean).
: (cadr (nth (member "U" *Letters) 2)))
-> "W"
: (cadr (nth (member "D" *Letters) 6))
-> "J"



Step 3 – Bringing it together

In Step 1 we chopped up the input string to a list, and in Step 2 we managed to encode each of these letters separately. Now let’s bring it together.

We want to take each letter of the input string and apply our encoding function on each single element, which is a typical application for mapcar. mapcar takes a function and a list as arguments. But what is our function? Obviously, we could define it like this:

(de encodeChar (C)
    (cadr (nth (member C *Letters) Key))) )

and hand it over to mapcar. But actually we need the encoding function only once, so it might be a better option (in terms of structure and readability) to define it as anonymous function.

As we might remember from the beginner’s tutorial, the syntax for anonymous functions is ” ‘((args) ( function )) “, so we can define it as:

:'((C) (cadr (nth (member C *Letters) Key)))

where C is the character to be encoded.

Now let’s create and test our mapcar anonymous function call on the chopped list, with key = 3:

: (setq TestStr (chop (uppc "in vino veritas")))
-> ("I" "N" " " "V" "I" "N" "O" " " "V" "E" "R" "I" "T" "A" "S")
: (mapcar '((C) (cadr (nth (member C *Letters) 3))) TestStr)
-> ("L" "Q" NIL "Y" "L" "Q" "R" NIL "Y" "H" "U" "L" "W" "D" "V")

This already looks quite promising: at least the character shifting looks correct now.

Now as last step, we need to convert these single letters back to a string, which we can do by using the pack function. We wrap it around our mapcar function and get:

: (pack (mapcar '((C) (cadr (nth (member C *Letters) 3))) TestStr))
-> "WKLVLVDWHVW"

As you can see, we “automatically” also got rid of all the NIL values that were created by whitespaces and punctuations.



Step 4 – Finishing the script

Let’s now wrap it up in a small script. We want to call it using the following syntax: ./caesar-cipher.l <plain-string> <key>, for example:

$ ./caesar-cipher.l "In vino veritas" 7
PUCPUVCLYPAHZ

As we learned in the “A very first PicoLisp Program”-post, we can retrieve the two parameters <plain-string> and <key> using opt.

Note that opt converts to string, so we need to use the function format to convert the key from string to integer, and store both in the global variables *PlainStr and *Key:

#! /usr/bin/picolisp /usr/lib/picolisp/lib.l

# first command line parameter: plain string
(setq *PlainStr (opt))

# second command line parameter: key (integer)
(setq *Key (format (opt)))

Also we need to define the global *Letters list and f course our encoding function caesar that takes a string and a key as parameters and returns the encoded string.

(setq *Letters (apply circ (mapcar char (range 65 90))))

(de caesar (Str Key)
   (pack
      (mapcar '((C) (cadr (nth (member C *Letters) Key)))
         (chop (uppc Str)) ) ) )

Then finally, we call the caesar function with the command line parameters and print out the result.

(prinl (caesar *PlainStr *Key))

After that we exit the interpreter with bye.

Finished!

The final script can be downloaded from here. Steps: Download the script, for example using curl:

$ curl https://gitlab.com/picolisp-blog/single-plage-scripts/-/raw/main/rosetta/caesar-cipher.l -o caesar-cipher.l

Make it executable:

$ chmod +x caesar-cipher.l

Run!

$ ./caesar-cipher.l "In vino veritas" 7
PUCPUVCLYPAHZ

This was the first part of the “Rosetta code” series, I hope you liked it.

Tomorrow we will have a look a closer look at the set function in PicoLisp, as preparation for the “100 Doors Task” from the Rosetta Code.



Sources


Source link