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

Swift: detect the use of constant salts #10993

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

karimhamdanali
Copy link
Contributor

@karimhamdanali karimhamdanali commented Oct 26, 2022

Constant salts should not be used for password hashing. Data hashed using constant salts are vulnerable to dictionary attacks, enabling attackers to recover the original input.

The rule currently supports all ciphers that the CryptoSwift API provides, but we can always extend it further if more APIs are added.

I'd appreciate a review of the query itself, the accompanying tests, and the associated documentation.

@github-actions
Copy link
Contributor

github-actions bot commented Oct 26, 2022

QHelp previews:

swift/ql/src/queries/Security/CWE-760/ConstantSalt.qhelp

Constant salt

Constant salts should not be used for password hashing. Data hashed using constant salts are vulnerable to dictionary attacks, enabling attackers to recover the original input.

Recommendation

Use randomly generated salts to securely hash input data.

Example

The following example shows a few cases of hashing input data. In the 'BAD' cases, the salt is constant, making the generated hashes vulnerable to dictionary attakcs. In the 'GOOD' cases, the salt is randomly generated, which protects the hashed data against recovery.


func encrypt(padding : Padding) {
	// ...

	// BAD: Using constant salts for hashing
	let salt: Array<UInt8> = [0x2a, 0x3a, 0x80, 0x05]
	let randomArray = (0..<10).map({ _ in UInt8.random(in: 0...UInt8.max) })
	_ = try HKDF(password: randomArray, salt: salt, info: randomArray, keyLength: 0, variant: Variant.sha2)
	_ = try PKCS5.PBKDF1(password: randomArray, salt: salt, iterations: 120120, keyLength: 0)
	_ = try PKCS5.PBKDF2(password: randomArray, salt: salt, iterations: 120120, keyLength: 0)
	_ = try Scrypt(password: randomArray, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1)

	// GOOD: Using randomly generated salts for hashing
	let salt = (0..<10).map({ _ in UInt8.random(in: 0...UInt8.max) })
	let randomArray = (0..<10).map({ _ in UInt8.random(in: 0...UInt8.max) })
	_ = try HKDF(password: randomArray, salt: salt, info: randomArray, keyLength: 0, variant: Variant.sha2)
	_ = try PKCS5.PBKDF1(password: randomArray, salt: salt, iterations: 120120, keyLength: 0)
	_ = try PKCS5.PBKDF2(password: randomArray, salt: salt, iterations: 120120, keyLength: 0)
	_ = try Scrypt(password: randomArray, salt: salt, dkLen: 64, N: 16384, r: 8, p: 1)

	// ...
}

References

exists(ClassOrStructDecl c, AbstractFunctionDecl f, CallExpr call, int arg |
c.getFullName() = ["HKDF", "PBKDF1", "PBKDF2", "Scrypt"] and
c.getAMember() = f and
f.getName().matches("%init(%salt:%") and
Copy link
Contributor

@geoffw0 geoffw0 Oct 28, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks like a great start, my only concern is how often salts are specified in the wild using the functions modelled above. I did a quick MRVA query for parameters called "salt" (or similar) and the most common call that appears to be relevant is to a thing called CCKeyDerivationPBKDF(_:_:_:_:_:_:_:_:_:) from CommonCrypto. Do you think we should perhaps create a follow-up issue to add a model of that to this query as well?

Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants