1

I'm using the Key component of defuse/php-encryption to generate a secure key used as voucher codes. Key has a function to print the generated key as a ascii-safe string. The only issue in my use case is that it's quite long.

Is there any secure way to reduce the length of the key, avoiding possible collisions and making sure there's still randomness to the key so valid keys can't be guessed?

I'm looking at ending up with something like a 16 char key.

inquam
  • 12,664
  • 15
  • 61
  • 101
  • So the real problem is how to get a unique string that represents a voucher code, right? – N.B. Jul 18 '17 at 17:18
  • At this specific use case yes. But I'd like to know of a way to make this generic and for instance crate a secure 20 car string next time etc. defuse/php-encryption seems to be well built and something one can trust. But not being able to choose any kind of length of the generated key is a bit sad. (or I missed something) – inquam Jul 18 '17 at 17:20
  • They got their code right. What you're after is their crypto secure random generator `random_bytes` (I think PHP 7 hast that function at its core). Once you obtain random bytes of desired length, insert it into your database. Make that value `unique` so if the insert fails (due to duplicate), randomize again and re-insert again. Don't use crypto tools for random characters. – N.B. Jul 18 '17 at 17:23
  • In general if you have a sequence of random things (bits, characters, etc) you can pick any from any portion as each is individually random. This does not apply to encoded data such as hex, Base64, etc, which have a limited encoding set. – zaph Jul 18 '17 at 17:40
  • Take a look at [Laravel's Str helper](https://github.com/illuminate/support/blob/master/Str.php#L285) and corresponding helper function [str_random](https://github.com/illuminate/support/blob/master/helpers.php#L850). Use is `$str = str_random(16);`. No need to reinvent anything really, many people had the same problem and solved it. Just ensure you can't have duplicates in your database like I suggested and take a look at the code I linked. – N.B. Jul 18 '17 at 17:45
  • 1
    I smell an [XY problem](https://meta.stackexchange.com/q/66377/266187). I don't see why you would use a voucher code as a key which might decrypt something thing. – Artjom B. Jul 18 '17 at 18:43
  • They key component is used to just generate a cryptographicaly secure key, that key CAN be used when you encrypt using the library, but I don't reuse a generated key for those two different use cases. So just think of it like a secure generated sequence of characters with a fixed length. And the fixed part was what I wanted to get around. – inquam Jul 18 '17 at 18:46

1 Answers1

0

Is there any secure way to reduce the length of the key, avoiding possible collisions and making sure there's still randomness to the key so valid keys can't be guessed?

Theoretically, yes. Since the data is hex-encoded, a safe length reduction would look like this (using constant-time base64url encoding):

<?php
use ParagonIE\ConstantTime\Base64UrlSafe;
use ParagonIE\ConstantTime\Hex;

/** @var Defuse\Crypto\Key $key */

// To save a shorter key:
$saved = $key->saveToAsciiSafeString();
$shortened = Base64UrlSafe::encode(
    Hex::decode($saved)
);
var_dump($shortened);

// To restore the key:
$lengthened = Hex::encode(
    Base64UrlSafe::decode($shortened)
);
$restoredKey = Key::loadFromAsciiSafeString($lengthened);

However, this is a bit of an XY problem. Just store the key as-is and don't do anything dangerous.

Scott Arciszewski
  • 33,610
  • 16
  • 89
  • 206