ABSOLUTELY you SHOULD WRITE your own ENCRYPTION LIBRARY!

Mark Arnold
8 min readAug 1, 2022

Why, and how in just a few lines of code.

Begin:

The following article focuses on a number of common yet easily fixed security weaknesses that are typically found in almost all software developments including those of multi-billion corporations. This article is technical in nature and designed to be absorbed by an experienced software developer.

If you actually take the time to read this article and you are actually not breaking any of the rules below then well, you are a GOD and I salute you!

It by no means covers all weaknesses, rather is covers those which are easily fixed and deliver a next-level of security to your software or application. It assumes a LINUX environment however the concepts also apply to other o/s. Let’s GO!

Encryption is your friend but how are you using it?

Encryption is your friend.

And it is very important (and very simple) to invent your own encryption library. You’ll find thousands of articles discouraging you from writing your own encryption algorithm but not very m(any) explaining precisely what you should be doing and further, how to actually do it… so here we go…

  • Do NOT invent your own encryption algorithm.
  • DO INVENT your own encryption library.
  • The ONLY encryption algorithms you should consider are: AES-256, SERPENT and Two-Fish. I recommend using “SERPENT” over “AES”, however your encryption library could easily incorporate them all.
  • DO USE a library such as LibTomCrypt which is maintained. LibTomCrypt is available for every mainstream language. Other libraries exist and are equally valid if they are actively maintained and are at least 10 years old.
  • You MUST enable CBC mode when utilizing your encryption algorithm. You must ensure you are using the maximum number of rounds that your algo supports. AES (14), SERPENT (32), and TWOFISH (16).
  • All secrets and IV’s must be randomly generated using a cryprographically secure psuedo-random generator such as Lib/secrets.py for Python. (all other languages have similar options)

Nothing revolutionary so far, although are you using your own library? Keep reading and you’ll see just how super simple it is!

Let’s get into the actual code… I will code in “universal”. The code below represents what you might be doing currently: (algorithm independent)

 $enc_text = library_CBC_encrypt($plain_text, $secret, $iv);

The $iv (initialization vector (see above)) we’ll ignore for now as often this is correctly implemented… same for $secret.

MASSIVE SO SIMPLE SECURITY INCREASE

sub encrypt ($plain_text, $secret, $iv) {
$r_bytes = random_bytes(16);
$enc_text= library_encrypt( $r_bytes . $plain_text, $secret, $iv);
return $enc_text;
}
sub decrypt ($enc_text, $secret, $iv) {
$plain_text = library_decrypt($enc_text, $secret, $iv);
$plain_text = sub_string ($plain_text, 16);
return $plain_text;
}

Now, YOU have YOUR OWN CUSTOM ENCRYPTION LIBRARY!

16 x random bytes added into the encryption (effectively a random pepper) already means that encrypting the “same plain text” always yields different results with the same secret and the same IV and it’s trivial to return the result minus the 16 bytes as above.

YOU SHOULD ALWAYS PEPPER!

Now, immediately your security is massively improved in two lines of code.

  • Even if you have a weak “secret” (a catastrophe but not unusual) and a bad actor was attempting to brute-force-decrypt the plain-text “hello” they can no longer do that. (as you never encrypt “hello”)
  • Every current and future rainbow attack is nullified.
  • Assuming a future weakness is discovered in the underlying algorithm then almost certainly it will shall rely on multiple non-peppered analysis which you are protected against.
  • Your encryption library produces unique results with identical inputs.

HMAC. (Message Authentication Code)

Let’s add our own HMAC into our own encryption library which again MASSIVELY increases security in just a COUPLE of lines of code… LibTomCrypt includes a number of message authentication protocols however I recommend “Blake2b MAC” as it’s FAST, secure and often overlooked.

HMAC enforces integrity and authenticity to our encryption library. In the example below we’re using a 16 byte HMAC signature which is prepend-ed to the actual encrypted data. This is critical as many encryption algorithms allow you to decrypt data with any secret and thus give you a resulting data-stream which might be parsed / interpreted by code with unexpected results. We thus extend our custom encryption library, as simple as the below:

sub encrypt ($plain_text, $secret, $iv, $hmac_secret) {
$r_bytes = random_bytes(16);
$enc_text = encrypt($r_bytes . $plain_text, $secret, $iv);
$hmac = blake2b_mac (16, $enc_text, $hmac_secret);
return $hmac . $enc_text;
}
sub decrypt ($enc_text, $secret, $iv, $hmac_secret) {
$hmac = blake2b_mac (16, sub_string($enc_text,16), $hmac_secret);
return failure if $hmac not equal to sub_string($enc_text,0,16);
$plain_text = decrypt( sub_string ($enc_text, 16), $secret, $iv);
return $plain_text;
}

DATA, and how to STORE it.

Of course you need to STORE STUFF in SQL, look-ups, REDIS, TEXT files.

2020 — Internet Giant Comcast, over 1 billion emails and passwords

2021 — Phone numbers for 533 million Facebook users leaked

If you are storing ANY of the below in your underlying system as plain-text then you need to think again! (PASSWORDS are a special case, see later). If you are relying on encrypting using “data-at-rest” then forget about that too.

  • Forename, surname
  • Email address
  • Address, geographic
  • Credit cards
  • Telephone numbers
  • Driving license / social security / TAX ID’s / etc..
  • Date of birth
  • ID link. (for instance Telegram ID or WhatsAPP ID)

