How to get the fingerprint of a public key? - php

In PHP, I have a public key (already as an OpenSSL resource). I'd like to calculate that public keys fingerprint (SHA1 or other hash).
How do I do this?
PHP version is 7.2 or older.
EDIT: This is not a duplicate of the other question, because that question is about doing this for an SSH key with SSH (and related) commands. I want to do the same thing using PHP and the PHP-extension openssl.

I've found the solution myself. The basic idea:
Decode the base64 encoded part of the key in PEM format (after removing spaces from it)
Hash the resulting binary data.
In code (PHP):
function getPublicKeyFingerprint(string $pemEncodedKey, string $hashAlgorithm = 'sha1')
{
$keyWithoutPemWrapper = \preg_replace(
'/^-----BEGIN (?:[A-Z]+ )?PUBLIC KEY-----([A-Za-z0-9\\/\\+\\s=]+)-----END (?:[A-Z]+ )?PUBLIC KEY-----$/ms',
'\\1',
$pemEncodedKey
);
$keyDataWithoutSpaces = \preg_replace('/\\s+/', '', $keyWithoutPemWrapper);
$binaryKey = \base64_decode($keyDataWithoutSpaces);
return \hash($hashAlgorithm, $binaryKey);
}

if you need a hash php has multiple hashing functions available:
sha1() - https://php.net/manual/en/function.sha1.php
md5() - https://www.php.net/manual/en/function.md5.php
or use hash() if you need a more specific algorithm - see the docs

Related

Nodejs how to implement OpenSSL AES-CBC encryption (from PHP)?

I am currently working on translating an encryption algorithm from PHP to Typescript, to use in a very specific API that requires the posted data to be encrypted with the API key and Secret. Here is the provided example of how to correctly encrypt data in PHP for use with the API (the way of implementing the key and IV can't be changed):
$iv = substr(hash("SHA256", $this->ApiKey, true), 0, 16);
$key = md5($this->ApiSecret);
$output = openssl_encrypt($Data, "AES-256-CBC", $key, OPENSSL_RAW_DATA, $iv);
$completedEncryption = $this->base64Url_Encode($output);
return $completedEncryption;
In the above code, the only thing the base64Url_Encode function does is convert the binary data to a valid Base64URL string.
And now the code as I have implemented it inside Typescript:
import { createHash, createCipheriv } from 'node:crypto'
const secretIV = createHash('sha256').update(this.ApiKey).digest().subarray(0, 16)
// Generate key
/*
Because the OpenSSL function in PHP automatically pads the string with /null chars,
do the same inside NodeJS, so that CreateCipherIV can accept it as a 32-byte key,
instead of a 16-byte one.
*/
const md5 = createHash('md5').update(this.ApiSecret).digest()
const key = Buffer.alloc(32)
key.set(md5, 0)
// Create Cipher
const cipher = createCipheriv('aes-256-cbc', key, secretIV)
let encrypted = cipher.update(data, 'utf8', 'binary');
encrypted += cipher.final('binary');
// Return base64URL string
return Buffer.from(encrypted).toString('base64url');
The above Typescript code only does NOT give the same output as the PHP code given earlier. I have looked into the original OpenSSL code, made sure that the padding algorithms are matching (pcks5 and pcks7) and checked if every input Buffer had the same byte length as the input inside PHP. I am currently thinking if it is some kind of binary malform that is causing the data to change inside Javascript?
I hope some expert can help me out with this question. Maybe I have overlooked something. Thanks in advance.
The stupidity is in the md5 function in PHP, which defaults to hexadecimal output instead of binary output:
md5(string $string, bool $binary = false): string
This is also why the code doesn't complain about the key (constructed from the MD5 hash) is being too small, it is fed 32 bytes after ASCII or UTF8 encoding, instead of the 16 bytes you'd use for AES-128.
Apparently it is using lowercase encoding, although not even that has been specified. You can indicate the encoding for NodeJS as well, see the documentation of the digest method. It also seems to be using lowercase, although I cannot directly find the exact specification of the encoding either.
Once you have completed your assignment, please try and remove the code ASAP, as you should never calculate the IV from the key; they key and IV combination should be unique, so the above code is not IND-CPA secure if the key is reused.
In case you are wondering why it is so stupid: the output of MD5 has been specified in standards, and is binary. Furthermore, it is impossible from the function to see what it is doing, you have to lookup the code. It will also work very badly if you're doing a compare; even if you are comparing strings then it is easy to use upper instead of lowercase (and both are equally valid, uppercase hex is actually easier to read for humans as we focus on the top part of letters more for some reason or other).
Basically it takes the principle of least surprise and tosses it out of the window. The encoding of the output could be made optimal instead, the NodeJS implementation does this correctly.

in PHP, is it possible to decrypt a string which is encrypted by mcrypt_encrypt [duplicate]

Since mcrypt was deprecated in PHP 7.1 and I have a lot of data encrypted/decrypted with mcrypt in existing project, how to migrate my PHP code from mcrypt to OpenSSL? I have the following code to encrypt:
$encoded = base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, 'salt', 'source string', MCRYPT_MODE_ECB));
And decryption code is:
$source = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, 'salt', base64_decode('encoded string'), MCRYPT_MODE_ECB);
What openssl_ functions should I use in the above examples to get the same results without encoded data conversion?
Or the only way is to run a script which will decrypt all my stored encrypted data with mcrypt and encode with openssl?
Thanks
OpenSSL doesn't have the Rijndael-256 cipher; there's no equivalent - you'll have to decrypt and re-encrypt everything.
But also:
You're missing padding and authentication.
Don't use ECB mode.
"salt" is not a proper encryption key, nor is any regular string. Use random_bytes() to generate your keys, with the proper key length for the chosen algorithm.
All of the above can be summed up like this: don't do it on your own, use a well-vetted library like defuse/php-encryption.
Cryptography is no simple thing and you can't do it properly with just 5 lines of code.

