Skip to content

Commit 0cbf136

Browse files
authored
Merge pull request #7273 from github/ruby/crypto-algorithms
Ruby: add CryptoAlgorithms library
2 parents 69f1c18 + 3da98ec commit 0cbf136

File tree

13 files changed

+1021
-96
lines changed

13 files changed

+1021
-96
lines changed

config/identical-files.json

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,9 +452,15 @@
452452
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll",
453453
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll"
454454
],
455-
"CryptoAlgorithms Python/JS": [
455+
"CryptoAlgorithms Python/JS/Ruby": [
456456
"javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll",
457-
"python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll"
457+
"python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll",
458+
"ruby/ql/lib/codeql/ruby/security/CryptoAlgorithms.qll"
459+
],
460+
"CryptoAlgorithmNames Python/JS/Ruby": [
461+
"javascript/ql/lib/semmle/javascript/security/internal/CryptoAlgorithmNames.qll",
462+
"python/ql/lib/semmle/python/concepts/internal/CryptoAlgorithmNames.qll",
463+
"ruby/ql/lib/codeql/ruby/security/internal/CryptoAlgorithmNames.qll"
458464
],
459465
"SensitiveDataHeuristics Python/JS": [
460466
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",

javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,10 @@
11
/**
22
* Provides classes modeling cryptographic algorithms, separated into strong and weak variants.
33
*
4-
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
4+
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
55
*/
66

7-
/**
8-
* Names of cryptographic algorithms, separated into strong and weak variants.
9-
*
10-
* The names are normalized: upper-case, no spaces, dashes or underscores.
11-
*
12-
* The names are inspired by the names used in real world crypto libraries.
13-
*
14-
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
15-
*/
16-
private module AlgorithmNames {
17-
predicate isStrongHashingAlgorithm(string name) {
18-
name =
19-
[
20-
"DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2",
21-
"SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512"
22-
]
23-
}
24-
25-
predicate isWeakHashingAlgorithm(string name) {
26-
name =
27-
[
28-
"HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160",
29-
"RIPEMD320", "SHA0", "SHA1"
30-
]
31-
}
32-
33-
predicate isStrongEncryptionAlgorithm(string name) {
34-
name = ["AES", "AES128", "AES192", "AES256", "AES512", "RSA", "RABBIT", "BLOWFISH"]
35-
}
36-
37-
predicate isWeakEncryptionAlgorithm(string name) {
38-
name =
39-
[
40-
"DES", "3DES", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", "ARCFOUR",
41-
"ARC5", "RC5"
42-
]
43-
}
44-
45-
predicate isStrongPasswordHashingAlgorithm(string name) {
46-
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
47-
}
48-
49-
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
50-
}
51-
52-
private import AlgorithmNames
7+
private import internal.CryptoAlgorithmNames
538

549
/**
5510
* A cryptographic algorithm.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Names of cryptographic algorithms, separated into strong and weak variants.
3+
*
4+
* The names are normalized: upper-case, no spaces, dashes or underscores.
5+
*
6+
* The names are inspired by the names used in real world crypto libraries.
7+
*
8+
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
9+
*/
10+
11+
/**
12+
* Holds if `name` corresponds to a strong hashing algorithm.
13+
*/
14+
predicate isStrongHashingAlgorithm(string name) {
15+
name =
16+
[
17+
"DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2",
18+
"SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512"
19+
]
20+
}
21+
22+
/**
23+
* Holds if `name` corresponds to a weak hashing algorithm.
24+
*/
25+
predicate isWeakHashingAlgorithm(string name) {
26+
name =
27+
[
28+
"HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160",
29+
"RIPEMD320", "SHA0", "SHA1"
30+
]
31+
}
32+
33+
/**
34+
* Holds if `name` corresponds to a strong encryption algorithm.
35+
*/
36+
predicate isStrongEncryptionAlgorithm(string name) {
37+
name =
38+
[
39+
"AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512",
40+
"ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192",
41+
"CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89",
42+
"IDEA", "RABBIT", "RSA", "SEED", "SM4"
43+
]
44+
}
45+
46+
/**
47+
* Holds if `name` corresponds to a weak encryption algorithm.
48+
*/
49+
predicate isWeakEncryptionAlgorithm(string name) {
50+
name =
51+
[
52+
"DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4",
53+
"ARCFOUR", "ARC5", "RC5"
54+
]
55+
}
56+
57+
/**
58+
* Holds if `name` corresponds to a strong password hashing algorithm.
59+
*/
60+
predicate isStrongPasswordHashingAlgorithm(string name) {
61+
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
62+
}
63+
64+
/**
65+
* Holds if `name` corresponds to a weak password hashing algorithm.
66+
*/
67+
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
68+
69+
/**
70+
* Holds if `name` corresponds to a weak block cipher mode of operation.
71+
*/
72+
predicate isWeakBlockMode(string name) { name = "ECB" }

python/ql/lib/semmle/python/concepts/CryptoAlgorithms.qll

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,10 @@
11
/**
22
* Provides classes modeling cryptographic algorithms, separated into strong and weak variants.
33
*
4-
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
4+
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
55
*/
66

7-
/**
8-
* Names of cryptographic algorithms, separated into strong and weak variants.
9-
*
10-
* The names are normalized: upper-case, no spaces, dashes or underscores.
11-
*
12-
* The names are inspired by the names used in real world crypto libraries.
13-
*
14-
* The classification into strong and weak are based on Wikipedia, OWASP and google (2017).
15-
*/
16-
private module AlgorithmNames {
17-
predicate isStrongHashingAlgorithm(string name) {
18-
name =
19-
[
20-
"DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2",
21-
"SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512"
22-
]
23-
}
24-
25-
predicate isWeakHashingAlgorithm(string name) {
26-
name =
27-
[
28-
"HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160",
29-
"RIPEMD320", "SHA0", "SHA1"
30-
]
31-
}
32-
33-
predicate isStrongEncryptionAlgorithm(string name) {
34-
name = ["AES", "AES128", "AES192", "AES256", "AES512", "RSA", "RABBIT", "BLOWFISH"]
35-
}
36-
37-
predicate isWeakEncryptionAlgorithm(string name) {
38-
name =
39-
[
40-
"DES", "3DES", "TRIPLEDES", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4", "ARCFOUR",
41-
"ARC5", "RC5"
42-
]
43-
}
44-
45-
predicate isStrongPasswordHashingAlgorithm(string name) {
46-
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
47-
}
48-
49-
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
50-
}
51-
52-
private import AlgorithmNames
7+
private import internal.CryptoAlgorithmNames
538

549
/**
5510
* A cryptographic algorithm.
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Names of cryptographic algorithms, separated into strong and weak variants.
3+
*
4+
* The names are normalized: upper-case, no spaces, dashes or underscores.
5+
*
6+
* The names are inspired by the names used in real world crypto libraries.
7+
*
8+
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
9+
*/
10+
11+
/**
12+
* Holds if `name` corresponds to a strong hashing algorithm.
13+
*/
14+
predicate isStrongHashingAlgorithm(string name) {
15+
name =
16+
[
17+
"DSA", "ED25519", "ES256", "ECDSA256", "ES384", "ECDSA384", "ES512", "ECDSA512", "SHA2",
18+
"SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "SHA3224", "SHA3256", "SHA3384", "SHA3512"
19+
]
20+
}
21+
22+
/**
23+
* Holds if `name` corresponds to a weak hashing algorithm.
24+
*/
25+
predicate isWeakHashingAlgorithm(string name) {
26+
name =
27+
[
28+
"HAVEL128", "MD2", "MD4", "MD5", "PANAMA", "RIPEMD", "RIPEMD128", "RIPEMD256", "RIPEMD160",
29+
"RIPEMD320", "SHA0", "SHA1"
30+
]
31+
}
32+
33+
/**
34+
* Holds if `name` corresponds to a strong encryption algorithm.
35+
*/
36+
predicate isStrongEncryptionAlgorithm(string name) {
37+
name =
38+
[
39+
"AES", "AES128", "AES192", "AES256", "AES512", "AES-128", "AES-192", "AES-256", "AES-512",
40+
"ARIA", "BLOWFISH", "BF", "ECIES", "CAST", "CAST5", "CAMELLIA", "CAMELLIA128", "CAMELLIA192",
41+
"CAMELLIA256", "CAMELLIA-128", "CAMELLIA-192", "CAMELLIA-256", "CHACHA", "GOST", "GOST89",
42+
"IDEA", "RABBIT", "RSA", "SEED", "SM4"
43+
]
44+
}
45+
46+
/**
47+
* Holds if `name` corresponds to a weak encryption algorithm.
48+
*/
49+
predicate isWeakEncryptionAlgorithm(string name) {
50+
name =
51+
[
52+
"DES", "3DES", "DES3", "TRIPLEDES", "DESX", "TDEA", "TRIPLEDEA", "ARC2", "RC2", "ARC4", "RC4",
53+
"ARCFOUR", "ARC5", "RC5"
54+
]
55+
}
56+
57+
/**
58+
* Holds if `name` corresponds to a strong password hashing algorithm.
59+
*/
60+
predicate isStrongPasswordHashingAlgorithm(string name) {
61+
name = ["ARGON2", "PBKDF2", "BCRYPT", "SCRYPT"]
62+
}
63+
64+
/**
65+
* Holds if `name` corresponds to a weak password hashing algorithm.
66+
*/
67+
predicate isWeakPasswordHashingAlgorithm(string name) { name = "EVPKDF" }
68+
69+
/**
70+
* Holds if `name` corresponds to a weak block cipher mode of operation.
71+
*/
72+
predicate isWeakBlockMode(string name) { name = "ECB" }
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* Provides classes modeling cryptographic algorithms, separated into strong and weak variants.
3+
*
4+
* The classification into strong and weak are based on Wikipedia, OWASP and Google (2021).
5+
*/
6+
7+
private import internal.CryptoAlgorithmNames
8+
9+
/**
10+
* A cryptographic algorithm.
11+
*/
12+
private newtype TCryptographicAlgorithm =
13+
MkHashingAlgorithm(string name, boolean isWeak) {
14+
isStrongHashingAlgorithm(name) and isWeak = false
15+
or
16+
isWeakHashingAlgorithm(name) and isWeak = true
17+
} or
18+
MkEncryptionAlgorithm(string name, boolean isWeak) {
19+
isStrongEncryptionAlgorithm(name) and isWeak = false
20+
or
21+
isWeakEncryptionAlgorithm(name) and isWeak = true
22+
} or
23+
MkPasswordHashingAlgorithm(string name, boolean isWeak) {
24+
isStrongPasswordHashingAlgorithm(name) and isWeak = false
25+
or
26+
isWeakPasswordHashingAlgorithm(name) and isWeak = true
27+
}
28+
29+
/**
30+
* A cryptographic algorithm.
31+
*/
32+
abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
33+
/** Gets a textual representation of this element. */
34+
string toString() { result = getName() }
35+
36+
/**
37+
* Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores).
38+
*/
39+
abstract string getName();
40+
41+
/**
42+
* Holds if the name of this algorithm matches `name` modulo case,
43+
* white space, dashes, underscores, and anything after a dash in the name
44+
* (to ignore modes of operation, such as CBC or ECB).
45+
*/
46+
bindingset[name]
47+
predicate matchesName(string name) {
48+
[name.toUpperCase(), name.toUpperCase().regexpCapture("^(\\w+)(?:-.*)?$", 1)]
49+
.regexpReplaceAll("[-_ ]", "") = getName()
50+
}
51+
52+
/**
53+
* Holds if this algorithm is weak.
54+
*/
55+
abstract predicate isWeak();
56+
}
57+
58+
/**
59+
* A hashing algorithm such as `MD5` or `SHA512`.
60+
*/
61+
class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm {
62+
string name;
63+
boolean isWeak;
64+
65+
HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) }
66+
67+
override string getName() { result = name }
68+
69+
override predicate isWeak() { isWeak = true }
70+
}
71+
72+
/**
73+
* An encryption algorithm such as `DES` or `AES512`.
74+
*/
75+
class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm {
76+
string name;
77+
boolean isWeak;
78+
79+
EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) }
80+
81+
override string getName() { result = name }
82+
83+
override predicate isWeak() { isWeak = true }
84+
}
85+
86+
/**
87+
* A password hashing algorithm such as `PBKDF2` or `SCRYPT`.
88+
*/
89+
class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm {
90+
string name;
91+
boolean isWeak;
92+
93+
PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) }
94+
95+
override string getName() { result = name }
96+
97+
override predicate isWeak() { isWeak = true }
98+
}

0 commit comments

Comments
 (0)