For use onvif password must be encrypted in a certain kind. The method described in ONVIF Appicaltion Programmer's Guide on page 35. I also found how to do this in PHP, it looks like this:
$nonce = pack('H*', mt_rand());
$passdigest = base64_encode(pack('H*', sha1($nonce . pack('a*', timestamp) . pack('a*', password))));
The main problem is that I don't know how all that byte operations works, so I need some help to transfer this PHP code in to the python...
from: https://github.com/Pegax/pyOnvif
n64 = ''.join(SystemRandom().choice(string.letters + string.digits+string.punctuation) for _ in range(22))
nonce = base64.b64encode(n64)
#n64 = base64.b64decode(nonce)
pdigest= base64.b64encode(sha1(n64+created+self.password).digest())
Related
I have an app in vb.net and I want to store a password in my database that is understandable from PHP. The creation in PHP is like this:
$hash = password_hash("mypassword", PASSWORD_BCRYPT);
The result looks like this:
$hash = '$2y$07$BCryptRequires22Chrcte/VlQH0piJtjXl.0t1XkA8pw9dMXTpOq';
and the code in php to validate a password looks likethis
if (password_verify('mypassword', $hash)) {
echo 'Password is valid!';
} else {
echo 'Invalid password.';
}
How can I replicate this code
$hash = password_hash("mypassword", PASSWORD_BCRYPT);
iv VB.Net, so the results will match exactly?
In the php line, you provided, you use the bcrypt algorithm to hash the password.
This is a general hashing algorithm, not unique to php.
Im not very familar with VB.net, but this is what I found with a quick search:
' This example assumes the Chilkat API to have been previously unlocked.
' See Global Unlock Sample for sample code.
Dim crypt As New Chilkat.Crypt2
' The BCrypt cost factor (work factor) can be set to a value from 4 to 31.
' The default value is 10. We'll set it here explicitly to the default value
' to make this new property known. This line of code can be omitted
' if the default value of 10 is desired.
crypt.BCryptWorkFactor = 10
Dim bcryptHash As String = crypt.BCryptHash("mySecretPassword")
Debug.WriteLine("BCrypt hash = " & bcryptHash)
' Sample output:
' BCrypt hash = $2a$10$H5kIVktMGzAPKGKNAe9DVu0iwEqfhv/o4MMJ/Dzw/MPy1leOE9NOK
' Note: Your output will be different because the BCryptHash method
' automatically generates a random salt.
Hi there StackOverflow community,
After researching for countless of hours, I'm unable to find an explanation as to why my ouputs differ between javascript and my laravel application.
I could use input type hidden to make a post from my web browser, but that would defeat the purpose of having a secure client side processing and I fear that if I don't find the reason as to why this is happening, then decryption (which I plan to do through php) would not work either.
my php code is as follows:
$payload = "this is my plaintext";
$binary_signature = "";
$private_key = openssl_pkey_get_private(file_get_contents(storage_path('privatekey.pem')), 'enc123456789');
openssl_sign($payload, $binary_signature, $private_key, OPENSSL_ALGO_SHA256);
$signature = base64_encode($binary_signature);
$new_payload = $payload."&sign=".$signature; // where my actual plaintext is also used in my javascript code
$key = "thisismykey";
$iv = "\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0\x0";
$encryption = openssl_encrypt($new_payload, 'AES-256-CBC', $key,OPENSSL_RAW_DATA, $iv);
dd(base64_encode($encyrption));
which outputs the following:
AEyHK+4DQWYjw8GeVV3mfzUJtk7ylxZINeryAdFptEbDyKOVbmNg8z32J2JgxGpFsQKpXxWaqDLf0IPNIq1jof0rKWhhDpaWzvTd0Tq/zgze7oGtZzEIqtdRDqax3ZvPkzNfuO/O14iW/YTwFkm9FLy9kGIirZDUTuAcOIjXGCgxhrhZHLn+V6SZpW5dYnH8u5rPDCeez2/HkUPI71YjD6hZ0DRjIkiXCyjPYH4fjNykz4yXo8hD+489Zxm8QPq1O1dyjR9JXSdrlYMWdixt6w0vz8EtPC8gZ+bDP/N/UEK07M52VB693zYb5uD1u7WuUUtsOjkr5ocF6QbEW7sjzI4q9yAxqvxRW/bkKqodcVqtglW6YsdJjrTR0EfA/Or/QF3e3QWVM5/2g4rT3ccE17OP6Rp/46yTpW9lOgS6Qiz2hY95GoaxbLfHB/Vb0Es+UppwDu8bd/u2Qax5erBi5ObZu3AjKNpTem45paspsKH3/vc2Jc810XrVQPjnDdZ8VrXvCgPiulywn5Mj28O7uUQ5bay3Zxy3bmHb7ESDEVMKiSEoru3LzDJ7wwPlidJzPcfWtuiMEMsPOv1Y6LaxtlizWM5/zYJFX/RA4d+KBl+Rn6BoPZDcX/6eh3oUoNhy
My JS Code (the plaintext is received through an ajax call which has the same sign method as you see from the php code, the encryption plaintext is of the same value from my php code)
function encrypt(plaintext, secretkey) {
var randomSeed = "";
randomSeed = secretkey;
var key = CryptoJS.enc.Utf8.parse(randomSeed.toUpperCase());
var iv = CryptoJS.enc.Utf8.parse("0000000000000000");
var encrypt = {};
encrypt = CryptoJS.AES.encrypt(plaintext, key, {
mode : CryptoJS.mode.CBC,
iv : iv
});
console.log("encryption is "+encrypt.toString());
return encrypt.toString(encrypt.toString());
}
Returns the correct value which is:
jLmAUr+JyCjbpctU4z6+dlF61jbHRphwTS0iAk3IRiy3jkfCtaCSWdiIO0awuX6G1jAlZroTiAuMl9OW0zj0q4HitndfGFtFUoMMCqZTzvMr6cy1TyG9EFz20T6ByrBnOvGuoVjv3Flufuk2Ghz5in2W2A3T+wF+SPXX/bIAnHtE3uW0bPl2q5tn6KyUI1uoQaYcMZKRPyzAQS7WSSwSOmAcVrRuDANgZQuO+3mh86QAdeFaYqFdZUnxD4c2kkbkGy17SUFfSK8Qjv+8tkTcYXV9QRRdWjGZiQQeyAr3PDKA4SDVzrcMNwJjTaLJiZv0Iau66HGpbf2yvRDLtIOoXQmnhs6NKTZpcSwZ07hHqVvBZmNRq+jqZOGw1s8GRH+Bz4yxSRycTS0DEddhyMoxhZcUc5wt42vDOYIEH2nuw/uu4gjrwpx0rVO1ssoZYRxvBaA6zSC4N04Wdn4JE2/LtXertDLEdLBtmk3c3n4QDU0tK5v31HMY7P7+fdQXU62niVxCNPSt9dpYa82IUrQuigNXgrbphQvZNmmcONi/4pnxJjKcKYpCn/1KhkBVUAhYm6UKJJvMNAo0M+cfsvReImrJx6IzPRdzTTFAQF5kW2NFkV4EIb0DtCF679RtdAhg5ShaP7QhqYL6EgFCs9WnJTACC26TmV20DAqUiuIYULLtjDW4qFOWi/y8D1JOWTar
I don't understand why my PHP encryption is giving the wrong output while my JavaScript encryption is giving the correct output
I'm hoping someone could give me an insight as to what I'm doing wrong from my PHP side. Wha I'm hoping to achieve is that my PHP encryption will output the same result as my JavaScript encryption.
Thank you in advance :)
I have solved my issue.
To those having a similar issue, here's a brief explanation. Crypto JS uses the following:
var key = CryptoJS.enc.Utf8.parse(randomSeed.toUpperCase());
var iv = CryptoJS.enc.Utf8.parse("0000000000000000");
Which translates to a word array if you console log the output. PHP needs to have the similar word array value that cryptoJS produces for it's AES encryption method. To solve this, you have to convert your $key and iv to be in hex format and format your code in php such as:
$key = pack("H*", "4a424d56595753555047553830334d42505a314f414256414c5a565239324659");
$iv = pack("H*", "30303030303030303030303030303030");
Then when you proceed to using openssl_encrypt
$encrypted_data = openssl_encrypt($plaintext, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
you will get the same output as crpytoJS.
Hope this helps.
OK... to the point...
I have a e-mailshot program that sends out thousands of emails - each with str_replace() merge fields (fields that get replaced by a row value in a recordset).
One of the important parts is my ability to track those mails on open so I include a single server-side generated pixel...
<img src="http://...trace.php?email=<<<EMAIL>>>" alt="" height="1" width="1">
The str_replace() replaces <<<EMAIL>>> with a unique real email address.
The trace.php file reads the $_GET['email'] and either logs it or sends mail confirmation.
My issue is security :)
I want to use two-way encryption so that the $_GET variable sent in the URL is an encrypted email. The trace.php file then needs to decrypt it.
As it's being sent in a URL, It has to be in ASCII format otherwise it will corrupt before decrypting.
I can't use openssl_encrypt() & openssl_decrypt() and I'm having to work with php 5.2.0 (don't hurl abuse at me!).
Any help would be greatly appreciated!!
While many of the comments you have received offer other valid ways of solving the problem e.g. a table of email addresses with primary keys, I am of the position that the best way to solve the problem is the way you originally intended: including the email address encrypted in the query URL.
I feel that this way is better because:
Computing the email address does not require database access. Database bottle-necking is generally the biggest offender for high-latency requests.
Encryption means that the same email address will produce a different IV/ciphertext pair each time you encrypt it. Thus, if you send multiple emails at different times (say, for two different marketing campaigns), the URL will be different each time. This may not have an effect, but it does provide a security advantage in that an attacker can't "pretend" that an email has been opened simply by visiting a URL.
The issue is that for this way to be better, you have to do it well. I've included an excerpt in PHP from this repository below. If you can't use openssl_* then upgrade your PHP version. Do not, ever, use the mcrypt_ functions. They are deprecated for a reason. You may need to hex encode instead of base64 encode the email addresses as is done in the example below.
<?php
define("ALGORITHM_NAME", "aes-128-gcm");
define("ALGORITHM_NONCE_SIZE", 12);
define("ALGORITHM_TAG_SIZE", 16);
define("ALGORITHM_KEY_SIZE", 16);
define("PBKDF2_NAME", "sha256");
define("PBKDF2_SALT_SIZE", 16);
define("PBKDF2_ITERATIONS", 32767);
function encryptString($plaintext, $password) {
// Generate a 128-bit salt using a CSPRNG.
$salt = random_bytes(PBKDF2_SALT_SIZE);
// Derive a key.
$key = hash_pbkdf2(PBKDF2_NAME, $password, $salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE, true);
// Encrypt and prepend salt and return as base64 string.
return base64_encode($salt . encrypt($plaintext, $key));
}
function decryptString($base64CiphertextAndNonceAndSalt, $password) {
// Decode the base64.
$ciphertextAndNonceAndSalt = base64_decode($base64CiphertextAndNonceAndSalt);
// Retrieve the salt and ciphertextAndNonce.
$salt = substr($ciphertextAndNonceAndSalt, 0, PBKDF2_SALT_SIZE);
$ciphertextAndNonce = substr($ciphertextAndNonceAndSalt, PBKDF2_SALT_SIZE);
// Derive the key.
$key = hash_pbkdf2(PBKDF2_NAME, $password, $salt, PBKDF2_ITERATIONS, ALGORITHM_KEY_SIZE, true);
// Decrypt and return result.
return decrypt($ciphertextAndNonce, $key);
}
function encrypt($plaintext, $key) {
// Generate a 96-bit nonce using a CSPRNG.
$nonce = random_bytes(ALGORITHM_NONCE_SIZE);
// Encrypt and prepend nonce.
$ciphertext = openssl_encrypt($plaintext, ALGORITHM_NAME, $key, OPENSSL_RAW_DATA, $nonce, $tag);
return $nonce . $ciphertext . $tag;
}
function decrypt($ciphertextAndNonce, $key) {
// Retrieve the nonce and ciphertext.
$nonce = substr($ciphertextAndNonce, 0, ALGORITHM_NONCE_SIZE);
$ciphertext = substr($ciphertextAndNonce, ALGORITHM_NONCE_SIZE, strlen($ciphertextAndNonce) - ALGORITHM_NONCE_SIZE - ALGORITHM_TAG_SIZE);
$tag = substr($ciphertextAndNonce, strlen($ciphertextAndNonce) - ALGORITHM_TAG_SIZE);
// Decrypt and return result.
return openssl_decrypt($ciphertext, ALGORITHM_NAME, $key, OPENSSL_RAW_DATA, $nonce, $tag);
}
?>
I am getting an error while trying to send a soap request (soapCall) to the server.
Fatal error: Uncaught SoapFault exception: [ns1:InvalidSecurity] An error was discovered processing the <wsse:Security> header
I need to send the ws-security header
<wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken wsu:Id="UsernameToken-1" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<wsse:Username>userID</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">passwd</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">ZTQ3YmJjZmM1ZTU5ODg3YQ==</wsse:Nonce>
<wsu:Created>2013-07-05T19:55:36.458Z</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>
After a lot of research I think the issue I got is the nonce didnt meet the requirement. As I am making up the soap header looks like the example I got. The only unknown element is to calculating this nonce...
From the example nonce I got, its a set of 24 numbers + alphabet + special character
Something like this
ZTQ3YmJjZmM1ZTU5ODg3YQ==
But however, I am not too sure how do you calculate the wsse nonce from php...is there any standard?
the code I had
$nonce = sha1(mt_rand());
Result
dabddf9dbd95b490ace429f7ad6b55c3418cdd58
which is something completely different than the example...and I believe this is the reason why this code is not working.
So I am doing more research and now I am using this
$NASC = substr(md5(uniqid('the_password_i_am _using', true)), 0, 16);
$nonce = base64_encode($NASC);
Result
NzJlMDQ4OTAyZWIxYWU5ZA==
Now, it looks similar to the example but I still getting that error showed from the beginning.
Can someone give me a hand please?
some further testing with soapUI.
same userID and passwd, set the passwordtype to passwordtext
and it is working.
is anyone know how do the soapUI calculate the nonce? or have any idea how soapUI passing the ws-security?
try something like this
string usn = "MyUsername";
string pwd = "MyPassword";
DateTime created = DateTime.Now.ToUniversalTime();
var nonce = getNonce();
string nonceToSend = Convert.ToBase64String(Encoding.UTF8.GetBytes(nonce));
string createdStr = created.ToString("yyyy-MM-ddTHH:mm:ssZ");
string passwordToSend = GetSHA1String(nonce + createdStr + pwd);
and functions:
protected string getNonce()
{
string phrase = Guid.NewGuid().ToString();
return phrase;
}
protected string GetSHA1String(string phrase)
{
SHA1CryptoServiceProvider sha1Hasher = new SHA1CryptoServiceProvider();
byte[] hashedDataBytes = sha1Hasher.ComputeHash(Encoding.UTF8.GetBytes(phrase));
string test = Convert.ToString(hashedDataBytes);
return Convert.ToBase64String(hashedDataBytes);
}
As uniqid() is based on a Pseudo-Random Number Generator, it does not provide enough entropy. Siehe Insufficient Entropy For Random Values
$nonce = base64_encode( bin2hex( openssl_random_pseudo_bytes( 16 ) ) );
If you don't have the OpenSSL module try this fallback to mcrypt_create_iv() see:
https://github.com/padraic/SecurityMultiTool/blob/master/library/SecurityMultiTool/Random/Generator.php
Microsoft defines the WS-Security nonce as:
The nonce is 16 bytes long and is passed along as a base64 encoded value.
The following PHP code generates a code that follows the Microsoft .Net WS-Security Standard:
$prefix = gethostname();
$nonce = base64_encode( substr( md5( uniqid( $prefix.'_', true)), 0, 16));
Some testing with no $prefix was successful, but the production version of this code uses the $prefix with no authentication problems encountered so far. The original version of this nonce code came from the following library (with a modification to the number of characters to return in substr):
http://code.ronoaldo.net/openemm/src/e25a2bad5aa7/webservices/WSSESoapClient.php#cl-267
Using the blowfish cbc mode, I want to create an encrypted token. When I create the token and immediately decrypt it, it works correctly. However, if I place the encrypted token in SESSION and try to decrypt it during a subsequent request, the decryption produces garbage.
This is my code. I am using SESSION for testing; eventually, I'll be storing these strings in a database instead.
session_start();
define("key","v8nga4r76qlipm111jnioool");
define("iv",substr(md5(uniqid(rand(),1)),0,8));
require_once("Crypt/Blowfish.php");
$str = "Blowfish_test";
// encode start!!
$blowfish = Crypt_Blowfish::factory("cbc", key, iv);
$encrypt = $blowfish->encrypt($str);
$encrypt64 = base64_encode($encrypt);
$_SESSION["test"] = $encrypt64;
So far, everything is correct. If, on the same request, I immediately decode it (from SESSION), the results are as expected:
// decode start!!
$blowfish = Crypt_Blowfish::factory("cbc", key, iv);
$decrypt64 = base64_decode($_SESSION["test"]);
$decrypt = $blowfish->decrypt($decrypt64);
$trim_decrypt = rtrim($decrypt, "\0");
echo "Before encryption : " . $str ."<br>";
echo "Encrypted string   : " .$encrypt64. "<br>";
echo "decrypted string   : " .$trim_decrypt. "<br>";
If I place only the second block of code on a different page (so a previously generated string is being decrypted), the decrypted string is garbage.
Encryption -> session["test"] -> Decryption --- no problem
session["test"] -> Decryption --- problem
What's happening here?
I'm sorry for this super delay.
I solved this problem by the comment at that time, so I close this question using community wiki.
--- add ---
problem is solved
// encode
// At the same time save the initialization vector
$_SESSION["test"] = $encrypt64;
$_SESSION["iv"] = iv;
--- other file ---
// decode
$blowfish = Crypt_Blowfish::factory("cbc", key, $_SESSION["iv"]);