I'm trying to encrypt and decrypt files with php. The files should be asynchronously decrypted with pgp.
When I used the default gnupg-php-functions the encryption works well. I can decipher it on console. If I try to decipher it with php I always get an unspecific Exception: "decryption failed"
I've tried it also with different Keys. I also used an other library "singpolyma/openpgp-php".
Where could be the problem?
$sMessage = 'Huhu';
$recipient = 'test#email.com';
$sPassword = '1234';
// initialize PGP
putenv("GNUPGHOME=".__DIR__."/.pgp/");
$oPgp = new gnupg();
$oPgp->import($sPublicKey);
$oPgp->seterrormode(GNUPG_ERROR_EXCEPTION);
$oPgp->import($sPublicKey);
$oPgp->addencryptkey($recipient);
$ciphertext = $oPgp->encrypt($sMessage);
echo '<pre>'.$ciphertext.'</pre>';
file_put_contents('/tmp/ciphertext.gpg', $ciphertext);
// create new GnuPG object
$gpg = new gnupg();
$gpg->import($sPrivateKey);
// throw exception if error occurs
$gpg->seterrormode(gnupg::ERROR_EXCEPTION);
// ciphertext message
$gpg->adddecryptkey($recipient, $sPassword);
$plaintext = $gpg->decrypt($ciphertext);
echo '<pre>' . $plaintext . '</pre>';
I solved my Problem. It is caused by the changes in gnupg v2. Problem was the use of a key-password. It could be solved by configuring pgp for unattended password use. Have a look at "yougot#haxed.com"'s comment at phpt.net.
Related
I have an encrypted message in AES-128 CBC in this format "f21fcc6677c9ba2335da551fa143cf08" and I'm trying to decrypt using a key in this format "cdff8db86efb418a8e492a29dba44869", I'm new to this and I can't seem to make it work, I tried this code with no success.
<?php
$simple_string = base64_decode('f21fcc6677c9ba2335da551fa143cf08');
echo $simple_string. "\n";
//echo $simple_string;
$ciphering = 'AES-128-CBC';
$iv_length = openssl_cipher_iv_length($ciphering);
$options = 0;
$encryption_key = 'cdff8db86efb418a8e492a29dba44869';
echo $encryption_key. "\n";
$decryption = openssl_decrypt($simple_string, $ciphering, $encryption_key, OPENSSL_RAW_DATA);
var_dump($decryption);
my output is
bool(false)
any ideas? I think I have to change the format of the encrypted message or the key, but don't find much in Google.
I'm trying to encrypt a message using phpseclib. Below is the method that encrypts it:
function RSAEncrypt($data, $publicKey)
{
$rsa = new \Crypt_RSA();
$rsa->loadKey($publicKey);
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
$encryptedData = $rsa->encrypt($data);
$encodedData = base64_encode($encryptedData);
return $encodedData;
}
the code that encrypt message
$client_key = 123456789;
$random_str = rand();
$aes_password = $client_key.'-'.$random_str;
$public_key = file_get_contents('keys/public.xml');
$ecrypted_password = RSAEncrypt($aes_password, $public_key);
but no matter the message the $aes_password that i passed , the $ecrypted_password output is always
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAE= ◀"
I tried to decrypt it using the private key to see if its valid anyways but i always gets Decryption Error so i figured maybe the error is with the encryption
I try to decrypt my enrypted file(zip archive which contains multiple files) with Gnupg in php, but it constantly returns false. no exception or error message.
here's encryption:
$gpg = gnupg_init();
gnupg_seterrormode($gpg, GNUPG_ERROR_EXCEPTION);
// public key
$publicKey = file_get_contents('pubkey.pub');
$key = gnupg_import($gpg, $publicKey);
gnupg_addencryptkey($gpg, $key['fingerprint']);
// zip file
$zip = file_get_contents('myzip.zip');
$encryptedFile = gnupg_encrypt($gpg, $zip);
//save encrypted file
file_put_contents('myzip.zip.gpg', $encryptedFile);
here's decryption:
$gpg = gnupg_init();
$privateKey = file_get_contents('private.asc');
$key = gnupg_import($gpg, $privateKey);
gnupg_adddecryptkey($gpg, $key['fingerprint'], '12345');
$file = file_get_contents('myzip.zip.gpg');
$content = gnupg_decrypt($gpg, $file); // <- always returns false
I tried to decrypt the file with online tool. at first I tried to decrypt only 1 text file and it worked(it displayed the content of file). I tried to decrypt the zip archive as well
but everytime I try to decrypt it with gnupg_decrypt in php it return false. what am I doing wrong?
The problem was in gnupg version. I instilled gpg2 and it worked.
PHP code:
mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $to_encrypt, MCRYPT_MODE_ECB);
I need the corresponding powershell code which can produce the same result.
I have already tried ConvertTo-SecureString/ ConvertFrom-SecureString.
Powershell Code (Not producing correct encryption):
$api_code = "214e3854a1ec5433ae986d1e5d40c436"
$params = #{"controller" = $controller; "action"= $action; "all"= $TRUE; }
[Byte[]] $key = $api_code[0..$api_code.length]
$param_object = $params | ConvertTo-SecureString -AsPlainText -Force
$param_aes = $param_object | ConvertFrom-SecureString -key $key
The encrypted string is coming out different. Is there a parameter that I am missing? Or Is there another module?
As pointed out in the comments, SecureStrings have nothing to do with the Rijndael specification, and MCRYPT_RIJNDAEL_256 is not the same as AES256 (which refer Rijndael-128 with a 256-bit key)
So, to solve your problem, we just need a function to encrypt a plaintext in ECB cipher mode using Rijndael with a block size of 256.
For this, the obvious choice is the RijndaelManaged class. Fortunately, the MSDN documentation provides a basic but fully functional example of how to use the RijndaelManaged class and a CryptoStream to encrypt and decrypt strings - all we need to do is rewrite it in PowerShell and change the block size and cipher mode:
function Encrypt-Rijndael256ECB {
param(
[byte[]]$Key,
[string]$Plaintext
)
$RijndaelProvider = New-Object -TypeName System.Security.Cryptography.RijndaelManaged
# Set block size to 256 to imitate MCRYPT_RIJNDAEL_256
$RijndaelProvider.BlockSize = 256
# Make sure we use ECB mode, or the generated IV will fuck up the first block upon decryption
$RijndaelProvider.Mode = [System.Security.Cryptography.CipherMode]::ECB
$RijndaelProvider.Key = $key
# This object will take care of the actual cryptographic transformation
$Encryptor = $RijndaelProvider.CreateEncryptor()
# Set up a memorystream that we can write encrypted data back to
$EncMemoryStream = New-Object System.IO.MemoryStream
$EncCryptoStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList $EncMemoryStream,$Encryptor,"Write"
$EncStreamWriter = New-Object System.IO.StreamWriter -ArgumentList $EncCryptoStream
# When we write data back to the CryptoStream, it'll get encrypted and written back to the MemoryStream
$EncStreamWriter.Write($Plaintext)
# Close the writer
$EncStreamWriter.Close()
# Close the CryptoStream (pads and flushes any data still left in the buffer)
$EncCryptoStream.Close()
$EncMemoryStream.Close()
# Read the encrypted message from the memory stream
$Cipher = $EncMemoryStream.ToArray() -as [byte[]]
$CipherText = [convert]::ToBase64String($Cipher)
# return base64 encoded encrypted string
return $CipherText
}
The decryption process is almost the same, although this time we'll need to reverse it and read the cipher text back through the CryptoStream from the MemoryStream:
function Decrypt-Rijndael256ECB {
param(
[byte[]]$Key,
[string]$CipherText
)
$RijndaelProvider = New-Object -TypeName System.Security.Cryptography.RijndaelManaged
$RijndaelProvider.BlockSize = 256
$RijndaelProvider.Mode = [System.Security.Cryptography.CipherMode]::ECB
$RijndaelProvider.Key = $key
$Decryptor = $RijndaelProvider.CreateDecryptor()
# Reverse process: Base64Decode first, then populate memory stream with ciphertext and lastly read decrypted data through cryptostream
$Cipher = [convert]::FromBase64String($CipherText) -as [byte[]]
$DecMemoryStream = New-Object System.IO.MemoryStream -ArgumentList #(,$Cipher)
$DecCryptoStream = New-Object System.Security.Cryptography.CryptoStream -ArgumentList $DecMemoryStream,$Decryptor,$([System.Security.Cryptography.CryptoStreamMode]::Read)
$DecStreamWriter = New-Object System.IO.StreamReader -ArgumentList $DecCryptoStream
$NewPlainText = $DecStreamWriter.ReadToEnd()
$DecStreamWriter.Close()
$DecCryptoStream.Close()
$DecMemoryStream.Close()
return $NewPlainText
}
Usually, I use openssl_encrypt to encrypt simple string with AES in PHP, and it works pretty well.
Now I need to encrypt files with AES-256-CTR mode, but the only way to do this is to file_get_contents the entire content of the file and then send it to the openssl_encrypt function to encrypt the actual file data. The problem is this method is very "poor" because of the critical waste of memory.
1) Is there a way to work with chunked data with PHP OpenSSL ?
For example:
<?php
// ...
$f = fopen('large.iso','r');
while(feof($f)){
$chunk = fread($f,16);
$cipher = openssl_encrypt(...$chunk...);
// ... code ...
}
// ... more code ...
?>
2) openssl_encrypt official documentation is not published yet. Does someone could clarify the meaning of the parameters of the function for use with AES-CTR mode? Does the counter is handled automatically? Is it necessary to apply a manual XOR the data returned by the function?
Note: It is a professional project so I don't want to use phpseclib or others' "anonymous" libraries, nor do I don't want to use the command line as well.
Looks like for php it's not possible to use aes-256-ctr without temporary file.
But for next chiper types:
OPENSSL_CIPHER_RC2_40
OPENSSL_CIPHER_RC2_128
OPENSSL_CIPHER_RC2_64
OPENSSL_CIPHER_DES
OPENSSL_CIPHER_3DES
OPENSSL_CIPHER_AES_128_CBC
OPENSSL_CIPHER_AES_192_CBC
OPENSSL_CIPHER_AES_256_CBC
you can use generating key on the fly:
$res = openssl_pkey_new('chiper args here');
openssl_pkey_export($res, $private_key);
$public_key = openssl_pkey_get_details($res);
$public_key = $public_key["key"];
Then encrypt:
$crypted_text = openssl_get_privatekey($private_key,'your data');
And decrypt:
openssl_public_decrypt($crypted_text,$decrypted_text,$public_key);
So if you don't want to use files, may be switching to OPENSSL_CIPHER_AES_256_CBC will help you?
1) It should be something like this:
function strtohex($x) {
$s = '';
foreach (str_split($x) as $c){
$s.=sprintf("%02X", ord($c));
}
return($s);
}
$method = "aes-256-ctr"; //aes-256-cbc
echo "Selected method: ".$method."<br /><br />";
$textToEncrypt = "My chunk of data";
$iv = "1234567890123456";
$pass = 'some_pass';
$dec_iv = strtohex($iv);
$key = strtohex($pass);
$enc_data = openssl_encrypt($textToEncrypt, $method, $pass, true, $iv);
echo "Encrypted message (openssl): ".$enc_data."<br />";
$dec_data = openssl_decrypt($enc_data, $method, $pass, OPENSSL_RAW_DATA, $iv);
echo "Decrypted message (openssl): ".$dec_data."<br />";
For CTR $iv should be unique for each chunk or your data can be broken.
2) I know only abot difference betwen CBC and CTR:
For CBC, the IV must be random, but not unique. It also must not be known.
For CTR, the IV must be unique and not known, but does not need to be random.