LIBSODIUM decrypt data inside mysql query like did with AES_DECRYPT

删除回忆录丶 提交于 2019-12-08 06:53:05

问题


I have some sql querys where im selecting rows near to the users location. With AES_DECRYPT i could do inside the query:

AES_DECRYPT(lat, :key)

I need the decrypted value inside the query to:
1. order them
2. delimit entrys in a given area
3. and similar things for other querys

A short example of one query:

SELECT something,
(
    6371 * acos( cos( radians(".$userdatafromdbfetchedbefore['lat'].") ) * cos( radians( AES_DECRYPT(lat, :key) ) ) * cos( radians( AES_DECRYPT(lng, :key) ) - radians(".$userdatafromdbfetchedbefore['lng'].") ) + sin( radians(".$userdatafromdbfetchedbefore['lat'].") ) * sin(radians( AES_DECRYPT(lat, :key))) )
) AS distance
FROM 
    table
HAVING 
    distance <= ".$userdatafromdbfetchedbefore['maxrange']."
ORDER BY 
    e.orderdate 
DESC,
    distance  
ASC
LIMIT
    ".$start.", ".$offset."

I can't select all rows on a different query and manipulate the result with php, that would be very ineffiecient with 100k + rows while the rows near the user might be only ~100.

Its very important for me to keep location data encrypted, i did not start my project because of unsecure encryption until now.

Now my question is how i can do the same thing with newly php implemented Libsodium ?

I couldnt find one example that would work. I just found a example with blind index where you can find a value if you encrypt the search term same like the stored one, but that isnt helpful in my case because i need to get the value to run that through the distance formula inside the same query.


回答1:


Libsodium isn't built into MySQL, so you can't just call something equivalent to AES_ENCRYPT() from within a MySQL query and get the results you expect.

However, an alternate approach is to use a library like CipherSweet, which provides searchable authenticated encryption. Make sure you understand its features and limitations before deciding to use it.

<?php
use ParagonIE\CipherSweet\CipherSweet;
use ParagonIE\CipherSweet\EncryptedRow;
use ParagonIE\CipherSweet\Transformation\AlphaCharactersOnly;
use ParagonIE\CipherSweet\Transformation\FirstCharacter;
use ParagonIE\CipherSweet\Transformation\Lowercase;
use ParagonIE\CipherSweet\Backend\FIPSCrypto;
use ParagonIE\CipherSweet\KeyProvider\StringProvider;

$provider = new StringProvider(
    // Example key, chosen randomly, hex-encoded:
    'a981d3894b5884f6965baea64a09bb5b4b59c10e857008fc814923cf2f2de558'
);
$engine = new CipherSweet($provider, new FIPSCrypto());

/** @var CipherSweet $engine */
$row = (new EncryptedRow($engine, 'contacts'))
    ->addTextField('first_name')
    ->addTextField('last_name')
    ->addFloatField('latitude')
    ->addFloatField('longitude');

// Notice the ->addRowTransform() method:
$row->addCompoundIndex(
    $row->createCompoundIndex(
        'contact_first_init_last_name',
        ['first_name', 'last_name'],
        64, // 64 bits = 8 bytes
        true
    )
        ->addTransform('first_name', new AlphaCharactersOnly())
        ->addTransform('first_name', new Lowercase())
        ->addTransform('first_name', new FirstCharacter())
        ->addTransform('last_name', new AlphaCharactersOnly())
        ->addTransform('last_name', new Lowercase())
);

$prepared = $row->prepareRowForStorage([
    'first_name' => 'Jane',
    'last_name' => 'Doe',
    'latitude' => 52.52,
    'longitude' => -33.106,
    'extraneous' => true
]);

var_dump($prepared);

You should see something similar to this. The values in the [0] will change, but the values in [1] will not. This is becuase [0] contains the row data with (some fields encrypted). [1] only contains blind indexes (usable later in SELECT queries).

array(2) {
  [0]=>
  array(5) {
    ["first_name"]=>
    string(141) "fips:nrtzoaxvPIOA7jPskWVwJmC0q8WJqrsnqjPh3ifNPsRd2TAx6OwTDfSiMVCXSsSRNQb_nxJlW7TbAtf5UvQRWWKTGhk_kXxpZKdnTrpjbmxi0IgstSrZ126Qz6E0_lvjew0Ygw=="
    ["last_name"]=>
    string(137) "fips:98f5CLB24w0zSqCGPR0D2oq9wQvUwzxo_byAp6mKgMgoJkUHZX1oTtk4Cm8FXI7fsUI8HOG5sKQFGRn6cXMw1EOMGgpXZqiXEDb3jxEbg9s95d4g2NeVd4xs2tmX0xlZ0nSM"
    ["latitude"]=>
    string(145) "fips:d3TVGfnRFlvWxbfihgHqjpXlXU3HtkCAHzM0-4f1l5dAeQf2Vk5RDDVOGMQNM09r0O4UOAub6QTyHGezQ0bWKQ5omqoYCTBJE0Uf_2DSPfO7U4dG74phaP04iFgqpJ8G41q54Kv5t54="
    ["longitude"]=>
    string(145) "fips:IcnUnBZZOxJPYXk-F3v12O_krNb9JsexljiV4gJzgctTpxLFm7ql0tJRF7xP3wLrUtd1VyfYBf75ot7iOSIIIFqsuyKZQdI9UyKbqd87RTMsHbHgPouxgZBg1urlqpuWqbOYEFGiti4="
    ["extraneous"]=>
    bool(true)
  }
  [1]=>
  array(1) {
    ["contact_first_init_last_name"]=>
    array(2) {
      ["type"]=>
      string(13) "w6dsrxbathjze"
      ["value"]=>
      string(16) "546b1ffd1f83c37a"
    }
  }
}

Note that the floating point fields will always produce a fixed-length output, even if the inputs have varying levels of precision. This is done intentionally to prevent attackers from learning information from ciphertext length.

If you select ModernCrypto instead of FIPSCrypto, all of the above will be done with libsodium. The exact encryption used by each is documented here, if anyone is curious.


Note that you'll have to do your own calculations of the decrypted values in PHP rather than SQL.

After all, the whole point of encrypting data before storing it in a database is to hide it from the database server (and any attackers who could have compromised said server).



来源:https://stackoverflow.com/questions/52000755/libsodium-decrypt-data-inside-mysql-query-like-did-with-aes-decrypt

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!