LibSodium functions return unreadable characters - php

I am following along with a tutorial on encryption: https://php.watch/articles/modern-php-encryption-decryption-sodium. In working with the Sodium extension I'm just baffled by a few things. Googling is returning frustratingly little help. (Most of the results are just duplications of the php.net/manual.)
1. In various articles I'm reading, the result of sodium_crypto_*_encrypt() is something familiar:
// ex. DEx9ATXEg/eRq8GWD3NT5BatB3m31WED
Whenever I echo it out myself I get something like:
// ex. 𫦢�2(*���3�CV��Wu��R~�u���H��
which I'm certain won't store correctly on a database. Nowhere in the articles or documentation does it mention anything about charset weirdness. I can throw a header('Content-Type: text/html; charset=ISO-8859-1') in there, but I still get weird characters I'm not certain are right since I'm not finding any threads talking about this:
// ex. ÑAÁ5eŠ…n#±'ýÞÃ1è9ÜÈ̳¬"CžãÚ0ÿÛ
2. I can't find any information about the best practice for storing keys or nonces.
I just figured this obvious-to-security-folks-but-not-to-others bit of information would be a regularly discussed part of articles on keygens and nonces and such. Seeing as both my keygen and nonce functions (at least in the Sodium library) seem to return non-UTF-8 gibberish, what do I do with it? fwrite it out to a file to be referenced later? Pass it directly to my database? Copy/pasting certainly doesn't work right with it being wingdings.
Other than these things, everything else in the encryption/decryption process makes complete sense to me. I'm far from new to PHP development, I just can't figure this out.

Came across https://stackoverflow.com/a/44874239/1128978 answering "PHP random_bytes returns unreadable characters"
random_bytes generates an arbitrary length string of cryptographic random bytes...
And suggests to use bin2hex to get readable characters. So amending my usages:
// Generate $ciphertext
$message = 'This is a secret message';
$key = sodium_crypto_*_keygen();
$nonce = random_bytes(SODIUM_CRYPTO_*BYTES);
$ciphertext = sodium_crypto_*_encrypt($message, '', $nonce, $key);
// Store hexadecimal versions of binary output
$nonce_hex = bin2hex($nonce);
$key_hex = bin2hex($key);
$ciphertext_hex = bin2hex($ciphertext);
// When ready to decrypt, convert hexadecimal values back to binary
$ciphertext_bin = hex2bin($ciphertext_hex);
$nonce_bin = hex2bin($nonce_hex);
$key_bin = hex2bin($key_hex);
$decrypted = sodium_crypto_*_decrypt($ciphertext_bin, '', $nonce_bin, $key_bin);
// "This is a secret message"
So making lots of use of bin2hex and hex2bin, but this now makes sense. Effectively solved, though not confident this is the proper way to work with it. I still have no idea why this isn't pointed out anywhere in php.net/manual nor in any of the articles/comments I've been perusing.

Related

SHA-1 base32 of a file report back to a string

