Need help converting this PHP sha256 hashing code to swift (iOS) - php

I need to convert this pice of PHP code to swift to create hashes, I am using a hash pattern in PHP to hash 2 strings with SHA256 and I would like to do this in swift, any ideas?
The SELF::SECRET is a secret key, and the SELF::HASH_PATTERN is my pattern and looks something like this: "00101010011100001010"
public function hash($first, $second) {
// Append the secret to the values.
$first = self::SECRET . $first;
$second = $second . self::SECRET;
// Hash the values.
$hash = hash_init('sha256');
hash_update($hash, $first);
$hash1 = hash_final($hash);
$hash = hash_init('sha256');
hash_update($hash, $second);
$hash2 = hash_final($hash);
// Create a new hash with pieces of the two we just made.
$result = '';
for ($i = 0; $i < strlen(self::HASH_PATTERN); $i++) {
$result .= substr(self::HASH_PATTERN, $i, 1) ? $hash2[$i] : $hash1[$i];
}
return $result;
}
Thanks!
UPDATE:
This is the part which I can't figure out:
$hash = hash_init('sha256');
hash_update($hash, $first);
$hash1 = hash_final($hash);
UPDATE:
After a few hours of doing research and coding I finally got it figured out.
This is the code that I wrote, maybe not the best, but it works :)
I used a small class from github for generating SHA256 strings in swift called NSHash
func create_token(first:String, second:String) -> String {
var newFirst = constants.secret + first as NSString
var newSecond = second + constants.secret as NSString
var hash1 = newFirst.SHA256()
var hash2 = newSecond.SHA256()
var result = ""
for var i = 0; i < countElements(constants.hash_pattern); i++ {
var character = "\(constants.hash_pattern[i])" as String
var number:Int = character.toInt()!
if number == 1 {
result = "\(result)\(hash2[i])"
}else {
result = "\(result)\(hash1[i])"
}
}
return result
}

Related

How to decrypt this CryptoJS encryption in PHP (function provided)

