rsk82
rsk82

Reputation: 29437

is this xor based encryption function safe?

What I tried to do here is create a function that will encrypt the same input into completely different output every time it is called. The base of this function is xor, but to prevent easy spotting of repetitive patterns in string. I added random hashing based on time and portion of a string to self-verify on decription.

All I ask for is if I made any kind of errors here that could reveal hidden text to experienced person without doing a brute force on the string. (I know that php has a module just for encryption but this is a poor mans version in case encryption module is not available.) Second: I do not ask you to rewrite this functions or to write something for me, what I ask is for a simple guidance what I have done wrong. I know that one possible security breach is that I use salsa by default, which is all zeros for empty string, but advantage is that this is the longest hash available in php, and second, what fool will use empty password to protect their data ?

function crapt($str,$pass,$hmac = false,$meth = 'salsa20') {
   $hash = pack('H*',($hmac===false) ? hash($meth,$pass) : hash_hmac($meth,$pass,$hmac));
   $str = gzdeflate($str,9);
   $tmphash = pack('H*',sha1(sin(microtime(1))));
   $str = $tmphash.((string)$str ^ (string)str_repeat($tmphash,strlen($str)/strlen($tmphash)+1));
   $str .= pack('H*',sha1($str));
   return (string)$str ^ (string)str_repeat($hash,strlen($str)/strlen($hash)+1);
}

function decrapt($str,$pass,$hmac = false,$meth = 'salsa20') {
  $hash = pack('H*',($hmac===false) ? hash($meth,$pass) : hash_hmac($meth,$pass,$hmac));
  $str = (string)$str ^ (string)str_repeat($hash,strlen($str)/strlen($hash)+1);
  $check = substr($str,-20);
  $str = substr($str,0,strlen($str)-20);
  if(pack('H*',sha1($str))!==$check) return false;
  $tmphash = substr($str,0,20);
  $str = substr($str,20);
  return gzinflate((string)$str ^ (string)str_repeat($tmphash,strlen($str)/strlen($tmphash)+1));
}

var_dump(decrapt(crapt('sometext','secretpassword'),'secretpassword'));

Upvotes: 3

Views: 1544

Answers (3)

Giacomo Verticale
Giacomo Verticale

Reputation: 656

Your algorithms operates in blocks of length strlen($hash)==strlen($tmphash). EDIT: wrong, but see below.

In the ciphertext, the first of such blocks is equal to ($tmphash XOR $hash). The following ones are each equal to (a_block_of_plaintext XOR $tmphash XOR $hash).

The first block of ciphertext is the key to your data. Just xor the ciphertext with a repetition of the first block of the ciphertext and you get the plaintext. No password needed.

I'm not a PHP programmer, so perhaps I'm missing something, but a practical attack would not be much different from this.

As a general rule only use professional grade crypto modules. If they are not available, then your application is not secure.

EDIT: by rereading the question I noticed that $hash and $tmphash have different lengths. $hash is 512 bit and $tmphash is 160 bit. However this does not change the basic idea; since the least common multiple of 512 and 160 is 2560, the blocks synchronize every 2560 bits. Therefore you are able to decipher only the first 160 bit of every 2560-bit block.

Upvotes: 7

Brian Stinar
Brian Stinar

Reputation: 1109

My php is not great and I'm a dude with one semester's worth of crypto, so by no means an expert. When evaluating the strength of a crypto system, one typically assumes an adversary has full access to your algorithm and implementation.

I see the line:

 $tmphash = pack('H*',sha1(sin(microtime(1))));

and I think that this is your key. Like I said, my PHP is pretty bad, so please correct me if I am wrong.

If the php sha1 function returns 40-bit hex number, this gives you a key space of WEP. The last time I checked, WEP can be cracked in about 3 minutes. I'm not totally sure if this is based on inherent vulnerabilities in the protocol through information leakage, or if this is because of a super small keyspace. However, 16^40 doesn't seem like a big enough key space for cryptographic security.

Additionally, based on this, all I would need to know is an approximate time that a user generated this request and you would greatly reduce the key space you need to search through. If the microtime() method in php actually gives you the current microseconds since the epoch, this would reduce my key search space from whatever 16^40 (php output ofsha1?) to the number of microseconds in the time frame I feel confident your user received this data from you. I could write a cracker that would run through this keyspace from the time I feel most confident at (the time I sniffed the packet) and back off from there until I hit some sort of a threshold.

You can always play the game of "my algorithm is a secret", but most security professionals I know don't really feel like that is a very valid argument (or a fun game to play). These are just two arguments a dude with a very basic education came across that only address your keyspace.

Don't implement anything like this yourself. It's a bad idea. If you are writing toy programs for a class it's cool, but if this is for any sort of production system whatsoever, I highly recommend using a tried and true cryptosystem.

-Brian J. Stinar-

Upvotes: 3

Nick Johnson
Nick Johnson

Reputation: 101149

Any cipher you invent yourself will undoubtedly have vulnerabilities - and if those of us on Stack Overflow can't detect it, that doesn't mean someone else won't. The first rule of cryptography is not to invent your own: use existing ciphers, and where possible, well known and tested implementations. If you absolutely can't use a standard library, implement an existing cipher, such as TEA - or better, find an existing implementation in your language of choice.

Upvotes: 13

Related Questions