Encrypt binary files with openssl_private_encrypt in php [duplicate]

I am trying to use the PHP function openssl_private_encrypt() to encrypt an uploaded file prior to saving it (see code snippet below), however it's bool is returning false and the encrypted content return is returning nothing. No errors are being displayed or reported.
$data = file_get_contents($_FILES['files']['tmp_name'][0]);
openssl_private_encrypt($data,$encrypted,$key);
$hash = sha1($encrypted);
file_put_contents('/path/to/folder/'.$hash,$encrypted);
Does anyone have any ideas as to why this isn't working?
Thanks
I'm not sure about PHP but in C/C++(OpenSSL) asymmetric encryption(RSA mainly) works on data with length less than the key size. And normally it is used to encrypt hash values. If you want to encrypt large(more the ~256 bytes)amount of data you'd better use some symmetric(block) cipher like AES or TriDES. Symmetric ciphers are much faster by the way.
PS Sorry I don't have enough reputation to put this post into comments.
You should proper initialize private key (http://pl1.php.net/manual/en/function.openssl-pkey-get-private.php)
$key = openssl_pkey_get_private ('file://path/to/file.pem');
$data = file_get_contents($_FILES['files']['tmp_name'][0]);
openssl_private_encrypt($data,$encrypted,$key);
$hash = sha1($encrypted);
file_put_contents('/path/to/folder/'.$hash,$encrypted);

PHP mcrypt to ColdFusion decrypt

I am working in a PHP app we have a particular string that we need to encrypt before storing in a database. I can do this in PHP with not problem using mcrypt with a key and a iv. Currently I'm trying to use blowfish because I thought it would be the most flexible as far as decrypting it in ColdFusion. The issue I ran into is it seems ColdFusion doesn't want to use the key or iv I encrypted with. ColdFusion wants you to generateSecretKey() and use some other way to create the iv.
What I can't seem to do is get the two to communicate. I tried first encrypting in coldFusion and using the key it generated and iv it used in PHP but the result was not what it should be. I know I must be missing something but I can't quite pinpoint what it might be.
<?php
$securedString = mcrypt_encrypt ('MCRYPT_BLOWFISH' , 'THISISMYKEYTHATISVERYLONG32CHARS' , "This is the string I need encrypted' , MCRYPT_MODE_CBC , '12345678');
echo base64_encode($securedString);
?>
So what would an equivalent ColdFusion Decryption call look like?
BTW: if Blowfish is not the ideal algorithm to use please feel free to suggest another as long as both ColdFusion and PHP can use it and it is secure.
Thanks,
Bruce
Something like this should work. You just need to share a common key between each.
In PHP:
base64_encode(mcrypt_encrypt(MCRYPT_3DES, $key, $plain_string, MCRYPT_MODE_ECB));
In Coldfusion:
<cfscript>
decrypted_string = decrypt(enc_string, key, "DESEDE", "Base64");
</cfscript>

sha1 in CodeIgniter?

What is difference in CodeIgniter sha1 and normal PHP sha1?
For example:
$codeigniter_hashed = $this -> encrypt -> sha1( "test" );
And
$normal_hashed = sha1("test");
Both will return same values.
Where does CodeIgniter uses encryption_key?
If your PHP installation doesn't have sha1 installed, you can use the CI version. If your PHP installation already has it, you don't need to use the CI function.
From the user guide:
$this->encrypt->sha1();
SHA1 encoding function. Provide a
string and it will return a 160 bit
one way hash. Note: SHA1, just like
MD5 is non-decodable. Example: $hash =
$this->encrypt->sha1('Some string');
Many PHP installations have SHA1
support by default so if all you need
is to encode a hash it's simpler to
use the native function: $hash =
sha1('Some string');
If your server does not support SHA1
you can use the provided function.
More info: http://codeigniter.com/user_guide/libraries/encryption.html
Pretty sure the function you show is a pure SHA encrypt - you only use a specific encryption_key if you want to key/encode the data so only you (the holder of the encryption key), will be able to decrypt it.
$encrypted_with_encryption_key = $this->encrypt->encode($var);
$encrypted_with_sha_no_enc_key = $this->encrypt->sha1($var);
the encryption key is saved at config/config.php
as
$config['encryption_key'] = 'some key';

Categories