Skip to content
This repository was archived by the owner on Jan 5, 2023. It is now read-only.

Commit d675daa

Browse files
authored
Merge pull request #284 from dilanbhalla/gocrypto
Adding Crypto Query/Library
2 parents fe6cf8c + a58070f commit d675daa

File tree

8 files changed

+482
-0
lines changed

8 files changed

+482
-0
lines changed
Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
/**
2+
* Provides classes for modeling cryptographic libraries.
3+
*/
4+
5+
import go
6+
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 OWASP and Wikipedia (2020).
15+
*
16+
* Sources (more links in qhelp file):
17+
* https://en.wikipedia.org/wiki/Strong_cryptography#Cryptographically_strong_algorithms
18+
* https://en.wikipedia.org/wiki/Strong_cryptography#Examples
19+
* https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html
20+
*/
21+
private module AlgorithmNames {
22+
predicate isStrongHashingAlgorithm(string name) {
23+
name = "DSA" or
24+
name = "ED25519" or
25+
name = "ES256" or
26+
name = "ECDSA256" or
27+
name = "ES384" or
28+
name = "ECDSA384" or
29+
name = "ES512" or
30+
name = "ECDSA512" or
31+
name = "SHA2" or
32+
name = "SHA224" or
33+
name = "SHA256" or
34+
name = "SHA384" or
35+
name = "SHA512" or
36+
name = "SHA3"
37+
}
38+
39+
predicate isWeakHashingAlgorithm(string name) {
40+
name = "HAVEL128" or
41+
name = "MD2" or
42+
name = "MD4" or
43+
name = "MD5" or
44+
name = "PANAMA" or
45+
name = "RIPEMD" or
46+
name = "RIPEMD128" or
47+
name = "RIPEMD256" or
48+
name = "RIPEMD320" or
49+
name = "SHA0" or
50+
name = "SHA1"
51+
}
52+
53+
predicate isStrongEncryptionAlgorithm(string name) {
54+
name = "AES" or
55+
name = "AES128" or
56+
name = "AES192" or
57+
name = "AES256" or
58+
name = "AES512" or
59+
name = "RSA" or
60+
name = "RABBIT" or
61+
name = "BLOWFISH"
62+
}
63+
64+
predicate isWeakEncryptionAlgorithm(string name) {
65+
name = "DES" or
66+
name = "3DES" or
67+
name = "TRIPLEDES" or
68+
name = "TDEA" or
69+
name = "TRIPLEDEA" or
70+
name = "ARC2" or
71+
name = "RC2" or
72+
name = "ARC4" or
73+
name = "RC4" or
74+
name = "ARCFOUR" or
75+
name = "ARC5" or
76+
name = "RC5"
77+
}
78+
79+
predicate isStrongPasswordHashingAlgorithm(string name) {
80+
name = "ARGON2" or
81+
name = "PBKDF2" or
82+
name = "BCRYPT" or
83+
name = "SCRYPT"
84+
}
85+
86+
predicate isWeakPasswordHashingAlgorithm(string name) { none() }
87+
}
88+
89+
private import AlgorithmNames
90+
91+
/**
92+
* A cryptographic algorithm.
93+
*/
94+
private newtype TCryptographicAlgorithm =
95+
MkHashingAlgorithm(string name, boolean isWeak) {
96+
isStrongHashingAlgorithm(name) and isWeak = false
97+
or
98+
isWeakHashingAlgorithm(name) and isWeak = true
99+
} or
100+
MkEncryptionAlgorithm(string name, boolean isWeak) {
101+
isStrongEncryptionAlgorithm(name) and isWeak = false
102+
or
103+
isWeakEncryptionAlgorithm(name) and isWeak = true
104+
} or
105+
MkPasswordHashingAlgorithm(string name, boolean isWeak) {
106+
isStrongPasswordHashingAlgorithm(name) and isWeak = false
107+
or
108+
isWeakPasswordHashingAlgorithm(name) and isWeak = true
109+
}
110+
111+
/**
112+
* A cryptographic algorithm.
113+
*/
114+
abstract class CryptographicAlgorithm extends TCryptographicAlgorithm {
115+
/** Gets a textual representation of this element. */
116+
string toString() { result = getName() }
117+
118+
/**
119+
* Gets the name of this algorithm.
120+
*/
121+
abstract string getName();
122+
123+
/**
124+
* Holds if the name of this algorithm matches `name` modulo case,
125+
* white space, dashes and underscores.
126+
*/
127+
bindingset[name]
128+
predicate matchesName(string name) {
129+
exists(name.regexpReplaceAll("[-_]", "").regexpFind("(?i)\\Q" + getName() + "\\E", _, _))
130+
}
131+
132+
/**
133+
* Holds if this algorithm is weak.
134+
*/
135+
abstract predicate isWeak();
136+
}
137+
138+
/**
139+
* A hashing algorithm such as `MD5` or `SHA512`.
140+
*/
141+
class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm {
142+
string name;
143+
boolean isWeak;
144+
145+
HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) }
146+
147+
override string getName() { result = name }
148+
149+
override predicate isWeak() { isWeak = true }
150+
}
151+
152+
/**
153+
* An encryption algorithm such as `DES` or `AES512`.
154+
*/
155+
class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm {
156+
string name;
157+
boolean isWeak;
158+
159+
EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) }
160+
161+
override string getName() { result = name }
162+
163+
override predicate isWeak() { isWeak = true }
164+
}
165+
166+
/**
167+
* A password hashing algorithm such as `PBKDF2` or `SCRYPT`.
168+
*/
169+
class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm {
170+
string name;
171+
boolean isWeak;
172+
173+
PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) }
174+
175+
override string getName() { result = name }
176+
177+
override predicate isWeak() { isWeak = true }
178+
}
179+
180+
/**
181+
* An application of a cryptographic algorithm.
182+
*/
183+
abstract class CryptographicOperation extends DataFlow::Node {
184+
/**
185+
* Gets the input the algorithm is used on, e.g. the plain text input to be encrypted.
186+
*/
187+
abstract Expr getInput();
188+
189+
/**
190+
* Gets the applied algorithm.
191+
*/
192+
abstract CryptographicAlgorithm getAlgorithm();
193+
}
194+
195+
/**
196+
* Models cryptographic operations of the `crypto/md5` package.
197+
*/
198+
class Md5 extends CryptographicOperation, DataFlow::CallNode {
199+
Md5() { getTarget().hasQualifiedName("crypto/md5", ["New", "Sum"]) }
200+
201+
override Expr getInput() { result = this.getArgument(0).asExpr() }
202+
203+
override CryptographicAlgorithm getAlgorithm() {
204+
result.matchesName(this.getTarget().getPackage().getName())
205+
}
206+
}
207+
208+
/**
209+
* Models cryptographic operations of the `crypto/sha1` package.
210+
*/
211+
class Sha1 extends CryptographicOperation, DataFlow::CallNode {
212+
Sha1() { getTarget().hasQualifiedName("crypto/sha1", ["New", "Sum"]) }
213+
214+
override Expr getInput() { result = this.getArgument(0).asExpr() }
215+
216+
override CryptographicAlgorithm getAlgorithm() {
217+
result.matchesName(this.getTarget().getPackage().getName())
218+
}
219+
}
220+
221+
/**
222+
* Models cryptographic operations of the `crypto/des` package.
223+
*/
224+
class Des extends CryptographicOperation, DataFlow::CallNode {
225+
Des() { getTarget().hasQualifiedName("crypto/des", ["NewCipher", "NewTripleDESCipher"]) }
226+
227+
override Expr getInput() { result = this.getArgument(0).asExpr() }
228+
229+
override CryptographicAlgorithm getAlgorithm() {
230+
result.matchesName(this.getTarget().getPackage().getName())
231+
}
232+
}
233+
234+
/**
235+
* Models cryptographic operations of the `crypto/rc4` package.
236+
*/
237+
class Rc4 extends CryptographicOperation, DataFlow::CallNode {
238+
Rc4() { getTarget().hasQualifiedName("crypto/rc4", ["NewCipher"]) }
239+
240+
override Expr getInput() { result = this.getArgument(0).asExpr() }
241+
242+
override CryptographicAlgorithm getAlgorithm() {
243+
result.matchesName(this.getTarget().getPackage().getName())
244+
}
245+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
Using weak cryptographic algorithms can leave data
8+
vulnerable to being decrypted or forged by an attacker.
9+
</p>
10+
11+
<p>
12+
Many cryptographic algorithms provided by cryptography
13+
libraries are known to be weak. Using such an
14+
algorithm means that encrypted or hashed data is less
15+
secure than it appears to be.
16+
</p>
17+
18+
</overview>
19+
<recommendation>
20+
21+
<p>
22+
Ensure that you use a strong, modern cryptographic
23+
algorithm. Use at least AES-128 or RSA-2048 for
24+
encryption, and SHA-2 or SHA-3 for secure hashing.
25+
</p>
26+
27+
</recommendation>
28+
<example>
29+
30+
<p>
31+
The following code uses the different packages to encrypt/hash
32+
some secret data. The first few examples uses DES, MD5, RC4, and SHA1,
33+
which are older algorithms that are now considered weak. The following
34+
examples use AES and SHA256, which are stronger, more modern algorithms.
35+
</p>
36+
37+
<sample src="examples/Crypto.go" />
38+
39+
</example>
40+
41+
<references>
42+
<li>OWASP: <a
43+
href="https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html">Cryptographic Storage Cheat Sheet</a>.
44+
</li>
45+
<li>Wikipedia: <a
46+
href="https://en.wikipedia.org/wiki/Strong_cryptography#Cryptographically_strong_algorithms">Cryptographically Strong Algorithms</a>.
47+
</li>
48+
<li>Wikipedia: <a
49+
href="https://en.wikipedia.org/wiki/Strong_cryptography#Examples">Strong Cryptography Examples</a>.
50+
</li>
51+
<li>NIST, FIPS 140 Annex a: <a href="http://csrc.nist.gov/publications/fips/fips140-2/fips1402annexa.pdf"> Approved Security Functions</a>.</li>
52+
<li>NIST, SP 800-131A: <a href="http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-131Ar1.pdf"> Transitions: Recommendation for Transitioning the Use of Cryptographic Algorithms and Key Lengths</a>.</li>
53+
</references>
54+
55+
</qhelp>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @name Use of a weak cryptographic algorithm
3+
* @description Using weak cryptographic algorithms can allow an attacker to compromise security.
4+
* @kind path-problem
5+
* @problem.severity error
6+
* @id go/weak-crypto-algorithm
7+
* @tags security
8+
* external/cwe/cwe-327
9+
*/
10+
11+
import go
12+
import WeakCryptoAlgorithmCustomizations::WeakCryptoAlgorithm
13+
import DataFlow::PathGraph
14+
15+
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
16+
where cfg.hasFlowPath(source, sink)
17+
select sink.getNode(), source, sink, "$@ is used in a weak cryptographic algorithm.",
18+
source.getNode(), "Sensitive data"
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Provides default sources, sinks and sanitizers for reasoning about
3+
* sensitive information in weak cryptographic algorithms,
4+
* as well as extension points for adding your own.
5+
*/
6+
7+
import go
8+
private import semmle.go.security.SensitiveActions
9+
private import CryptoLibraries
10+
11+
module WeakCryptoAlgorithm {
12+
/**
13+
* A data flow source for sensitive information in weak cryptographic algorithms.
14+
*/
15+
abstract class Source extends DataFlow::Node { }
16+
17+
/**
18+
* A data flow sink for sensitive information in weak cryptographic algorithms.
19+
*/
20+
abstract class Sink extends DataFlow::Node { }
21+
22+
/**
23+
* A sanitizer for sensitive information in weak cryptographic algorithms.
24+
*/
25+
abstract class Sanitizer extends DataFlow::Node { }
26+
27+
/**
28+
* A sensitive source.
29+
*/
30+
class SensitiveSource extends Source {
31+
SensitiveSource() { this.asExpr() instanceof SensitiveExpr }
32+
}
33+
34+
/**
35+
* An expression used by a weak cryptographic algorithm.
36+
*/
37+
class WeakCryptographicOperationSink extends Sink {
38+
WeakCryptographicOperationSink() {
39+
exists(CryptographicOperation application |
40+
application.getAlgorithm().isWeak() and
41+
this.asExpr() = application.getInput()
42+
)
43+
}
44+
}
45+
46+
/**
47+
* A configuration depicting taint flow from sensitive information to weak cryptographic algorithms.
48+
*/
49+
class Configuration extends TaintTracking::Configuration {
50+
Configuration() { this = "WeakCryptoAlgorithm" }
51+
52+
override predicate isSource(DataFlow::Node source) { source instanceof Source }
53+
54+
override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
55+
56+
override predicate isSanitizer(DataFlow::Node node) {
57+
super.isSanitizer(node) or
58+
node instanceof Sanitizer
59+
}
60+
}
61+
}

0 commit comments

Comments
 (0)