Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for up to 256c passphrases, correct bitwise inversion in hashes #94

Merged
merged 2 commits into from
Feb 9, 2024

Conversation

gs-kamnas
Copy link
Contributor

This PR updates the password buffer size to support up to 256 character passwords (the maximum supported by Microsoft in any known NTLM implementation) as well as addresses the following 2 issues:

  • Hashes as generated and consumed have all bits complemented (making such disagree with all other NTHash implementations such as passlib). Therefore, this PR corrects this behavior however will require users using a pre-hashed password in config to recompute the hash.

  • Passwords remain in memory (per the referenced FIXME) even when no longer necessary; this change adds an explicit memory barrier after the memset to zero on the password buffer in an event to prevent the compiler from optimizing away the memset.

@fralken
Copy link
Collaborator

fralken commented Feb 2, 2024

  • Hashes as generated and consumed have all bits complemented (making such disagree with all other NTHash implementations such as passlib). Therefore, this PR corrects this behavior however will require users using a pre-hashed password in config to recompute the hash.

Hello, this is a good catch! Actually the error is not in the hashing function but rather in the hexadecimal representation of a number, that indeed was wrong.

Regarding setting memory to zero for password buffers, rather than using __asm__ volatile ("" ::: "memory"); maybe it is better to use memset_s as explained in this SonarCube report .

utils.c Outdated Show resolved Hide resolved
main.c Outdated Show resolved Hide resolved
@fralken
Copy link
Collaborator

fralken commented Feb 3, 2024

I just checked on Godbolt and apparently with clang the asm directive has no effect. Indeed it works with gcc. Also the memset_s function is not very portable as explained in Zero'ing memory, compiler optimizations and memset_s.

They suggest using a function like

void erase_memory(void *pointer, size_t size_data, size_t size_to_erase) {
	if(size_to_erase > size_data) size_to_erase = size_data;
	volatile unsigned char *p = pointer;
	while (size_to_erase--){
		*p++ = 0;
	}
}

where the volatile pointer should not be optimised away.

Copy link

sonarqubecloud bot commented Feb 7, 2024

@gs-kamnas
Copy link
Contributor Author

I just checked on Godbolt and apparently with clang the asm directive has no effect. Indeed it works with gcc. Also the memset_s function is not very portable as explained in Zero'ing memory, compiler optimizations and memset_s.

They suggest using a function like

void erase_memory(void *pointer, size_t size_data, size_t size_to_erase) {
	if(size_to_erase > size_data) size_to_erase = size_data;
	volatile unsigned char *p = pointer;
	while (size_to_erase--){
		*p++ = 0;
	}
}

where the volatile pointer should not be optimised away.

Interesting that clang handles as it does, therefore I have implemented a function that I'm calling "compat_memset_s" that uses your volatile pointer recommendation but should be otherwise API compatible to native memset_s; in case you later move to c11 with the not-so-portable stdlib extensions.

Appears to not be removed even when built with max optimizations(-O3): https://godbolt.org/z/T34Y8cr5n

@fralken fralken merged commit f2225c5 into versat:master Feb 9, 2024
11 of 12 checks passed
@gs-kamnas gs-kamnas deleted the long_pw branch February 9, 2024 19:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants