diff --git a/python/ql/lib/experimental/cryptography/CryptoAlgorithmNames.qll b/python/ql/lib/experimental/cryptography/CryptoAlgorithmNames.qll index 937b45b7aacc..1a641c0071e6 100644 --- a/python/ql/lib/experimental/cryptography/CryptoAlgorithmNames.qll +++ b/python/ql/lib/experimental/cryptography/CryptoAlgorithmNames.qll @@ -104,9 +104,9 @@ predicate isSymmetricEncryptionAlgorithm(string name) { predicate isKeyDerivationAlgorithm(string name) { name = [ - "ARGON2", "CONCATKDF", "CONCATKDFHASH", "CONCATKDFHMAC", "KBKDFCMAC", "BCRYPT", "HKDF", - "HKDFEXPAND", "KBKDF", "KBKDFHMAC", "PBKDF1", "PBKDF2", "PBKDF2HMAC", "PKCS5", "SCRYPT", - "X963KDF", "EVPKDF" + "ARGON2", "ARGON2D", "ARGON2I", "ARGON2ID", "CONCATKDF", "CONCATKDFHASH", "CONCATKDFHMAC", + "KBKDFCMAC", "BCRYPT", "HKDF", "HKDFEXPAND", "KBKDF", "KBKDFHMAC", "PBKDF1", "PBKDF2", + "PBKDF2HMAC", "PKCS5", "SCRYPT", "X963KDF", "EVPKDF" ] } diff --git a/python/ql/lib/experimental/cryptography/CryptoArtifact.qll b/python/ql/lib/experimental/cryptography/CryptoArtifact.qll index e8939c981113..ac34ab27a166 100644 --- a/python/ql/lib/experimental/cryptography/CryptoArtifact.qll +++ b/python/ql/lib/experimental/cryptography/CryptoArtifact.qll @@ -135,6 +135,10 @@ abstract class KeyDerivationOperation extends CryptographicOperation { DataFlow::Node getHashConfigSrc() { none() } + DataFlow::Node getLanesConfigSrc() { none() } + + DataFlow::Node getMemoryCostConfigSrc() { none() } + // TODO: get encryption algorithm for CBC-based KDF? DataFlow::Node getDerivedKeySizeSrc() { none() } @@ -147,6 +151,10 @@ abstract class KeyDerivationOperation extends CryptographicOperation { abstract predicate requiresHash(); + abstract predicate requiresLanes(); + + abstract predicate requiresMemoryCost(); + //abstract predicate requiresKeySize(); // Going to assume all requires a size abstract predicate requiresMode(); } diff --git a/python/ql/lib/experimental/cryptography/modules/CryptographyModule.qll b/python/ql/lib/experimental/cryptography/modules/CryptographyModule.qll index 0831d625d803..f3e87da603f8 100644 --- a/python/ql/lib/experimental/cryptography/modules/CryptographyModule.qll +++ b/python/ql/lib/experimental/cryptography/modules/CryptographyModule.qll @@ -70,10 +70,10 @@ module KDF { .getMember(algName) and result = algModule.asSource() and // https://github.com/pyca/cryptography/tree/main/src/cryptography/hazmat/primitives/kdf - member in ["concatkdf", "hkdf", "kbkdf", "pbkdf2", "scrypt", "x963kdf"] and + member in ["argon2", "concatkdf", "hkdf", "kbkdf", "pbkdf2", "scrypt", "x963kdf"] and algName in [ - "ConcatKDFHash", "ConcatKDFHMAC", "HKDF", "HKDFExpand", "KBKDFCMAC", "KBKDFHMAC", - "PBKDF2HMAC", "Scrypt", "X963KDF" + "Argon2d", "Argon2i", "Argon2id", "ConcatKDFHash", "ConcatKDFHMAC", "HKDF", + "HKDFExpand", "KBKDFCMAC", "KBKDFHMAC", "PBKDF2HMAC", "Scrypt", "X963KDF" ] ) } @@ -111,21 +111,31 @@ module KDF { } override predicate requiresSalt() { - this.getAlgorithm().getKDFName() in ["PBKDF2HMAC", "CONCATKDFHMAC", "HKDF"] + this.getAlgorithm().getKDFName() in ["PBKDF2HMAC", "CONCATKDFHMAC", "HKDF", "SCRYPT", "ARGON2"] } - override predicate requiresIteration() { this.getAlgorithm().getKDFName() in ["PBKDF2HMAC"] } + override predicate requiresIteration() { this.getAlgorithm().getKDFName() in ["PBKDF2HMAC", "ARGON2"] } + + override predicate requiresLanes() { this.getAlgorithm().getKDFName() in ["ARGON2"] } + + override predicate requiresMemoryCost() { this.getAlgorithm().getKDFName() in ["ARGON2"] } override DataFlow::Node getIterationSizeSrc() { this.requiresIteration() and - // ASSUMPTION: ONLY EVER in arg 3 in PBKDF2HMAC - result = Utils::getUltimateSrcFromApiNode(this.getParameter(3, "iterations")) + if this.getAlgorithm().getKDFName() = "ARGON2" + then result = Utils::getUltimateSrcFromApiNode(this.getKeywordParameter("iterations")) + else + // ASSUMPTION: ONLY EVER in arg 3 in PBKDF2HMAC + result = Utils::getUltimateSrcFromApiNode(this.getParameter(3, "iterations")) } override DataFlow::Node getSaltConfigSrc() { this.requiresSalt() and + // ARGON2 variants have it as a keyword-only parameter + if this.getAlgorithm().getKDFName() = "ARGON2" + then result = Utils::getUltimateSrcFromApiNode(this.getKeywordParameter("salt")) // SCRYPT has it in arg 1 - if this.getAlgorithm().getKDFName() = "SCRYPT" + else if this.getAlgorithm().getKDFName() = "SCRYPT" then result = Utils::getUltimateSrcFromApiNode(this.getParameter(1, "salt")) else // EVERYTHING ELSE that uses salt is in arg 2 @@ -138,9 +148,23 @@ module KDF { result = Utils::getUltimateSrcFromApiNode(this.getParameter(0, "algorithm")) } + override DataFlow::Node getLanesConfigSrc() { + this.requiresLanes() and + // ASSUMPTION: ONLY EVER in keyword parameter + result = Utils::getUltimateSrcFromApiNode(this.getKeywordParameter("lanes")) + } + + override DataFlow::Node getMemoryCostConfigSrc() { + this.requiresMemoryCost() and + // ASSUMPTION: ONLY EVER in keyword parameter + result = Utils::getUltimateSrcFromApiNode(this.getKeywordParameter("memory_cost")) + } + // TODO: get encryption algorithm for CBC-based KDF? override DataFlow::Node getDerivedKeySizeSrc() { - if this.getAlgorithm().getKDFName() in ["KBKDFHMAC", "KBKDFCMAC"] + if this.getAlgorithm().getKDFName() = "ARGON2" + then result = Utils::getUltimateSrcFromApiNode(this.getKeywordParameter("length")) + else if this.getAlgorithm().getKDFName() in ["KBKDFHMAC", "KBKDFCMAC"] then result = Utils::getUltimateSrcFromApiNode(this.getParameter(2, "length")) else result = Utils::getUltimateSrcFromApiNode(this.getParameter(1, "length")) } diff --git a/python/ql/lib/experimental/cryptography/modules/stdlib/HashlibModule.qll b/python/ql/lib/experimental/cryptography/modules/stdlib/HashlibModule.qll index 346512e9a2db..487ed783ff56 100644 --- a/python/ql/lib/experimental/cryptography/modules/stdlib/HashlibModule.qll +++ b/python/ql/lib/experimental/cryptography/modules/stdlib/HashlibModule.qll @@ -197,6 +197,10 @@ module KDF { override predicate requiresSalt() { any() } override predicate requiresIteration() { any() } + + override predicate requiresLanes() { none() } + + override predicate requiresMemoryCost() { none() } } // TODO: better modeling of scrypt @@ -233,5 +237,9 @@ module KDF { override predicate requiresSalt() { any() } override predicate requiresIteration() { none() } + + override predicate requiresLanes() { none() } + + override predicate requiresMemoryCost() { none() } } }