I'm having troubles figuring out how to implement a program that I can generate a base32 sha-1 value of a file. I know it can't be too difficult to figure out as to generate a standard sha1 file is fairly easy.
$file1 = sha1_file('main.jpg');
Any help would be appreciated.
If you want to encode the SHA1 value as Base32, you gonna have to either write that yourself or find a library. PHP does not have it built-in, like it does with base64_encode.
A while ago, I needed a base32_encode function, so I wrote one. I don't know how efficient it is, and I'm sure better ones exist out there, but it does work. It's located here: https://github.com/NTICompass/PHP-Base32
Using that you can do:
<?php
include 'Base32.php';
$base32 = new Base32;
$file1 = sha1_file('main.jpg');
echo $base32->base32_encode($file1);
I have a PHP class, Base2n, which can encode Base32 per RFC 4648. It's actually more flexible than that, allowing you to parametrically define many standard and non-standard encoding schemes with a 2n base.
https://github.com/ademarre/binary-to-text-php
Base32 is demonstrated in the first example of the README file.
Here's what your "main.jpg" example would look like:
// include, require, or autoload Base2n
$file1 = sha1_file('main.jpg', TRUE);
$base32 = new Base2n(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567', FALSE, TRUE, TRUE);
$base32FileHash = $base32->encode($file1);
Notice that I also set $raw_output=TRUE in the call to sha1_file(). I assume this is what you want because otherwise the Base32 output would be done on the hexadecimal representation of the SHA-1 hash digest, not the raw 160-bit digest itself.

Charset detection in PHP

//i've added a new take on this please see Cheating PHP integers . any help will be much appreciated. I've had an idea to trying and hack the storage option of the arrays by packing the integers into unsigned bytes (only need 8 or 16 bits integers to reduce the memory considerably).
Hi
I'm currently working on custom charset detection libraries and created a port from Mozilla's charset detection algorithm and used chardet (the python port) for a helping hand. However, this is extremely memory intensive in PHP (around 30mb of memory if I just load in Western language detection). I've optimised all I can without rewriting it from scratch to load each piece (this would reduce memory but make it a lot slower).
My question is that, do you know of any LGPL PHP libraries that do charset detection?
This would be purely for research to give me a slight guiding hand in the right direction.
I already know of mb_detect_encoding but it's far too limited and brings up far too many false positives with the text files i have (yet python's chardet detects them perfectly)
I created a method which encodes correctly to UTF-8. But it was hard to figure out what is currently encoded so I came to this solution:
<?php
function _convert($content) {
if(!mb_check_encoding($content, 'UTF-8')
OR !($content === mb_convert_encoding(mb_convert_encoding($content, 'UTF-32', 'UTF-8' ), 'UTF-8', 'UTF-32'))) {
$content = mb_convert_encoding($content, 'UTF-8');
if (mb_check_encoding($content, 'UTF-8')) {
// log('Converted to UTF-8');
} else {
// log('Could not converted to UTF-8');
}
}
return $content;
}
?>
As you can see I do a conversion to check if it still the same (UTF-8/16) and if not convert it. Maybe you can use some of this code.
First of all, interesting project you are working on! I'm curious how the end product will be.
Have you take a look at the ICU project already?

RSA Decrypted Data Corrupt

My script uses openssl_private_decrypt() to decrypt a string encrypted with RSA in another program. Currently it writes to a file. But when I try to open it up in a text editor, it says it can't detect the encoding. If I try to echo it, nothing appears. If I output it's length, I get 256, instead of the correct 3.
I know the decryption is done right because using the cat terminal command on the output file gives the correct data.
$ cat decrypted.txt
It looks like this is a character encoding problem, a problem I hear can give a lot of pain in PHP. I even tried utf8_encode(). What might the problem be?
Here's the code:
$results = '';
openssl_private_decrypt(
base64_decode(
<<<EOS
QWlG+AZIt9GE0hw0wwcPRtUWueMLBxj3YWpa5zQBoz1ttnt7TvlxDtYWZcvaUL/qr2CJCADE2iTR
G72FhAwew2fhqlqmsxL7Nns3yegflTTMXyilVM3mPU4Cx94ylLfa+ZrqrNEepaRorNJ/js5iTq9i
avegO/kYOv4zhEsZirlk/Mj0vVv6irWo8WyZoCDC2SwfGWeSUI8F4pq4FUkRh9V/0zAUZ+3P0A7Z
SrA80dSa6U/J+poRcmE1vRLQXvM8dBtFRKmb0zfltLUBMcMhcglzAhcpemJ99OCZmUuynFRcRNkj
CkOLsO+lSHntcbmXqsKE+of78gnU3tp5hHSHIg==
EOS
),
$results,
openssl_pkey_get_private(
// load private key
),
OPENSSL_NO_PADDING
);
echo $results;
The fact that you're getting decrypted data exactly the length of a single block instead of the length of your expected data is really, really pointing towards a padding problem.
Make sure you're using the same padding flag on both sides.
I'm not familiar with openssl_private_decrypt, but it seems logical to me that you would provide base64_encode()'d data to openssl_private_encrypt().
In such case, you're mangling your data by running in the wrong order on decrypt.
Seems like you would want to decrypt the string first, then run base64_decode() on the unencrypted string.

How to convert torrent info hash for scrape?

