2

When I was about 13 or 14 years old, I was a little interested in cryptography (which is, after all, an interesting field). I learnt quite a lot since that time (it has been about 8 years since then), but I'm still very far away from concidering myself an expert in cryptography.

Whatever, when I was at that age, I wrote this little perl-script which I just found on an old HD. (Saved as MyEncrypt.pm)

package MyEncrypt;

use strict;
use warnings;

my @_ALPHABET = ('a' .. 'z', 'A' .. 'Z', 0 .. 10, ' ');
my $_i = 0;
my %_ALPHABET = map { $_i++; $_ => $_i } @_ALPHABET;
$_i = 0;
my %_ALPHABET_REVERSE = map { $_i++; $_i => $_ } @_ALPHABET;

sub new {
    bless +{}, shift
}

sub set_password {
    my $self = shift;
    my $password = shift;
    $self->{hashed_password} = _hash_password($password);
    return $self;
}

sub encrypt {
    my $self = shift;
    my $input = shift;

    my $hashed_password = $self->{hashed_password};
    die "No password set.\n" unless $hashed_password;

    my @split = split(//, $input);

    my $output = shift;
    for (0 .. $#split) {
        my $new_number .= ($_ALPHABET{$split[$_]} + ($hashed_password ** ($_ + 1))) % $#_ALPHABET;
        $output .= $_ALPHABET_REVERSE{$new_number};
    }
    return $output;
}

sub _hash_password {
    my $password = shift;
    my $hash = 1;
    my $i = 1;
    for (split(//, $password)) {
        my $power = length($password) / (2 ** $i);
        $power = 1 if $power < 1;
        $hash *= int($_ALPHABET{$_} ** $power);
        $i++;
    }

    if(is_multiple_of_two($hash)) {
        $hash += 1;
    }

    while (length($hash) != 10) {
        no warnings;
        $hash *= $hash | join('', map { $_ALPHABET{$_} } split(//, $password));
        $hash =~ s/\.//g;
        $hash = substr($hash, 0, 10);
    }
    return $hash;
}

sub is_multiple_of_two {
    my $n = shift;
    my $log = log($n) / log(2);
    if($log == int($log)) {
        return 1;
    } else {
        return 0;
    }
}

1;

(It probably has the worst hashing-algorithm ever. I know).

This is my "test-program" for it:

use strict;
use warnings;
use MyEncrypt;

my $enc = MyEncrypt->new();
$enc->set_password('abc');
die $enc->encrypt("hello world");

My idea was this: We give it a password and it somehow generates a "hash" of it (here in a way that, I admit, I don't quite understand anymore. But hey: It has been 8 years since that... . For some reason, it should be 10 digits long and these are generated by, until the password is 10 digits long, multiplying the password with the OR'd characters of the alphabet (where a = 1, ... A = 27, ...) and then cutting it to 10 characters or less, until this leads to a "hash"), which is then later used for this letter-by-letter-substitution:

x = (number of the actual letter + password_hash to the power of (position of this character + 1)) modulo the size of the alphabet

and then x is used to look for the letter numbered x, which will be added to the output-string. When gone through all the text, the output will have a completely different form of what it had as input. And when one letter changes in the password, the whole string is different.

E.g.:

string: "hello world", pass: "abc" => 9bkpXY1H0oR
string: "hello world", pass: "abcd" => HS4gVkuWX4U
string: "hello world", pass: "abcda" => DhAqIeHn9cr

and so on.

Of course, the code is terrible, the hashing-algorithm is probably the worst one ever and the idea is not really new, but I came up with it myself and at that time I was quite proud of myself for this. But how secure would this have been? How much time would one need to decrypt this and how would this be done? As I've said, I developed in many fields, but for some reason after that script I did not care so much about cryptography anymore and my knowledge there is quite limited.

(Also, sadly: This is an incomplete version of that file. I'm not 100% sure, but I believe that I had somekind of decrypt-routine (though, this might be false. It might have been in another attempt), which seems lost. So I cannot even say whether this version of the algorithm could be decrypted in an easy way if you have the password. I didn't even notice this at first seeing this file again).

Thanks.

kono
  • 21
  • 2

1 Answers1

1

This would be trivial to attack if the code actually did what you intended and it was decryptable. (It doesn't though). You have to try all 63 (length of your alphabet) different values of the hashes modulo the alphabet size and then you can decrypt any message.

Essentially you shift each character by Hp+1 modulo 63, where H is the computed hash value. Now you should note mathematically that Hp mod N is the same as (H mod N)p mod N. So regardless of the fancy way of constructing the hash, there are only effectively 63 different hashes. You simply need to try all of them.

Granted this assumes that your code actually works and is decryptable, which it isn't at the moment.

For example, for pw="abc" the hash is 8486571168. Note perl doesn't do arbitrary precision math. So 8486571168**2 in perl is 7.20218901895289e+19 as is 8486571168**2 + $x for any value of $x from 0 to 63.

You can easily demonstrate this by using the same password ('abc') to encrypt say "hBROKEN1234" or "hNOTWORKING" (or anything else starting with an h) will always of which also go to "9bkpXY1H0oR". You could fix this by using a modular exponentiation function, at which point the attack described above could decrypt it by trying 63 different values of the hash.

dr jimbob
  • 38,768
  • 8
  • 92
  • 161
  • This question was [reposted from Code Review](http://codereview.stackexchange.com/questions/57969/how-easy-is-it-to-crack-this-encryption-algorithm). I suggest that you post your answer there. – Gilles 'SO- stop being evil' Jul 25 '14 at 08:09