I know what you are thinking, it's never a good idea to roll your own encryption functions, but I'm doing this for fun and self-learning.

I created a function that allows you to send a string as a parameter and it will return an encrypted version of the string.

Here is my encryption function:

function encrypt($string) {
    $characters = str_split($string);
    foreach($characters as &$character) {
        $ascii = ord($character);
        $random = rand(0,9);
        if($ascii < 44) {
            $prefix = chr(rand(35,78));
            $letter = chr($ascii + $random);
        } else {
            $prefix = chr(rand(79,122));
            $letter = chr($ascii - $random);
        $r_ascii = [chr(rand(35,122)), chr(rand(35,122)), chr(rand(35,122))];
        $character = "{$prefix}{$random}{$r_ascii[0]}{$letter}{$r_ascii[1]}{$r_ascii[2]}";
    return implode("", $characters);

This will encrypt the string, whereas every character will become 6 characters. The 1st 2 of each character are keys that are required to decrypt the letter, and the 4th character is the actual character being encrypted except masked by a random digit (Basically the letter is converted to its ASCII number and a random number between 0-9 is added/subtracted from the letter). The 1st key (labeled prefix) lets the decrypt function know if the random number needs to be added or subtracted, the random number is passed as the 2nd character in the encryption, and characters 3, 5 and 6 are random noise characters.

Note: The prefix is generated depending on the ASCII number of the character that is being encrypted. If this ASCII number is below 44, the random number is always added to the character being encrypted, else it is always subtracted. The prefix itself is a character in a certain range, if the ASCII number is below 44, a random character between ASCII 35 and 78 is generated, any of these characters tell the decrypt function to subtract the random number from the encrypted character, else ASCII between 79 and 122 will always add the number.

For example, the string "Never roll your own encryption functions." may encrypt to:

s7uGsxW0ueMkX99m^Zr6E_3jP1cqJ_>67&KyX6jlX.k7@hb/m1BkFDQ94cD7<0: c$`9Zp3ot6*iHLW2.sSsm2YpZ,=00 4zW3Tl\ti5@r4ir2]l<791H!9'f3ebw0y8ef%1a7B\>)u2_pY)s4qu0-[1ZoRRv6)nIn\2kgx?n9df@&j8sfP8#9))p1z1JejRd9Hl(t[27l+9R5y^>GT0&tu\w2]gAif8ig;AZ3mkf@Q7Yl#/h86&np

Now, the decrypt function:

function decrypt($string) {
    $characters = str_split($string, 6);
    foreach($characters as &$character) {
        if(strlen($character) > 6) continue;
        $parts = str_split($character);
        if(ord($parts[0]) > 78) {
            $character = chr(ord($parts[3])+$parts[1]);
        } else {
            $character = chr(ord($parts[3])-$parts[1]);
    return implode("", $characters);

This function takes the encrypted string and breaks it into parts of 6 (Because every encrypted character is equal to 6 characters) and reverses all of the randomizations that I did during encryption to return the string:

Never roll your own encryption functions.

My question(s): What shortcomings will I have with these functions?

Another question I have is; how can these functions be improved?

  • 1
    \$\begingroup\$ @GrumpyCrouton: if you're interested in cryptography, give the cryptopals crypto challenges a try. Learning how to break ciphers will teach you much more than writing functions that produce random-looking strings. \$\endgroup\$ Commented Feb 1, 2018 at 13:04

1 Answer 1


The main shortcoming of this algorithm is that it relies solely on security through obscurity.

Since you save all information to reconstruct the plain-text string in the encrypted string, the only information keeping that encrypted string safe is the fact that an attacker has to know how to get the decrypted string from it. This is inherently unsafe.

As an attacker (who does not know the algorithm, but can use the encrypt function), one could note the following features:

  1. The encrypted string is always six times longer than the plain-text, so a good guess would be that each block of six characters encodes one character.
  2. The second character of that block is always a number, so it is probably not a function that transforms a single character to six random looking characters.
  3. At this point it becomes a game of finding correlations between the characters in the encrypted string and the plain text. A common strategy would be seeing which offset would be needed to get a certain character in the encrypted string. This would lead to the finding that the offset is actually in the encrypted string and your "encryption" is broken.
  • \$\begingroup\$ How do encryption functions _usually _ work? Isn't that always the case for encryption/decryption? (Not including hashing) - There has to be a way to decrypt it and I couldn't think of a way without some sort of key in the encryption itself. That's why I added as much noise and randomization as I could. \$\endgroup\$ Commented Jan 31, 2018 at 20:56
  • 2
    \$\begingroup\$ @GrumpyCrouton Normally you have a secret (a key), which you use to both encrypt and decrypt the plain-text. It is easier to keep a key secret (make it long enough and don't tell anyone) than keeping your algorithm secret (there are many ways to reverse-engineer code). \$\endgroup\$
    – Graipher
    Commented Jan 31, 2018 at 22:41
  • 2
    \$\begingroup\$ +1. Also note that the 'prefix' uses two ranges, and that the lower range is only used for spaces and certain punctuation characters, making it likely that word boundaries will stand out. Also, the filler characters are randomly distributed, but 'letter' is not. Even without being able to use encrypt, having access to a sufficient amount of encrypted messages should be enough to break this. \$\endgroup\$ Commented Feb 1, 2018 at 12:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.