(Please note that the function I reference from the provided answer didn't work so I want to modify it to make it work or please provide a suitable solution to AES encryption in VueJS and decryption in PHP (or Laravel))
I have a password will be sent to Laravel API so I managed to encrypt and base64 it then send it to Laravel API. Here's the original encryption
And here's the encryption and encoding
var encryptedPassword = CryptoJS.AES.encrypt("123456", "Secret Passphrase");
const replacerFunc = () => {
const visited = new WeakSet();
return (key, value) => {
if (typeof value === "object" && value !== null) {
if (visited.has(value)) {
return;
}
visited.add(value);
}
return value;
};
};
let jsonString = JSON.stringify(encryptedPassword, replacerFunc());
let bs46encoded = btoa(unescape(encodeURIComponent(JSON.stringify(jsonString, replacerFunc()))))
I get this result
IntcIiRzdXBlclwiOntcIiRzdXBlclwiOnt9fSxcImNpcGhlcnRleHRcIjp7XCJ3b3Jkc1wiOlsxODQ4NTYxMTAzLDE1MjkyNDgyMTUsLTEwODg3MTk1MDEsLTEyNjAyOTYzNjJdLFwic2lnQnl0ZXNcIjoxNn0sXCJrZXlcIjp7XCIkc3VwZXJcIjp7fSxcIndvcmRzXCI6Wy0yODA5NjkxMjcsNzAzNjYxOTM0LDE1Mjg5OTYxNDEsLTEwOTU5OTQ2MDYsLTY4OTMyOTM1NiwtNDQ1MDc3MjE3LC0yMDM4MDY1MTUxLC0xNzI0MjIzMzE4LC0xNTk1Nzk5MDI5LDgxOTY1NjMwMSwtMTQzNTIxMDg2NCwxODkwMDcyNTc5XSxcInNpZ0J5dGVzXCI6MzJ9LFwiaXZcIjp7XCJ3b3Jkc1wiOlstMTU5NTc5OTAyOSw4MTk2NTYzMDEsLTE0MzUyMTA4NjQsMTg5MDA3MjU3OV0sXCJzaWdCeXRlc1wiOjE2fSxcImFsZ29yaXRobVwiOntcImtleVNpemVcIjo4LFwiJHN1cGVyXCI6e1wiY2ZnXCI6e1wibW9kZVwiOntcIiRzdXBlclwiOnt9LFwiRW5jcnlwdG9yXCI6e30sXCJEZWNyeXB0b3JcIjp7fX0sXCJwYWRkaW5nXCI6e30sXCIkc3VwZXJcIjp7fX0sXCJibG9ja1NpemVcIjo0LFwiJHN1cGVyXCI6e1wia2V5U2l6ZVwiOjQsXCJpdlNpemVcIjo0LFwiX0VOQ19YRk9STV9NT0RFXCI6MSxcIl9ERUNfWEZPUk1fTU9ERVwiOjIsXCIkc3VwZXJcIjp7XCJfbWluQnVmZmVyU2l6ZVwiOjB9fX19LFwiYmxvY2tTaXplXCI6NCxcImZvcm1hdHRlclwiOnt9LFwic2FsdFwiOntcIndvcmRzXCI6WzE5NDk1NjcxNjIsMjExODc0MjAyOF0sXCJzaWdCeXRlc1wiOjh9fSI=
In laravel
$objString = base64_decode($ecodedString);
And I get
"{\"$super\":{\"$super\":{}},\"ciphertext\":{\"words\":[-1208966431,415513002,-380428285,-1848403568],\"sigBytes\":16},\
"key\":{\"$super\":{},\"words\":[1997420112,-1528658502,-601329304,170123410,85401029,1271916135,-1899682466,856024313,-1926693888,505524620,1922976396,79922502],\"sigBytes\":32},
\"iv\":{\"words\":[-1926693888,505524620,1922976396,79922502],\"sigBytes\":16},\"algorithm\":{\"keySize\":8,\"$super\":{\"cfg\":{\"mode\":{\"$super\":{},\"Encryptor\":{},\"Decryptor\":{}},\"padding\":{},\"$super\":{}},\"blockSize\":4,\"$super\":{\"keySize\":4,\"ivSize\":4,\"_ENC_XFORM_MODE\":1,\"_DEC_XFORM_MODE\":2,\"$super\":{\"_minBufferSize\":0}}}},\"blockSize\":4,\"formatter\":{},
\"salt\":{\"words\":[3335652791,3193595722],\"sigBytes\":8}}"
Then
$this->cryptoJsAesDecrypt("Secret Passphrase", $objString);
public function cryptoJsAesDecrypt($passphrase, $jsonString){
$jsondata = json_decode($jsonString, true);
Log::alert("jsondata");
Log::alert($jsondata);
$salt = hex2bin($jsondata["salt"]);
$ct = base64_decode($jsondata["ct"]);
$iv = hex2bin($jsondata["iv"]);
$concatedPassphrase = $passphrase.$salt;
$md5 = array();
$md5[0] = md5($concatedPassphrase, true);
$result = $md5[0];
for ($i = 1; $i < 3; $i++) {
$md5[$i] = md5($md5[$i - 1].$concatedPassphrase, true);
$result .= $md5[$i];
}
$key = substr($result, 0, 32);
$data = openssl_decrypt($ct, 'aes-256-cbc', $key, true, $iv);
Log::alert("data");
Log::alert($data);
return $data;
}
$jsondata returns
{"$super":{"$super":{}},"ciphertext":{"words":[-1208966431,415513002,-380428285,-1848403568],"sigBytes":16},
"key":{"$super":{},"words":[1997420112,-1528658502,-601329304,170123410,85401029,1271916135,-1899682466,856024313,-1926693888,505524620,1922976396,79922502],"sigBytes":32},
"iv":{"words":[-1926693888,505524620,1922976396,79922502],"sigBytes":16},"algorithm":{"keySize":8,"$super":{"cfg":{"mode":{"$super":{},"Encryptor":{},"Decryptor":{}},"padding":{},"$super":{}},"blockSize":4,"$super":{"keySize":4,"ivSize":4,"_ENC_XFORM_MODE":1,"_DEC_XFORM_MODE":2,"$super":{"_minBufferSize":0}}}},"blockSize":4,"formatter":{},
"salt":{"words":[3335652791,3193595722],"sigBytes":8}}
But can't get other variables correctly to decrypt this encryption and find the original plain text. How can I edit this function to make it work?
I try to clone this answer Encryption in JavaScript and decryption with PHP

Kotlin(Android) MD5 checking with PHP Signature

I been working on this for days.
Our backend have a signature checking which is done using PHP:
private $HMAC_ALGO = 'md5';
public function decodeAndValidateMessage($data,$signature,$secretkey) {
if (!is_string($data)) {
throw new InvalidRequestException($data);
}
$decodedData = base64_decode($data);
// if not json returned the throw exception...
$jsonDecoded = json_decode($decodedData,true);
if (!$jsonDecoded) {
throw new InvalidRequestException($decodedData);
}
// validate
$signatureRef = base64_encode(hash_hmac($this->HMAC_ALGO,$decodedData,$secretkey,true));
if ($signature === $signatureRef) {
return $jsonDecoded;
} else {
throw new InvalidSignatureException();
}
}
I made it work on iOS:
func hmac(_ algorithm: HMACAlgorithm, key: String) -> String {
let cKey = key.cString(using: String.Encoding.utf8)
let cData = self.cString(using: String.Encoding.utf8)
var result = [CUnsignedChar](repeating: 0, count: Int(algorithm.digestLength()))
CCHmac(algorithm.toCCHmacAlgorithm(), cKey!, Int(strlen(cKey!)), cData!, Int(strlen(cData!)), &result)
let hmacData:Data = Data(bytes: UnsafePointer<UInt8>(result), count: (Int(algorithm.digestLength())))
let hmacBase64 = hmacData.base64EncodedString(options: NSData.Base64EncodingOptions(rawValue: 0))
print(String(hmacBase64))
return String(hmacBase64)
}
Any idea/help on doing this on Kotlin/Android? I'm being stuck on InvalidSignatureException error.
fun generateSignature(data : HashMap<String, Any>) : String {
val hmac = Mac.getInstance("HmacMD5")
hmac.init(SecretKeySpec(Constant.PRIVATEKEY.toByteArray(Charsets.UTF_8), hmac.algorithm))
return Base64.encodeToString(data.toString().toByteArray(),Base64.URL_SAFE + Base64.NO_PADDING + Base64.NO_CLOSE + Base64.NO_WRAP)
}
Thanks :D I really appreciate for any help :D
Update:
Just to make my question simpler?
Is it possible to make translate the iOS line of code to Kotlin?
enum HMACAlgorithm {
case md5, sha1, sha224, sha256, sha384, sha512
func toCCHmacAlgorithm() -> CCHmacAlgorithm {
var result: Int = 0
switch self {
case .md5:
result = kCCHmacAlgMD5
case .sha1:
result = kCCHmacAlgSHA1
case .sha224:
result = kCCHmacAlgSHA224
case .sha256:
result = kCCHmacAlgSHA256
case .sha384:
result = kCCHmacAlgSHA384
case .sha512:
result = kCCHmacAlgSHA512
}
return CCHmacAlgorithm(result)
}
func digestLength() -> Int {
var result: CInt = 0
switch self {
case .md5:
result = CC_MD5_DIGEST_LENGTH
case .sha1:
result = CC_SHA1_DIGEST_LENGTH
case .sha224:
result = CC_SHA224_DIGEST_LENGTH
case .sha256:
result = CC_SHA256_DIGEST_LENGTH
case .sha384:
result = CC_SHA384_DIGEST_LENGTH
case .sha512:
result = CC_SHA512_DIGEST_LENGTH
}
return Int(result)
}
}
this is how I call the function
var params : Dictionary
params.generateSignature()
fun generateSignature(data : HashMap) : String {
val hmac = Mac.getInstance("HmacMD5")
hmac.init(SecretKeySpec(Constant.PRIVATEKEY.toByteArray(Charsets.UTF_8), hmac.algorithm))
return Base64.encodeToString(data.toString().toByteArray(),Base64.URL_SAFE + Base64.NO_PADDING + Base64.NO_CLOSE + Base64.NO_WRAP)
}
Someone finally found out the answer.
My mistake is hashmap should be run under JSONObject
var obj = JsonObject(data)
and use obj.toString() :D

check symfony, fos-user encrypted password with nodejs

I need to validate a password in a Symfony 3.3 / FriendsOfSymfony UserBundle 1.3 application from an AWS Lambda function.
The relevant password hashing code in Symfony is here https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Security/Core/Encoder/MessageDigestPasswordEncoder.php#L52
However the code doesn't produce the same hashes even at the first line.
In Symfony with password=test, salt=asLZCFQJ5flTtOWdphjKtpngthjK6h2FtMRSIZZ2bus
$salted = $this->mergePasswordAndSalt($raw, $salt);
$digest = hash($this->algorithm, $salted, true);
//base64_encode($digest) == '2QhirHmPwt0O5MrtTdfWsWKCCeOQO/y02Di04/aUIJxWhdNDQSGCaUuL1ONLUasdsD88CBSIzGwsePqGTCcQmA=='
// "stretch" hash
for ($i = 1; $i < $this->iterations; ++$i) {
$digest = hash($this->algorithm, $digest.$salted, true);
}
With the same details in nodejs I get:
var pass='test';
var salt='asLZCFQJ5flTtOWdphjKtpngthjK6h2FtMRSIZZ2bus';
var salted = pass + '{' + salt + '}';
var digest = sha512.update(salted).digest('binary');
//new Buffer(digest).toString('base64') == 'w5kIYsKsecKPw4LDnQ7DpMOKw61Nw5fDlsKxYsKCCcOjwpA7w7zCtMOYOMK0w6PDtsKUIMKcVsKFw5NDQSHCgmlLwovDlMOjS1HCqx3CsD88CBTCiMOMbCx4w7rChkwnEMKY'
for (var i = 1; i < 5000; ++i) {
digest = require('crypto').createHash('sha512').update(digest + salted).digest('binary');
process.stdout.write(new Buffer(digest).toString('base64')+"\n");
}
or is this a character encoding problem? The first 3 characters of the binary hash look very similar in the debuggers.
Screenshot from PHPStorm
Screenshot from WebStorm
Finally i figured it out, hope it can help someone in the future.The issue comes from characters contact.
./middleware/passwordEncode.js:
const cryptoLib = require('crypto');
const encryptPassword = (password:any, salt:any) => {
let salted = password + '{' + salt + '}';
if (!salt){
salted = password;
}
let digest = cryptoLib.createHash('sha512').update(salted).digest('binary');
for (let i = 1; i < 5000; i++){
digest = cryptoLib.createHash('sha512').update( Buffer.concat([Buffer.from(digest, 'binary'), Buffer.from(salted, 'utf8')]) ).digest('binary');
}
return ( Buffer.from(digest, 'binary')).toString('base64');
}
module.exports.encryptPassword = encryptPassword;
./middleware/passwordDecode.js:
const passwordEncode = require('../middleware/passwordEncode')
const verifyPassword = (password:any, salt:any, encoded:any) => {
return encoded === passwordEncode.encryptPassword(password,salt);
}
module.exports.verifyPassword = verifyPassword
I have resolved this by switching the encryption method to bcrypt. This answer describes how to check the resulting password:https://stackoverflow.com/a/26643637/123594

Method works on C++ but how to reproduce the same in PHP?

I have the following code on c++
std::string Battlenet::AccountMgr::CalculateShaPassHash(std::string const& name, std::string const& password)
{
SHA256Hash email;
email.UpdateData(name);
email.Finalize();
SHA256Hash sha;
sha.UpdateData(ByteArrayToHexStr(email.GetDigest(), email.GetLength()));
sha.UpdateData(":");
sha.UpdateData(password);
sha.Finalize();
return ByteArrayToHexStr(sha.GetDigest(), sha.GetLength(), true);
}
std::string ByteArrayToHexStr(uint8 const* bytes, uint32 arrayLen, bool reverse /* = false */)
{
int32 init = 0;
int32 end = arrayLen;
int8 op = 1;
if (reverse)
{
init = arrayLen - 1;
end = -1;
op = -1;
}
std::ostringstream ss;
for (int32 i = init; i != end; i += op)
{
char buffer[4];
sprintf(buffer, "%02X", bytes[i]);
ss << buffer;
}
return ss.str();
}
I'm trying to reproduce the same result on PHP, and what i did so far:
public function RegisterBattleNetAccount($email, $password)
{
$GLOBALS['mysqli']->query("use {$GLOBALS['db_auth']}");
//strtoupper
$pass = hash('sha256', strrev(strtoupper(hash('sha256', $email))).':'.$password);
$pass = strtoupper(strrev($pass));
$email = strtoupper($email);
$stmt = $GLOBALS['mysqli']->prepare("INSERT INTO battlenet_accounts (`email`,`sha_pass_hash`) VALUES (?, ?)");
$stmt->bind_param("ss", $email, $pass);
$stmt->execute();
}
Results:
C++: 09FEBAB417CF2FA563AC89963519CCAC53D5F556F8BF20D7EEB818A0584A514E
PHP: 4e514a58a018b8eed720bff856f5d553accc19359689ac63a52fcf17b4bafe09
what i can do to obtain the same result as C++?
If you look closely, you'll see that (case notwithstanding) the two results are the same except that each hex couple is written in reverse order.
Your C++ version is called with reverse as true; so, simply don't do that!
(Then make the casing consistent between the two programs.)

Python socket recv (client-side)

i have to connect to an api via socket and send / recv some data.
the company send me a php-example-file with this code for reading data from the socket:
function readAnswer() {
$size = fgets($this->socketPtr, 64);
$answer = "";
$readed = 0;
while($readed < $size) {
$part = fread($this->socketPtr, $size - $readed);
$readed += strlen($part);
$answer .= $part;
}
return $answer;
}
This works for me. But in python i get from times to times an error.
not everything from the socket is recv.
my python try looks like this:
def read_answer(self,the_socket,timeout=0.5):
the_socket.setblocking(0)
total_data=[]
data=''
begin=time.time()
while 1:
if total_data and time.time()-begin > timeout:
break
elif time.time()-begin > timeout*2:
break
try:
data = the_socket.recv(8192)
if data:
total_data.append(data)
begin=time.time()
else:
time.sleep(0.1)
except:
pass
return ''.join(total_data)
i recv data as a dict / array. and from time to time i only get a int (msg length i think)
so what would be a better way to read the data from socket.
ah the api sends the data in a correct way, i checked this. it's only this little function ;(
After using the code below (thanks falsetru) and added a readed=len(data) i run into another problem:
this is the working php code:
function _parse_answer($answerData)
{
$result = array();
$lines = explode("\n", $answerData);
$data = explode("&", $lines[0]);
foreach($data as $piece)
{
$keyval = explode("=", $piece, 2);
$result[$keyval[0]] = $keyval[1];
}
for($i=1;$i<count($lines);$i++)
{
$result["csv"][]=$lines[$i];
}
return $result;
}
and this my crappy python code:
def parse_answer(self,data):
#print "dd_demo_api: answer: (%s)" % (data)
if data:
result = {}
lines = data.split("\n")
index_list = 0
if len(lines) == 1:
index_list = 0
else:
index_list = 1
pieces = lines[index_list].split("&")
for x in pieces:
keyval = x.split("=")
result[keyval[0]] = keyval[1]
iterlines = iter(lines)
next(iterlines)
next(iterlines)
count = 1
result["csv"] = {}
for x in iterlines:
result["csv"][count] = x.split(";")
return result
else:
return 0
i think here is some optimization required? ;(
Python version does not do the same thing with PHP version.
Try following code:
def read_answer(self, sock):
size = int(sock.recv(64).strip().rstrip('\0'))
# Above is not exactly same as `fgets`.
# If that causes an issue, use following instead.
#
# f = sock.makefile('r')
# size = int(f.readline(64).rstrip('\0'))
#
# and replace `sock.recv(n)` with `f.read(n)` in the following loop.
total_data = []
readed = 0
while readed < size:
data = sock.recv(size - readed)
if data:
total_data.append(data)
readed += len(data)
return b''.join(total_data)

Categories