diff --git a/config/identical-files.json b/config/identical-files.json index 579a22379e84..b066c443d9fd 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -234,12 +234,14 @@ "CryptoAlgorithms Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll", "python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll", - "ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll" + "ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll", + "rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll" ], "CryptoAlgorithmNames Python/JS/Ruby": [ "javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll", "python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll", - "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll" + "ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll", + "rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll" ], "SensitiveDataHeuristics Python/JS": [ "javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll", @@ -254,7 +256,8 @@ "Concepts Python/Ruby/JS": [ "python/ql/lib/semmle/python/internal/ConceptsShared.qll", "ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll", - "javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll" + "javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll", + "rust/ql/lib/codeql/rust/internal/ConceptsShared.qll" ], "ApiGraphModels": [ "javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll", diff --git a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll +++ b/javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/python/ql/lib/semmle/python/internal/ConceptsShared.qll b/python/ql/lib/semmle/python/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/python/ql/lib/semmle/python/internal/ConceptsShared.qll +++ b/python/ql/lib/semmle/python/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll index 135f830e47dc..1b13e4ebb17e 100644 --- a/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll +++ b/ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll @@ -30,7 +30,7 @@ module Cryptography { class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to refine existing API models. If you want to model new APIs, @@ -40,7 +40,7 @@ module Cryptography { /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ DataFlow::Node getInitialization() { result = super.getInitialization() } /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ @@ -61,14 +61,14 @@ module Cryptography { /** Provides classes for modeling new applications of a cryptographic algorithms. */ module CryptographicOperation { /** - * A data-flow node that is an application of a cryptographic algorithm. For example, + * A data flow node that is an application of a cryptographic algorithm. For example, * encryption, decryption, signature-validation. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `CryptographicOperation` instead. */ abstract class Range extends DataFlow::Node { - /** Gets the data-flow node where the cryptographic algorithm used in this operation is configured. */ + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ abstract DataFlow::Node getInitialization(); /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ @@ -118,14 +118,14 @@ module Http { /** Provides classes for modeling HTTP clients. */ module Client { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to refine existing API models. If you want to model new APIs, * extend `Http::Client::Request::Range` instead. */ class Request extends DataFlow::Node instanceof Request::Range { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } @@ -150,14 +150,14 @@ module Http { /** Provides a class for modeling new HTTP requests. */ module Request { /** - * A data-flow node that makes an outgoing HTTP request. + * A data flow node that makes an outgoing HTTP request. * * Extend this class to model new APIs. If you want to refine existing API models, * extend `Http::Client::Request` instead. */ abstract class Range extends DataFlow::Node { /** - * Gets a data-flow node that contributes to the URL of the request. + * Gets a data flow node that contributes to the URL of the request. * Depending on the framework, a request may have multiple nodes which contribute to the URL. */ abstract DataFlow::Node getAUrlPart(); diff --git a/rust/ql/lib/codeql/rust/Concepts.qll b/rust/ql/lib/codeql/rust/Concepts.qll index 7e3ec0990ce3..51d601070000 100644 --- a/rust/ql/lib/codeql/rust/Concepts.qll +++ b/rust/ql/lib/codeql/rust/Concepts.qll @@ -105,7 +105,7 @@ module RemoteSource { } /** - * A data-flow node that constructs a SQL statement (for later execution). + * A data flow node that constructs a SQL statement (for later execution). * * Often, it is worthy of an alert if a SQL statement is constructed such that * executing it would be a security risk. @@ -122,7 +122,7 @@ final class SqlConstruction = SqlConstruction::Range; */ module SqlConstruction { /** - * A data-flow node that constructs a SQL statement. + * A data flow node that constructs a SQL statement. */ abstract class Range extends DataFlow::Node { /** @@ -133,7 +133,7 @@ module SqlConstruction { } /** - * A data-flow node that constructs and executes SQL statements. + * A data flow node that constructs and executes SQL statements. * * If the context of interest is such that merely constructing a SQL statement * would be valuable to report, consider also using `SqlConstruction`. @@ -148,7 +148,7 @@ final class SqlExecution = SqlExecution::Range; */ module SqlExecution { /** - * A data-flow node that executes SQL statements. + * A data flow node that executes SQL statements. */ abstract class Range extends DataFlow::Node { /** @@ -159,7 +159,7 @@ module SqlExecution { } /** - * A data-flow node that performs SQL sanitization. + * A data flow node that performs SQL sanitization. */ final class SqlSanitization = SqlSanitization::Range; @@ -168,7 +168,28 @@ final class SqlSanitization = SqlSanitization::Range; */ module SqlSanitization { /** - * A data-flow node that performs SQL sanitization. + * A data flow node that performs SQL sanitization. */ abstract class Range extends DataFlow::Node { } } + +/** + * Provides models for cryptographic things. + */ +module Cryptography { + private import codeql.rust.internal.ConceptsShared::Cryptography as SC + + final class CryptographicOperation = SC::CryptographicOperation; + + class EncryptionAlgorithm = SC::EncryptionAlgorithm; + + class HashingAlgorithm = SC::HashingAlgorithm; + + class PasswordHashingAlgorithm = SC::PasswordHashingAlgorithm; + + module CryptographicOperation = SC::CryptographicOperation; + + class BlockMode = SC::BlockMode; + + class CryptographicAlgorithm = SC::CryptographicAlgorithm; +} diff --git a/rust/ql/lib/codeql/rust/Frameworks.qll b/rust/ql/lib/codeql/rust/Frameworks.qll index 0c6fc573d0fb..483056888ec6 100644 --- a/rust/ql/lib/codeql/rust/Frameworks.qll +++ b/rust/ql/lib/codeql/rust/Frameworks.qll @@ -3,5 +3,6 @@ */ private import codeql.rust.frameworks.Reqwest +private import codeql.rust.frameworks.RustCrypto private import codeql.rust.frameworks.stdlib.Env private import codeql.rust.frameworks.Sqlx diff --git a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll index b22b27c4db65..1eb651314c2c 100644 --- a/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll +++ b/rust/ql/lib/codeql/rust/dataflow/internal/DataFlowImpl.qll @@ -330,7 +330,7 @@ module Node { override ReturnKind getKind() { result = rk } } - /** A data-flow node that represents the output of a call. */ + /** A data flow node that represents the output of a call. */ abstract class OutNode extends Node { /** Gets the underlying call for this node. */ abstract DataFlowCall getCall(ReturnKind kind); diff --git a/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll new file mode 100644 index 000000000000..9dd40004766a --- /dev/null +++ b/rust/ql/lib/codeql/rust/frameworks/RustCrypto.qll @@ -0,0 +1,57 @@ +/** + * Provides modeling for the `RustCrypto` family of crates (`cipher`, `digest` etc). + */ + +private import rust +private import codeql.rust.Concepts +private import codeql.rust.dataflow.DataFlow + +bindingset[algorithmName] +private string simplifyAlgorithmName(string algorithmName) { + // the cipher library gives triple-DES names like "TdesEee2" and "TdesEde2" + if algorithmName.matches("Tdes%") then result = "3des" else result = algorithmName +} + +/** + * An operation that initializes a cipher through the `cipher::KeyInit` or + * `cipher::KeyIvInit` trait, for example `Des::new` or `cbc::Encryptor::new`. + */ +class StreamCipherInit extends Cryptography::CryptographicOperation::Range { + string algorithmName; + + StreamCipherInit() { + // a call to `cipher::KeyInit::new`, `cipher::KeyInit::new_from_slice`, + // `cipher::KeyIvInit::new`, `cipher::KeyIvInit::new_from_slices` or `rc2::Rc2::new_with_eff_key_len`. + exists(PathExpr p, string rawAlgorithmName | + this.asExpr().getExpr().(CallExpr).getFunction() = p and + p.getResolvedCrateOrigin().matches("%/RustCrypto%") and + p.getPath().getPart().getNameRef().getText() = + ["new", "new_from_slice", "new_from_slices", "new_with_eff_key_len"] and + ( + rawAlgorithmName = p.getPath().getQualifier().getPart().getNameRef().getText() or + rawAlgorithmName = + p.getPath() + .getQualifier() + .getPart() + .getGenericArgList() + .getGenericArg(0) + .(TypeArg) + .getTypeRepr() + .(PathTypeRepr) + .getPath() + .getPart() + .getNameRef() + .getText() + ) and + algorithmName = simplifyAlgorithmName(rawAlgorithmName) + ) + } + + override DataFlow::Node getInitialization() { result = this } + + override Cryptography::CryptographicAlgorithm getAlgorithm() { result.matchesName(algorithmName) } + + override DataFlow::Node getAnInput() { none() } + + override Cryptography::BlockMode getBlockMode() { result = "" } +} diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll b/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll new file mode 100644 index 000000000000..341f3ade509f --- /dev/null +++ b/rust/ql/lib/codeql/rust/internal/ConceptsImports.qll @@ -0,0 +1,7 @@ +/** + * This file contains imports required for the Rust version of `ConceptsShared.qll`. + * Since they are language-specific, they can't be placed directly in that file, as it is shared between languages. + */ + +import codeql.rust.dataflow.DataFlow::DataFlow as DataFlow +import codeql.rust.security.CryptoAlgorithms as CryptoAlgorithms diff --git a/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll new file mode 100644 index 000000000000..1b13e4ebb17e --- /dev/null +++ b/rust/ql/lib/codeql/rust/internal/ConceptsShared.qll @@ -0,0 +1,181 @@ +/** + * Provides Concepts which are shared across languages. + * + * Each language has a language specific `Concepts.qll` file that can import the + * shared concepts from this file. A language can either re-export the concept directly, + * or can add additional member-predicates that are needed for that language. + * + * Moving forward, `Concepts.qll` will be the staging ground for brand new concepts from + * each language, but we will maintain a discipline of moving those concepts to + * `ConceptsShared.qll` ASAP. + */ + +private import ConceptsImports + +/** + * Provides models for cryptographic concepts. + * + * Note: The `CryptographicAlgorithm` class currently doesn't take weak keys into + * consideration for the `isWeak` member predicate. So RSA is always considered + * secure, although using a low number of bits will actually make it insecure. We plan + * to improve our libraries in the future to more precisely capture this aspect. + */ +module Cryptography { + class CryptographicAlgorithm = CryptoAlgorithms::CryptographicAlgorithm; + + class EncryptionAlgorithm = CryptoAlgorithms::EncryptionAlgorithm; + + class HashingAlgorithm = CryptoAlgorithms::HashingAlgorithm; + + class PasswordHashingAlgorithm = CryptoAlgorithms::PasswordHashingAlgorithm; + + /** + * A data flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `CryptographicOperation::Range` instead. + */ + class CryptographicOperation extends DataFlow::Node instanceof CryptographicOperation::Range { + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + CryptographicAlgorithm getAlgorithm() { result = super.getAlgorithm() } + + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ + DataFlow::Node getInitialization() { result = super.getInitialization() } + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + DataFlow::Node getAnInput() { result = super.getAnInput() } + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + BlockMode getBlockMode() { result = super.getBlockMode() } + } + + /** Provides classes for modeling new applications of a cryptographic algorithms. */ + module CryptographicOperation { + /** + * A data flow node that is an application of a cryptographic algorithm. For example, + * encryption, decryption, signature-validation. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `CryptographicOperation` instead. + */ + abstract class Range extends DataFlow::Node { + /** Gets the data flow node where the cryptographic algorithm used in this operation is configured. */ + abstract DataFlow::Node getInitialization(); + + /** Gets the algorithm used, if it matches a known `CryptographicAlgorithm`. */ + abstract CryptographicAlgorithm getAlgorithm(); + + /** Gets an input the algorithm is used on, for example the plain text input to be encrypted. */ + abstract DataFlow::Node getAnInput(); + + /** + * Gets the block mode used to perform this cryptographic operation. + * + * This predicate is only expected to have a result if two conditions hold: + * 1. The operation is an encryption operation, i.e. the algorithm used is an `EncryptionAlgorithm`, and + * 2. The algorithm used is a block cipher (not a stream cipher). + * + * If either of these conditions do not hold, then this predicate should have no result. + */ + abstract BlockMode getBlockMode(); + } + } + + /** + * A cryptographic block cipher mode of operation. This can be used to encrypt + * data of arbitrary length using a block encryption algorithm. + */ + class BlockMode extends string { + BlockMode() { + this = + [ + "ECB", "CBC", "GCM", "CCM", "CFB", "OFB", "CTR", "OPENPGP", + "XTS", // https://csrc.nist.gov/publications/detail/sp/800-38e/final + "EAX" // https://en.wikipedia.org/wiki/EAX_mode + ] + } + + /** Holds if this block mode is considered to be insecure. */ + predicate isWeak() { this = "ECB" } + + /** Holds if the given string appears to match this block mode. */ + bindingset[s] + predicate matchesString(string s) { s.toUpperCase().matches("%" + this + "%") } + } +} + +/** Provides classes for modeling HTTP-related APIs. */ +module Http { + /** Provides classes for modeling HTTP clients. */ + module Client { + /** + * A data flow node that makes an outgoing HTTP request. + * + * Extend this class to refine existing API models. If you want to model new APIs, + * extend `Http::Client::Request::Range` instead. + */ + class Request extends DataFlow::Node instanceof Request::Range { + /** + * Gets a data flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + DataFlow::Node getAUrlPart() { result = super.getAUrlPart() } + + /** Gets a string that identifies the framework used for this request. */ + string getFramework() { result = super.getFramework() } + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + predicate disablesCertificateValidation( + DataFlow::Node disablingNode, DataFlow::Node argumentOrigin + ) { + super.disablesCertificateValidation(disablingNode, argumentOrigin) + } + } + + /** Provides a class for modeling new HTTP requests. */ + module Request { + /** + * A data flow node that makes an outgoing HTTP request. + * + * Extend this class to model new APIs. If you want to refine existing API models, + * extend `Http::Client::Request` instead. + */ + abstract class Range extends DataFlow::Node { + /** + * Gets a data flow node that contributes to the URL of the request. + * Depending on the framework, a request may have multiple nodes which contribute to the URL. + */ + abstract DataFlow::Node getAUrlPart(); + + /** Gets a string that identifies the framework used for this request. */ + abstract string getFramework(); + + /** + * Holds if this request is made using a mode that disables SSL/TLS + * certificate validation, where `disablingNode` represents the point at + * which the validation was disabled, and `argumentOrigin` represents the origin + * of the argument that disabled the validation (which could be the same node as + * `disablingNode`). + */ + abstract predicate disablesCertificateValidation( + DataFlow::Node disablingNode, DataFlow::Node argumentOrigin + ); + } + } + } +} diff --git a/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll new file mode 100644 index 000000000000..7176c666c573 --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/CryptoAlgorithms.qll @@ -0,0 +1,117 @@ +/** + * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +private import internal.CryptoAlgorithmNames + +/** + * A cryptographic algorithm. + */ +private newtype TCryptographicAlgorithm = + MkHashingAlgorithm(string name, boolean isWeak) { + isStrongHashingAlgorithm(name) and isWeak = false + or + isWeakHashingAlgorithm(name) and isWeak = true + } or + MkEncryptionAlgorithm(string name, boolean isWeak) { + isStrongEncryptionAlgorithm(name) and isWeak = false + or + isWeakEncryptionAlgorithm(name) and isWeak = true + } or + MkPasswordHashingAlgorithm(string name, boolean isWeak) { + isStrongPasswordHashingAlgorithm(name) and isWeak = false + or + isWeakPasswordHashingAlgorithm(name) and isWeak = true + } + +/** + * Gets the most specific `CryptographicAlgorithm` that matches the given `name`. + * A matching algorithm is one where the name of the algorithm matches the start of name, with allowances made for different name formats. + * In the case that multiple `CryptographicAlgorithm`s match the given `name`, the algorithm(s) with the longest name will be selected. This is intended to select more specific versions of algorithms when multiple versions could match - for example "SHA3_224" matches against both "SHA3" and "SHA3224", but the latter is a more precise match. + */ +bindingset[name] +private CryptographicAlgorithm getBestAlgorithmForName(string name) { + result = + max(CryptographicAlgorithm algorithm | + algorithm.getName() = + [ + name.toUpperCase(), // the full name + name.toUpperCase().regexpCapture("^([\\w]+)(?:-.*)?$", 1), // the name prior to any dashes or spaces + name.toUpperCase().regexpCapture("^([A-Z0-9]+)(?:(-|_).*)?$", 1) // the name prior to any dashes, spaces, or underscores + ].regexpReplaceAll("[-_ ]", "") // strip dashes, underscores, and spaces + | + algorithm order by algorithm.getName().length() + ) +} + +/** + * A cryptographic algorithm. + */ +abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { + /** Gets a textual representation of this element. */ + string toString() { result = this.getName() } + + /** + * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). + */ + abstract string getName(); + + /** + * Holds if the name of this algorithm is the most specific match for `name`. + * This predicate matches quite liberally to account for different ways of formatting algorithm names, e.g. using dashes, underscores, or spaces as separators, including or not including block modes of operation, etc. + */ + bindingset[name] + predicate matchesName(string name) { this = getBestAlgorithmForName(name) } + + /** + * Holds if this algorithm is weak. + */ + abstract predicate isWeak(); +} + +/** + * A hashing algorithm such as `MD5` or `SHA512`. + */ +class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} + +/** + * An encryption algorithm such as `DES` or `AES512`. + */ +class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } + + /** Holds if this algorithm is a stream cipher. */ + predicate isStreamCipher() { isStreamCipher(name) } +} + +/** + * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. + */ +class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} diff --git a/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll b/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll new file mode 100644 index 000000000000..8bb63d97876a --- /dev/null +++ b/rust/ql/lib/codeql/rust/security/internal/CryptoAlgorithmNames.qll @@ -0,0 +1,84 @@ +/** + * Names of cryptographic algorithms, separated into strong and weak variants. + * + * The names are normalized: upper-case, no spaces, dashes or underscores. + * + * The names are inspired by the names used in real world crypto libraries. + * + * The classification into strong and weak are based on Wikipedia, OWASP and Google (2021). + */ + +/** + * Holds if `name` corresponds to a strong hashing algorithm. + */ +predicate isStrongHashingAlgorithm(string name) { + name = + [ + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#blake2 + // and https://www.blake2.net/ + "BLAKE2", "BLAKE2B", "BLAKE2S", + // see https://github.com/BLAKE3-team/BLAKE3 + "BLAKE3", + // + "DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2", + "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#cryptography.hazmat.primitives.hashes.SHAKE128 + "SHAKE128", "SHAKE256", + // see https://cryptography.io/en/latest/hazmat/primitives/cryptographic-hashes/#sm3 + "SM3", + // see https://security.stackexchange.com/a/216297 + "WHIRLPOOL", + ] +} + +/** + * Holds if `name` corresponds to a weak hashing algorithm. + */ +predicate isWeakHashingAlgorithm(string name) { + name = + [ + "HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160", + "RIPEMD320", "SHA0", "SHA1" + ] +} + +/** + * Holds if `name` corresponds to a strong encryption algorithm. + */ +predicate isStrongEncryptionAlgorithm(string name) { + name = + [ + "AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512", + "ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192", + "CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89", + "IDEA", "RABBIT", "RSA", "SEED", "SM4" + ] +} + +/** + * Holds if `name` corresponds to a weak encryption algorithm. + */ +predicate isWeakEncryptionAlgorithm(string name) { + name = + [ + "DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", + "ARCFOUR", "ARC5", "RC5" + ] +} + +/** + * Holds if `name` corresponds to a strong password hashing algorithm. + */ +predicate isStrongPasswordHashingAlgorithm(string name) { + name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"] +} + +/** + * Holds if `name` corresponds to a weak password hashing algorithm. + */ +predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" } + +/** + * Holds if `name` corresponds to a stream cipher. + */ +predicate isStreamCipher(string name) { name = ["CHACHA", "RC4", "ARC4", "ARCFOUR", "RABBIT"] } diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp new file mode 100644 index 000000000000..e24222e09fc5 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.qhelp @@ -0,0 +1,62 @@ + + + +

+ Using broken or weak cryptographic algorithms can leave data + vulnerable to being decrypted or forged by an attacker. +

+ +

+ Many cryptographic algorithms provided by cryptography + libraries are known to be weak, or flawed. Using such an + algorithm means that encrypted or hashed data is less + secure than it appears to be. +

+ +

+ This query alerts on any use of a weak cryptographic algorithm, that is + not a hashing algorithm. Use of broken or weak cryptographic hash + functions are handled by the + rust/weak-sensitive-data-hashing query. +

+ +
+ + +

+ Ensure that you use a strong, modern cryptographic + algorithm, such as AES-128 or RSA-2048. +

+ +
+ + +

+ The following code uses the des crate from the + RustCrypto family to encrypt some secret data. The + DES algorithm is old and considered very weak. +

+ + + +

+ Instead, we should use a strong modern algorithm. In this + case, we have selected the 256-bit version of the AES + algorithm. +

+ + + +
+ + +
  • NIST, FIPS 140 Annex A: Approved Security Functions.
  • +
  • NIST, SP 800-131A Revision 2: Transitioning the Use of Cryptographic Algorithms and Key Lengths.
  • +
  • OWASP: Cryptographic Storage Cheat Sheet - Algorithms. +
  • +
    + +
    diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql new file mode 100644 index 000000000000..3d777b08539c --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithm.ql @@ -0,0 +1,25 @@ +/** + * @name Use of a broken or weak cryptographic algorithm + * @description Using broken or weak cryptographic algorithms can compromise security. + * @kind problem + * @problem.severity warning + * @security-severity 7.5 + * @precision high + * @id rust/weak-cryptographic-algorithm + * @tags security + * external/cwe/cwe-327 + */ + +import rust +import codeql.rust.Concepts + +from Cryptography::CryptographicOperation operation, string msgPrefix +where + exists(Cryptography::EncryptionAlgorithm algorithm | algorithm = operation.getAlgorithm() | + algorithm.isWeak() and + msgPrefix = "The cryptographic algorithm " + algorithm.getName() + ) + or + operation.getBlockMode().isWeak() and msgPrefix = "The block mode " + operation.getBlockMode() +select operation, "$@ is broken or weak, and should not be used.", operation.getInitialization(), + msgPrefix diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs new file mode 100644 index 000000000000..3e86462c62a2 --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmBad.rs @@ -0,0 +1,2 @@ +let des_cipher = cbc::Encryptor::::new(key.into(), iv.into()); // BAD: weak encryption +let encryption_result = des_cipher.encrypt_padded_mut::(data, data_len); diff --git a/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs new file mode 100644 index 000000000000..6cafbc69bf7d --- /dev/null +++ b/rust/ql/src/queries/security/CWE-327/BrokenCryptoAlgorithmGood.rs @@ -0,0 +1,2 @@ +let aes_cipher = cbc::Encryptor::::new(key.into(), iv.into()); // GOOD: strong encryption +let encryption_result = aes_cipher.encrypt_padded_mut::(data, data_len); diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected new file mode 100644 index 000000000000..f1395ff39ec0 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.expected @@ -0,0 +1,21 @@ +| test_cipher.rs:20:27:20:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:20:27:20:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:23:27:23:60 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:23:27:23:60 | ...::new_from_slice(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:26:27:26:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:26:27:26:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:29:27:29:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:29:27:29:48 | ...::new(...) | The cryptographic algorithm RC4 | +| test_cipher.rs:59:23:59:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:59:23:59:42 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:63:23:63:47 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:63:23:63:47 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:67:23:67:46 | ...::new_from_slice(...) | The cryptographic algorithm DES | +| test_cipher.rs:71:23:71:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:71:23:71:42 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:75:27:75:46 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:75:27:75:46 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:80:24:80:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:80:24:80:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:84:24:84:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:84:24:84:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:88:24:88:48 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:88:24:88:48 | ...::new(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:92:24:92:52 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:92:24:92:52 | ...::new_from_slice(...) | The cryptographic algorithm 3DES | +| test_cipher.rs:97:23:97:42 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:97:23:97:42 | ...::new(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:101:23:101:46 | ...::new_from_slice(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:105:23:105:56 | ...::new_with_eff_key_len(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:105:23:105:56 | ...::new_with_eff_key_len(...) | The cryptographic algorithm RC2 | +| test_cipher.rs:110:23:110:50 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:110:23:110:50 | ...::new(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:114:23:114:55 | ...::new_from_slice(...) | The cryptographic algorithm RC5 | +| test_cipher.rs:132:23:132:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:132:23:132:76 | ...::new(...) | The cryptographic algorithm DES | +| test_cipher.rs:138:23:138:76 | ...::new_from_slices(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:138:23:138:76 | ...::new_from_slices(...) | The cryptographic algorithm DES | +| test_cipher.rs:141:23:141:76 | ...::new(...) | $@ is broken or weak, and should not be used. | test_cipher.rs:141:23:141:76 | ...::new(...) | The cryptographic algorithm DES | diff --git a/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref new file mode 100644 index 000000000000..6b7ff78b567a --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/BrokenCryptoAlgorithm.qlref @@ -0,0 +1,2 @@ +query: queries/security/CWE-327/BrokenCryptoAlgorithm.ql +postprocess: utils/InlineExpectationsTestQuery.ql \ No newline at end of file diff --git a/rust/ql/test/query-tests/security/CWE-327/options.yml b/rust/ql/test/query-tests/security/CWE-327/options.yml new file mode 100644 index 000000000000..5a3cf0cab12e --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/options.yml @@ -0,0 +1,10 @@ +qltest_cargo_check: true +qltest_dependencies: + - cipher = { version = "0.4.4" } + - rc4 = { version = "0.1.0" } + - rabbit = { version = "0.4.1" } + - aes = { version = "0.8.4" } + - des = { version = "0.8.1" } + - rc2 = { version = "0.8.1" } + - rc5 = { version = "0.0.1" } + - cbc = { version = "0.1.2" } diff --git a/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs new file mode 100644 index 000000000000..0cf20c4c2782 --- /dev/null +++ b/rust/ql/test/query-tests/security/CWE-327/test_cipher.rs @@ -0,0 +1,143 @@ + +use cipher::{consts::*, StreamCipher, KeyInit, KeyIvInit, BlockEncrypt, BlockDecrypt, BlockEncryptMut, BlockDecryptMut}; +use rc4::{Rc4}; +use rabbit::{Rabbit, RabbitKeyOnly}; +use aes::{Aes128, Aes192Enc, Aes256Dec}; +use des::{Des, TdesEde2, TdesEde3, TdesEee2, TdesEee3}; +use rc2::{Rc2}; +use rc5::{RC5_16_16_8, RC5_32_16_16}; + +// --- tests --- + +fn test_stream_cipher( + key128: &[u8;16], iv128: &[u8;16], plaintext: &str +) { + let mut data = plaintext.as_bytes().to_vec(); + + // rc4 (broken) + let rc4_key = rc4::Key::::from_slice(key128); + + let mut rc4_cipher1 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] + rc4_cipher1.apply_keystream(&mut data); + + let mut rc4_cipher2 = Rc4::::new_from_slice(key128).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + rc4_cipher2.apply_keystream(&mut data); + + let mut rc4_cipher3 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] + let _ = rc4_cipher3.try_apply_keystream(&mut data); + + let mut rc4_cipher4 = Rc4::<_>::new(rc4_key); // $ Alert[rust/weak-cryptographic-algorithm] + let _ = rc4_cipher4.apply_keystream_b2b(plaintext.as_bytes(), &mut data); + + // rabbit + let rabbit_key = rabbit::Key::from_slice(key128); + let rabbit_iv = rabbit::Iv::from_slice(iv128); + + let mut rabbit_cipher1 = RabbitKeyOnly::new(rabbit_key); + rabbit_cipher1.apply_keystream(&mut data); + + let mut rabbit_cipher2 = Rabbit::new(rabbit_key, rabbit_iv); + rabbit_cipher2.apply_keystream(&mut data); +} + +fn test_block_cipher( + key: &[u8], key128: &[u8;16], key192: &[u8;24], key256: &[u8;32], + data: &mut [u8], input: &[u8], block128: &mut [u8;16] +) { + // aes + let aes_cipher1 = Aes128::new(key128.into()); + aes_cipher1.encrypt_block(block128.into()); + aes_cipher1.decrypt_block(block128.into()); + + let aes_cipher2 = Aes192Enc::new_from_slice(key192).unwrap(); + aes_cipher2.encrypt_block(block128.into()); + + let aes_cipher3 = Aes256Dec::new(key256.into()); + aes_cipher3.decrypt_block(block128.into()); + + // des (broken) + let des_cipher1 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher1.encrypt_block(data.into()); + des_cipher1.decrypt_block(data.into()); + + let des_cipher2 = des::Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher2.encrypt_block(data.into()); + des_cipher2.decrypt_block(data.into()); + + let des_cipher3 = Des::new_from_slice(key).expect("fail"); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher3.encrypt_block(data.into()); + des_cipher3.decrypt_block(data.into()); + + let des_cipher4 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher4.encrypt_block_b2b(input.into(), data.into()); + des_cipher4.decrypt_block_b2b(input.into(), data.into()); + + let mut des_cipher5 = Des::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + des_cipher5.encrypt_block_mut(data.into()); + des_cipher5.decrypt_block_mut(data.into()); + + // triple des (broken) + let tdes_cipher1 = TdesEde2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher1.encrypt_block(data.into()); + tdes_cipher1.decrypt_block(data.into()); + + let tdes_cipher2 = TdesEde3::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher2.encrypt_block(data.into()); + tdes_cipher2.decrypt_block(data.into()); + + let tdes_cipher3 = TdesEee2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher3.encrypt_block(data.into()); + tdes_cipher3.decrypt_block(data.into()); + + let tdes_cipher4 = TdesEee3::new_from_slice(key).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + tdes_cipher4.encrypt_block(data.into()); + tdes_cipher4.decrypt_block(data.into()); + + // rc2 (broken) + let rc2_cipher1 = Rc2::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + rc2_cipher1.encrypt_block(data.into()); + rc2_cipher1.decrypt_block(data.into()); + + let rc2_cipher2 = Rc2::new_from_slice(key).expect("fail"); // $ Alert[rust/weak-cryptographic-algorithm] + rc2_cipher2.encrypt_block(data.into()); + rc2_cipher2.decrypt_block(data.into()); + + let rc2_cipher3 = Rc2::new_with_eff_key_len(key, 64); // $ Alert[rust/weak-cryptographic-algorithm] + rc2_cipher3.encrypt_block(data.into()); + rc2_cipher3.decrypt_block(data.into()); + + // rc5 (broken) + let rc5_cipher1 = RC5_16_16_8::new(key.into()); // $ Alert[rust/weak-cryptographic-algorithm] + rc5_cipher1.encrypt_block(data.into()); + rc5_cipher1.decrypt_block(data.into()); + + let rc5_cipher2 = RC5_32_16_16::new_from_slice(key).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + rc5_cipher2.encrypt_block(data.into()); + rc5_cipher2.decrypt_block(data.into()); +} + +type MyDesEncryptor = cbc::Encryptor; + +fn test_cbc( + key: &[u8], key128: &[u8;16], iv: &[u8], iv128: &[u8;16], + input: &[u8], data: &mut [u8] +) { + let data_len = data.len(); + + // aes + let aes_cipher1 = cbc::Encryptor::::new(key128.into(), iv128.into()); + _ = aes_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); + + // des (broken) + let des_cipher1 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher1.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher2 = MyDesEncryptor::new(key.into(), iv.into()); // $ MISSING: Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher2.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher3 = cbc::Encryptor::::new_from_slices(&key, &iv).unwrap(); // $ Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher3.encrypt_padded_mut::(data, data_len).unwrap(); + + let des_cipher4 = cbc::Encryptor::::new(key.into(), iv.into()); // $ Alert[rust/weak-cryptographic-algorithm] + _ = des_cipher4.encrypt_padded_b2b_mut::(input, data).unwrap(); +}