I have a torrent hash from the magnet link. For example: fda164e7af470f83ea699a529845a9353cc26576
When I try to get information about leechers and peers I should request: http://tracker.publicbt.com/scrape?info_hash=???
How should I convert info hash for this request? Is it url encoding or becoding? how? In PHP.
It's a raw hexadecimal representation. Use pack() with H to convert it. Then URL encode it.
Got this python snippet from a colleague,
r = ''
s = 'fda164e7af470f83ea699a529845a9353cc26576'
for n in range(0, len(s), 2):
r += '%%%s' % s[n:n+2].upper()
print r
Output: %FD%A1%64%E7%AF%47%0F%83%EA%69%9A%52%98%45%A9%35%3C%C2%65%76
Works like a charm.
Edit: Works like a charm for getting the tracker to give back status 200 (ok) but still doesn't work for retrieving the torrent details...
In case someone is having trouble and comes across this thread in the future: the trick to this whole issue is to use the bool $raw_output argument of the PHP: sha1 function, setting it to "true".
The BDecode/DEncode classes can be found HERE. This project, called Trackon, also includes many other helpful classes to interact with torrent trackers and files.
So, in PHP, something like this will work to obtain the correct info hash for scraping the tracker for details:
include('./path/to/BDecode.php');
include('./path/to/BEncode.php');
function getHash($torFile){
$tfile = BDecode(file_get_contents($torFile));
$infohash = sha1(BEncode($tfile["info"]), TRUE);
return urlencode($infohash);
}
Then merely call it like so:
$hash = getHash('./path/to/.torrent');
Hope this helps someone out there. I was still scratching my head after reading many posts about how to obtain the correct info hash. I understand why this wasn't mentioned anywhere now though, this argument was added in PHP 5. If you're not running PHP 5, you will have to convert the sha1 hash to raw binary after you calculate it.

How to encrypt a string in Python and decrypt that same string in PHP?

I have a string that I would like to encrypt in Python, store it as a cookie, then in a PHP file I'd like to retrieve that cookie, and decrypt it in PHP. How would I go about doing this?
I appreciate the fast responses.
All cookie talk aside, lets just say I want to encrypt a string in Python and then decrypt a string in PHP.
Are there any examples you can point me to?
Use a standard encryption scheme. The implementation is going to be equivalent in either language.
RSA is available (via third party libraries) in both languages, if you need asymmetric key crypto. So is AES, if you need symmetric keys.
There is a good example here:
http://www.codekoala.com/blog/2009/aes-encryption-python-using-pycrypto/
Other links that may help:
http://www.phpclasses.org/browse/package/4238.html
http://www.chilkatsoft.com/p/php_aes.asp
If you're not talking about encryption but encoding to make sure the contents make it through safely regardless of quoting issues, special characters, and line breaks, I think base64 encoding is your best bet. PHP has base64_encode / decode() out of the box, and I'm sure Python has, too.
Note that base64 encoding obviously does nothing to encrypt your data (i.e. to make it unreadable to outsiders), and base64 encoded data grows by 33%.
Well, my first thought would be to use a web server that uses SSL and set the cookie's secure property to true, meaning that it will only be served over SSL connections.
However, I'm aware that this probably isn't what you're looking for.
Although a bit late. Find sample code below using the Fernet library
#Python Code - fernet 1.0 library
from cryptography.fernet import Fernet
key = b"Gm3wFh9OiQHcVc8rcAMm8IOqKOJtk7CbrGRKVhrvXhg="
f = Fernet(key)
token = f.encrypt(b'the quick brown fox jumps over the lazy hare')
print(token)
##gAAAAABiMWVPsStLo42ExcmIqcGvRvCCmnhB5B6dc2JsOm4w-VsE9oJOuk_qYuZvHv5quQR4t_6ZjNJzAdCiDPOtESNzCreJZLwc2X-_apbqKKnBwc3KhmqL-K5X7t1uR1WXuyUEYUtW
<?php
//PHP - kelvinmo/fernet-php v1.0.1 A
require 'vendor/autoload.php';
use Fernet\Fernet;
$key = "Gm3wFh9OiQHcVc8rcAMm8IOqKOJtk7CbrGRKVhrvXhg=" ;
$fernet = new Fernet($key);
$token = "gAAAAABiMWVPsStLo42ExcmIqcGvRvCCmnhB5B6dc2JsOm4w-VsE9oJOuk_qYuZvHv5quQR4t_6ZjNJzAdCiDPOtESNzCreJZLwc2X-_apbqKKnBwc3KhmqL-K5X7t1uR1WXuyUEYUtW";
echo $fernet->decode($token);
?>

Categories