Often, you need to LOOKUP this encrypted stored information and therefore you need a unique KEY. I’ll use email addresses in the examples below as so bloody often email addresses are stored unencrypted within an information store. Or in Facebook’s case, 1/2 billion phone numbers. OMG!

Indeed, ANYTHING that is ANYWAY linked or connected to an ACTUAL person MUST be encrypted with your library if it is stored ANYWHERE.

So, we now need to extend our encryption library with a HASH function:

Hash. (Cryptographic hash function)

I personally prefer a Blake2b HASH due to it’s speed however SHA-3 is the standard. Of course LibTomCrypt supports both and many more too.

YOU SHOULD ALWAYS PEPPER

If you’re using HASH algorithms, MD5, SHA, Keccak, BLAKE, etc. without a PEPPER then think again! You know, sites like https://crack.sh/ and https://crackstation.net/ to name just two are on your case.

sub hash ($text_to_hash, $hash_pepper) {
$hash = blake2b_hash ( $text_to_hash . $hash_pepper );
return $hash;
}

Once again in a single line of code you defeat every pre-calculation of a HASH and there are literally billions of pre-calculated hashes available. $hash_pepper should be 16 random bytes pre/post appended to the actual text therefore resulting in a UNIQUE HASH to your encryption library and therefore not reproducible for any hacking or cracking site.

Storing DATA

The above is an atypical example of your new SQL table… the KEY, the INDEX, the LOOKUP has now changed to “email_hash” from “email_address”.

SELECT decrypt(email_enc) WHERE email_hash = hash(email_address);

As every encryption is UNIQUE as every encryption contains a 16 byte random pepper then you CANNOT lookup the encrypted email address via email_enc as it is UNIQUE and not reproducible. email_hash is also UNIQUE however contains a static pepper and is therefore reproducible.

So, where you were SELECTing or using “email_address” as your previous INDEX/KEY, you are now using “email_hash”. This allows super fast indexing (as before) and only then do you decrypt the email address using your custom library once you’ve matched the row you’re looking up.

Apply the same to all data linked to an individual, email_address is only an example of the obvious.

Recap!

If you’re still with me then you are bloody amazing and obviously a super intelligent developer who finds stuff like this interesting. I salute you.

So, all of your encryption is now totally custom, you have your own encryption, decryption, HASH, HMAC algorithms which are based on world leading libraries which cannot be replicated by standard hacking techniques and all of your personal data in your databases is encrypted with super fast look-ups just as before and all, in reality, in just a few lines of additional code.

That is the recap. It really is super simple… encryption is your friend.

STORING PASSWORDS:

The amount of times I’ve read you shouldn’t encrypt passwords with a standard encryption algorithm such as say AES drives me mad!

Of course you MUST!

And of course I’ve read, never ever use a HASH algorithm such as SHA.

Of course you SHOULD!

Here is a PERFECT way to store passwords:

sub store_password 
($txt_passwd, $secret, $iv, $hmac_secret, $hash_pepper, $salt) {
// $salt is 16 x random bytes (per USER_ID) & stored (somewhere) linked to USER_ID. $hash_pepper is static. $salt is per user unique. $passwd_hash = hash ($txt_passwd, $hash_pepper . $salt);
$argon_passwd = ARGON2 ($passwd_hash, $salt);
$store_passwd = encrypt($argon_passwd, $secret, $iv, $hmac_secret);
// So now we have a TEXT PASSWORD provided by the user which we initially HASH to our own unique formula and is reproducible.// Then we ARGON it up using a reproducible and stored SALT. More on ARGON later. You SHOULD be using ARGON or bCrypt is acceptable too.// Finally, we encrypt and HMAC authenticate which is not reproducible but can be reversed using the correct decrypt parameters. return $store_passwd;
}
sub check_password
($txt_passwd, $secret, $iv, $hmac_secret, $hash_pepper, $salt, $id){
// $id is the USER_ID for the password to be looked up.
$store_passwd = SELECT $store_passwd FROM $USER_ID;
// So let's decrypt our stored password from the database....
$argon_passwd = decrypt($store_passwd, $secret, $iv, $hmac_secret)
// Now we re-create the HASH using the supplied text password as b4
$passwd_hash = hash ($txt_passwd, $hash_pepper . $salt);
// Now let's verify the $argon_passwd with the supplied $txt_passwd
$verify = argon_verify ($argon_passwd, $passwd_hash);
return $verify;
}

A few notes on the above:

  • We use our own HASH routine to take the plain_text password and we add our unique per USER_ID salt to the HASH which also contains our own static PEPPER thus creating our own plain_text password which we then use ARGON to define the key.
  • ARGON is a key derivation algorithm suitable to convert any password into a cryptographic key. It offers variable time and memory costs as well as output size which can be configured based on your requirements.
  • We encrypt the resulting output from ARGON and actually store the encrypted ARGON key in the database, REDIS or other.

CONCLUSIONS:

  • We’ve created our own custom encryption and decryption libraries which yield significant security increases yet operate on proven underlying cryptographic libraries.
  • We authenticate and verify the integrity when decrypting.
  • We have our own custom HASH routines with PEPPER.
  • We can store any information in a super secure way and we can lookup this information just as before by adding an additional lookup column to our data which is our custom Blake2b HASH.
  • Passwords are secured using salts, peppers, ARGON derivation and finally encrypted into the main database.
  • And all in just a few lines of code.
  • And this forms just the beginning of how you can build and extend your own libraries to work from.

COMMENTS OR QUESTIONS WELCOMED!

:-)

--

--

Mark Arnold

The simplest most advanced appointment system in the world.