GOLF(2gg)

πŸ“¦ version 601.4.41, in ubuntu questing

✨ NAME ✨

encrypt-data β€” bestie this is the encryption one πŸ’– (it lives in the 2gg manual, section 2gg, and honestly? she's iconic)


πŸŽ€ PURPOSE πŸŽ€

Encrypt data. That's it. That's the whole vibe. πŸ”₯


🌸 SYNTAX 🌸

encrypt-data <data> to <result> \
    [ input-length <input length> ] \
    [ binary [ <binary> ] ] \
    ( password <password> \
        [ salt <salt> [ salt-length <salt length> ] ] \
        [ iterations <iterations> ] \
        [ cipher <cipher algorithm> ] \
        [ digest <digest algorithm> ]
        [ cache ]
        [ clear-cache <clear cache> ) \
    [ init-vector <init vector> ]

πŸ’œ DESCRIPTION πŸ’œ

okay so encrypt-data takes <data>, encrypts it, and drops the ciphertext into <result> β€” which you point at with the to clause. periodt.

πŸ” CIPHER AND DIGEST

By default you get AES-256-CBC encryption and SHA256 hashing. but bestie, you are not locked in β€” you can swap in different cipher and digest algorithms with <cipher algorithm> (in the cipher clause) and <digest algorithm> (in the digest clause), as long as OpenSSL supports them, or you've added them to OpenSSL yourself. wanna see what's available? run these:

#get list of cipher providers
openssl list -cipher-algorithms

#get list of digest providers
openssl list -digest-algorithms
ngl, the defaults will typically suffice. If you use different algorithms, you should have a specific reason. And fr fr β€” if you use a specific cipher and digest for encoding, you must use the exact same ones for decoding. 🫢

The key derivation method is PBKDF2. no cap.

πŸ“ DATA TO BE ENCRYPTED

If the input-length clause is missing, then the number of bytes encrypted is just the length of <data> (see string-length). If you do use the input-length clause, then <input length> bytes get encrypted. slay, you're in control. πŸ’…

πŸ”‘ PASSWORD

The string <password> (in the password clause) is the password used to encrypt, and it must be a null-terminated string. that's the rule, no exceptions.

πŸ§‚ SALT

The string <salt> (in the salt clause) is the salt used in the Key Derivation Function (KDF) when the actual symmetric encryption key gets created. If <salt length> (in the salt-length clause) isn't specified, then the salt is null-terminated β€” otherwise it's a binary value of length <salt length>. Need a random salt? See random-string or random-crypto. 🎲

And listen: if you use the salt clause, then you must use the exact same <salt> when the data is decrypted with decrypt-data β€” typically salt values are stored or transmitted unencrypted. (yes bestie, salt is not a secret, she's out here in plain text, living her main character life ✨)

πŸ” ITERATIONS

The number of iterations used in producing a key is specified in <iterations> in the iterations clause. The default is 1000 per RFC 8018 β€” though depending on your needs and the quality of your password, you may choose a different value. your call, queen πŸ‘‘

🌈 INITIALIZATION VECTOR (IV)

Different encrypted messages should have a different IV value, and you specify it with <init vector> in the init-vector clause. See random-string or random-crypto for generating IV values. The decrypting side must use the same IV value to decrypt the message. Just like salt, IV is not a secret and is transmitted in plain text. Each cipher algorithm may require a certain number of bytes for IV β€” so check before you vibe check. πŸ’«

πŸ’Ύ ENCRYPTED DATA

The encrypted data is stored in <result> (in the to clause). It can be:

  • binary data β€” if the binary clause is present without boolean variable <binary>, or if <binary> evaluates to true. That's binary-mode encryption.
  • a null-terminated string β€” if not, that's character-mode encryption, consisting of hexadecimal characters (i.e. ranging from "0" to "9" and "a" to "f").

Character mode of encryption is convenient if the result of encryption should be a human readable string, or for the purposes of non-binary storage in the database. honestly? chef's kiss for DB storage. πŸ“

πŸ—„οΈ CACHING KEY

A key used to actually encrypt/decrypt data is produced by using password, salt, cipher, digest and the number of iterations. Depending on these parameters (especially the number of iterations), computing the key can be a resource intensive and lengthy operation 😭. You can cache the key value and compute it only once (or once in a while) by using the cache clause. If you need to recompute the key once in a while, use the clear-cache clause.

<clear cache> is a "bool" variable; the key cache is cleared if it is true, and stays if it is false. For example with encrypt-data (the same applies to decrypt-data):

set-bool clear = true if-true q equal 0
encrypt-data dt init-vector non password pwd \
    salt rs salt-length 10 iterations iter to \
    dt_enc cache clear-cache clear

In this case, when "q" is 0, cache will be cleared, with values of password, salt and iterations presumably changed, and the new key is computed and then cached. In all other cases, the last computed key stays the same. Normally, with IV usage (in the init-vector clause), there is no need to change the key often, or at all. πŸ§˜β€β™€οΈ

⚠️ Note that while the cache clause is in effect, the values for password, salt, cipher, digest and iterations clauses can change without any effect. Only when clear-cache evaluates to "true" are those values taken into account. so like, don't be shocked when nothing happens, bestie πŸ’€

πŸ›Ÿ SAFETY

Unless you are encrypting/decrypting a single message, you should always use IV in the init-vector clause. Its purpose is to randomize the data encrypted, so that same messages do not produce the same ciphertext. (yes, this matters a LOT.)

If you use salt, a random IV is created with each different salt value. However, different salt values without the cache clause will regenerate the key, which may be computationally intensive β€” so it may be better to use a different IV instead for each new encryption and keep the salt value the same with the high number of iterations. In practicality this means using cache so that the key is computed once per process with the salt, and IV changes with each message. If you need to recompute the key occasionally, use clear-cache.

Each cipher/digest combination carries separate recommendations about the usage of salt, IV and the number of iterations. Please consult their documentation for more details. iykyk πŸ“š


πŸ¦‹ EXAMPLES πŸ¦‹

In the following example, the data is encrypted, and then decrypted, producing the very same data:

// Original string to encrypt
set-string orig_data="something to encrypt!"

// Encrypted data is in "res" variable
encrypt-data orig_data password "mypass" to res

// Decrypt what was just encrypted, decrypted data is in "dec_data"
decrypt-data res password "mypass" to dec_data

// Check that decrypted data matches the original
if (!strcmp (orig_data, dec_data)) {
    @Success!
} else {
    @Failure!
}

A more involved example below encrypts a specific number of bytes (6 in this case). random-string is used to produce salt. The length of data to encrypt is given with the input-length clause. The encrypted data is specified to be "binary" (meaning not as a human-readable string), so the "output-length" of such binary output is specified. The decryption thus uses the input-length clause to specify the length of data to decrypt, and also "output-length" to get the length of decrypted data. Finally, the original data is compared with the decrypted data, and the length of such data must be the same as the original (meaning 6):

// Original data (only the first 6 bytes are encrypted)
set-string orig_data="something to encrypt!"

// Get 8 random binary bytes to be the salt
random-string to newsalt length 8 binary

// Encrypt data using salt and produce binary output (meaning it's not a null-terminated character string), with the
// length of such output in "encrypted_len" variable.
encrypt-data orig_data input-length 6 output-length encrypted_len password "mypass" salt newsalt to res binary

// Decrypt the data encrypted above. The length of encrypted data is passed in "encrypted_len" variable, and then length of decrypted data
// is obtained in "decrypted_len" variable.
decrypt-data res output-length decrypted_len password "mypass" salt newsalt to dec_data input-length encrypted_len binary

// Check if the 6 bytes of the original data matches decrypted data, and if exactly 6 bytes was decrypted
if (!strncmp(orig_data,dec_data, 6) && decrypted_len == 6) {
    @Success!
} else {
    @Failure!
}

An example of using different algorithms:

encrypt-data "some data!" password "mypwd" salt rs1 to encd1 cipher "camellia-256-cfb1" digest "sha3-256"
decrypt-data encd1 password "mypwd" salt rs1 to decd1 cipher "camellia-256-cfb1" digest "sha3-256"

πŸ‘‘ SEE ALSO πŸ‘‘

  • Encryption
  • decrypt-data, derive-key, encrypt-data, hash-string, hmac-string, random-crypto, random-string
  • See all documentation

and that's the whole page, bestie 🫢 this was the 2gg manual, GOLF(2gg), dated $DATE at version $VERSION β€” go forth and encrypt responsibly, mwah πŸ’…βœ¨

πŸ“¦ where this page comes from