Armor-plated Crypto

--

One of the first things you learn about computing is that we think in characters and numbers, and they think in binary. And, so, we must find ways to convert our characters and numbers into binary. Typical formats include hexadecimal, octal, Base64 and ASCII, and where formats convert the binary format into something we can read, print and copy, and vice-versa. For example, 0101 1011 in binary becomes 5b in hexadecimal.

In cryptography, too, you learn that our processing is performed on bytes, and we have a byte array on which we operate on. Our inputs and outputs to our encryption and decryption processes must thus be in the form of a byte array. There is no strange EOF (End of File) characters that we need when we use strings - it is just a whole bunch of bytes. In memory, this is typically defined as a buffer of data.

So, a problem we have is to output our ciphertext — and which is in the form of a whole lot of bytes — in a form which can be easily transported into other systems or applications. For this we can use the armor format. In this case we will use the AGE (Actually Good Encryption) encryption method to demonstrate the technique.

Overall, the armor process converts ciphertext into a text format, and uses the ASCII armoring format. This output begins with “ — — -BEGIN AGE ENCRYPTED FILE — — “ and ends with “ — — -END AGE ENCRYPTED FILE — — -”, and has 64 character values in a line of text. This type of format makes it easier to transport the ciphertext, as it can be inserted into a text formatted message format, or can be easily copied and pasted into a console application.

From the command line, we can enable the ASCII-only “armored” encoding format using the “-a” option:

$ age -e -a -r  age1axz2uqf9yzvp88ychw5dznj5gx56pkt24f0095jvk5uzuka2yvjq7869el 1.txt > 1.txt.age
$ cat 1.txt.age
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1SGlwWFBLOEpmZG9iT3RS
S3BNZDFObnMvYkszd1ZpMElNWWIzWEQ2ZkQ0CjRrOE5nQUwvUk5jYXVSWTZjSTUz
S0NudnEzVXNVTXAyZEpvZ29vWFpISzgKLS0tIDNYR0xZd3dNTnZvazBDc3dIZmFI
Y045RG5YYlZrT2dDYWYzMFE5aVNQaTQKNCba7C55KMEXZv258lU6Z1C3W8QAtZIF
RqeqPIvJa9cE54aACA==
-----END AGE ENCRYPTED FILE-----

When decrypting the amored format is automatically detected:

$ age -d -i key.age 1.txt.age
Enter passphrase for identity file "key.age":pass
Hello

Coding

To create the Armor format, we add a new writer for the data:

recipient, _ := age.ParseX25519Recipient(publicKey)
out := &bytes.Buffer{}
armorWriter := armor.NewWriter(out)
w, _ := age.Encrypt(armorWriter, recipient)

and then to un-armor:

receiver, _ := age.ParseX25519Identity(privateKey)
armorReader := armor.NewReader(out)
r, _ := age.Decrypt(armorReader, receiver)

The Golang code for this is [here]:

package main

import (
"bytes"
"fmt"
"io"
"log"

"os"

"filippo.io/age"
"filippo.io/age/armor"
)

func main() {

msg := "Hello"

argCount := len(os.Args[1:])

if argCount > 0 {
msg = os.Args[1]
}

identity, _ := age.GenerateX25519Identity()
publicKey := identity.Recipient().String()
privateKey := identity.String()

recipient, _ := age.ParseX25519Recipient(publicKey)

out := &bytes.Buffer{}

armorWriter := armor.NewWriter(out)

w, _ := age.Encrypt(armorWriter, recipient)

if _, err := io.WriteString(w, msg); err != nil {
log.Fatalf("Failed to write to encrypted file: %v", err)
}
w.Close()
armorWriter.Close()

fmt.Printf("Message:\t%v\n", msg)

fmt.Printf("Public key:\t%v\n", publicKey)
fmt.Printf("Private key:\t%v\n", privateKey)
fmt.Printf("\nEncrypted file size: %d\nCipher:\n%v\n", out.Len(), string(out.Bytes()))

receiver, _ := age.ParseX25519Identity(privateKey)

armorReader := armor.NewReader(out)

r, _ := age.Decrypt(armorReader, receiver)

_, _ = io.Copy(out, r)

fmt.Printf("\n\nDecrypted string:\t%v", string(out.Bytes()))

}

and a sample run is [here]:

Message:	the quick brown fox jumps over the lazy dog 123
Public key: age19gmpplfknmh8rm7qmu0f9stq4r9d4t45hczq0f3srd4elshhs4gs3qu93y
Private key: AGE-SECRET-KEY-100FZ330H3QPK8TW6ATQHQ0MP8L77L2DESEDPQ0VQYZTNNEQJ2PDQHW2267
Encrypted file size: 406
Cipher:
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBWOFhBTTZ3RjV2QTJ2TTdD
cGlXZzJNTE8xMUxoV2VQUjV6ckQrR1grQWpRCkdnT3RZT0tGVHlGeHMrSkJKd2pL
UGZOMjdIbHBmUkdZL1B3NGVDVHl0NWsKLS0tIExYRW52blNpZ2hLanlyazhxR3U4
Q0pHTGlvelRaaGVCT1NYclhvSFRnWWcKnWWgAvbycz5gjj4Q+leVv/qHz41g3GRA
s1pyKIg+qrSoAffDBFhgQLSyh9J3dMb3frRmU03yW5cKbwz6JmpFOn3DhNAjF4Sn
RY7ntDrsWQ==
-----END AGE ENCRYPTED FILE-----
Decrypted string: the quick brown fox jumps over the lazy dog 123

You can discovered more about the Amor format here: https://asecuritysite.com/pgp/pypgp

--

--

Prof Bill Buchanan OBE FRSE
ASecuritySite: When Bob Met Alice

Professor of Cryptography. Serial innovator. Believer in fairness, justice & freedom. Based in Edinburgh. Old World Breaker. New World Creator. Building trust.