emqx/emqx-auth-mongo

Mongo plugin working well with sha256, but not able to make it work with sha256 and a salt

gmgershon opened this issue · 6 comments

Using emqttd 2.3.11.

The Mongo plugin is working correctly for us for authentication and ACLs using a simple sha256 hash.

We would prefer to use a salt option from the start since it would not be possible to do so subsequently without retaining the plain-text passwords.

We don't know if this is a problem with our calculations or is a bug in the plugin.

We changed the conf file to specify sha256,salt instead of just sha256.

We populated the mongo record salt field with the hex representation of a 32 byte salt.

We have tried several variations of computing the password hex value but none has worked. Perhaps we are not properly concatenating the password and the salt before calculating the sha256 of the result. We tried concatenating the hex strings, concatenating the plaintext password and the salt, as well as concatenating byte arrays, before calculating the sha256 hex representation for the target password field. None worked.

So, what are the steps expected by emq's mongo plugin to produce the hashed password field?

Could someone provide a simple plaintext password (e.g. "xyz") and a corresponding working pair of salt and password fields that we could use to test our Java hashing algorithm? This would clearly determine if the problem is in the plugin or our code.

Perhaps the answers could be added to the plugin documentation for others.

Thanks!

Could someone provide a simple plaintext password (e.g. "xyz") and a corresponding working pair of salt and password fields that we could use to test our Java hashing algorithm? This would clearly determine if the problem is in the plugin or our code.

Here is an example:
password_hash = sha256,salt
plain password: "sha256"
salt: “salt”
hash: "e586e489b1c0338b9bcfadc4572c271df669533c8035e02c09a0c58ddb48df63"

We have tried several variations of computing the password hex value but none has worked. Perhaps we are not properly concatenating the password and the salt before calculating the sha256 of the result. We tried concatenating the hex strings, concatenating the plaintext password and the salt, as well as concatenating byte arrays, before calculating the sha256 hex representation for the target password field. None worked.

Please concatenate with byte arrays. If password_hash = sha256,salt, salt should be appended to the password. If password_hash = salt,sha256, salt should be prepended to the password

@ngjaying - Thank you for the advice and example.

With your assistance, we found our problem which was using the underlying bytes of a generated salt, rather than the bytes of the hex representation of the generated salt.

Using Apache Commons Codec, a Java solution is trivial. We packaged some example code and results that may be useful for others.

/**
	Example sha256 hash password digest, as well as sha256 hash of password with salt digest
	
	Utilizes Apache Commons Codec https://commons.apache.org/proper/commons-codec/
	
	Copyright 2018 Intermedia Sciences, LLC
	
	Licensed under the Apache License, Version 2.0 (the "License");
	you may not use this file except in compliance with the License.
	You may obtain a copy of the License at
	
	    http://www.apache.org/licenses/LICENSE-2.0
	
	Unless required by applicable law or agreed to in writing, software
	distributed under the License is distributed on an "AS IS" BASIS,
	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
	See the License for the specific language governing permissions and
	limitations under the License.
*/

import java.security.SecureRandom;

import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;

public class SecurityHashGenerator {
	
	private void hash(String passwordAsText, String saltProvidedAsText) {
		
		// Plain text password
		System.out.printf("\n\nPassword plain text        '%s'", passwordAsText);
		
		// Simple sha256 of password without using salt (equivalent to an empty salt)
		String passwordSha256HashAsHex = DigestUtils.sha256Hex(passwordAsText);
		System.out.printf("\nPassword-only sha256 hash  '%s'", passwordSha256HashAsHex);
		
		// If salt is provided then use it, otherwise generate a salt hex string from 32 random bytes
		String saltAsText = saltProvidedAsText;
		if (saltProvidedAsText.length() == 0) {
			SecureRandom rng = new SecureRandom();
			byte seed[] = new byte[32];
			rng.nextBytes(seed);
			saltAsText = Hex.encodeHexString(seed);
		}
		System.out.printf("\nSalt plain text            '%s'", saltAsText);

		// Result with salt appended to password (vs prepended)
		String result = DigestUtils.sha256Hex(passwordAsText + saltAsText);
		System.out.printf("\nPassword with salt sha256  '%s'", result);
		
	}

	public static void main(String[] args) {
		SecurityHashGenerator hasher = new SecurityHashGenerator();
		hasher.hash("sha256", "salt");
		hasher.hash("sha256", "");
	}
}

And results with a provided as well as a generated salt:

Password plain text        'sha256'
Password-only sha256 hash  '5d5b09f6dcb2d53a5fffc60c4ac0d55fabdf556069d6631545f42aa6e3500f2e'
Salt plain text            'salt'
Password with salt sha256  'e586e489b1c0338b9bcfadc4572c271df669533c8035e02c09a0c58ddb48df63'

Password plain text        'sha256'
Password-only sha256 hash  '5d5b09f6dcb2d53a5fffc60c4ac0d55fabdf556069d6631545f42aa6e3500f2e'
Salt plain text            '064bff32ea37ff12829d4da144c5606f5d09a1393321b3c8c71c5eb6abcd2220'
Password with salt sha256  '68215cbde3acdd9b9d58aea404613639105bb2ac4a622a045c1a24b1a0feb181'

We are clearly now able to compute a correct sha256 password using our generated salt, but are not able to get the sha256,salt option to work using the Mongo plugin.

The sha256,salt option doesn't work for us even using the supplied example values for a user:

{ 
    "_id" : ObjectId("5bea29a20da5a88e20e45160"), 
    "username" : "mr1-rpi5", 
    "password" : "e586e489b1c0338b9bcfadc4572c271df669533c8035e02c09a0c58ddb48df63", 
    "salt" : "salt", 
    "is_superuser" : false, 
    "created" : "2018-11-12T18:40:39Z"
}

Looking at the source code and auth config it's not clear where the "salt" field is being accessed.

@gmgershon

auth.mongo.auth_query.password_field = password,salt

@turtleDeng

Thanks! Now working!

@gilbert-wong
This undocumented solution should be added as a comment in the etc/emqx_auth_mongo.conf template.

The document has been add as a comment.