Skip to content

Commit f6fe627

Browse files
authored
Merge pull request #11914 from geoffw0/rncrypt3
Swift: Add RNCryptor sinks to swift/constant-salt
2 parents 3dd9392 + b3d30bf commit f6fe627

File tree

3 files changed

+134
-2
lines changed

3 files changed

+134
-2
lines changed

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

+10-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ import DataFlow::PathGraph
2222
class ConstantSaltSource extends Expr {
2323
ConstantSaltSource() {
2424
this = any(ArrayExpr arr | arr.getType().getName() = "Array<UInt8>") or
25-
this instanceof StringLiteralExpr
25+
this instanceof StringLiteralExpr or
26+
this instanceof NumberLiteralExpr
2627
}
2728
}
2829

@@ -38,6 +39,14 @@ class ConstantSaltSink extends Expr {
3839
call.getStaticTarget() = f and
3940
call.getArgumentWithLabel("salt").getExpr() = this
4041
)
42+
or
43+
// RNCryptor
44+
exists(ClassOrStructDecl c, MethodDecl f, CallExpr call |
45+
c.getFullName() = ["RNCryptor", "RNEncryptor", "RNDecryptor"] and
46+
c.getAMember() = f and
47+
call.getStaticTarget() = f and
48+
call.getArgumentWithLabel(["salt", "encryptionSalt", "hmacSalt", "HMACSalt"]).getExpr() = this
49+
)
4150
}
4251
}
4352

Original file line numberDiff line numberDiff line change
@@ -1,17 +1,60 @@
11
edges
2+
| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : |
3+
| rncryptor.swift:59:24:59:43 | call to Data.init(_:) : | rncryptor.swift:63:57:63:57 | myConstantSalt1 |
4+
| rncryptor.swift:59:24:59:43 | call to Data.init(_:) : | rncryptor.swift:68:106:68:106 | myConstantSalt1 |
5+
| rncryptor.swift:59:24:59:43 | call to Data.init(_:) : | rncryptor.swift:71:106:71:106 | myConstantSalt1 |
6+
| rncryptor.swift:59:24:59:43 | call to Data.init(_:) : | rncryptor.swift:75:127:75:127 | myConstantSalt1 |
7+
| rncryptor.swift:59:24:59:43 | call to Data.init(_:) : | rncryptor.swift:78:135:78:135 | myConstantSalt1 |
8+
| rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : |
9+
| rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:59:24:59:43 | call to Data.init(_:) : |
10+
| rncryptor.swift:60:24:60:30 | call to Data.init(_:) : | rncryptor.swift:65:55:65:55 | myConstantSalt2 |
11+
| rncryptor.swift:60:24:60:30 | call to Data.init(_:) : | rncryptor.swift:69:131:69:131 | myConstantSalt2 |
12+
| rncryptor.swift:60:24:60:30 | call to Data.init(_:) : | rncryptor.swift:72:131:72:131 | myConstantSalt2 |
13+
| rncryptor.swift:60:24:60:30 | call to Data.init(_:) : | rncryptor.swift:76:152:76:152 | myConstantSalt2 |
14+
| rncryptor.swift:60:24:60:30 | call to Data.init(_:) : | rncryptor.swift:79:160:79:160 | myConstantSalt2 |
15+
| rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : |
16+
| rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:60:24:60:30 | call to Data.init(_:) : |
217
| test.swift:43:35:43:130 | [...] : | test.swift:51:49:51:49 | constantSalt |
318
| test.swift:43:35:43:130 | [...] : | test.swift:56:59:56:59 | constantSalt |
419
| test.swift:43:35:43:130 | [...] : | test.swift:62:59:62:59 | constantSalt |
520
| test.swift:43:35:43:130 | [...] : | test.swift:67:53:67:53 | constantSalt |
621
nodes
22+
| file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | semmle.label | [summary] to write: return (return) in Data.init(_:) : |
23+
| rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | semmle.label | [summary param] 0 in Data.init(_:) : |
24+
| rncryptor.swift:59:24:59:43 | call to Data.init(_:) : | semmle.label | call to Data.init(_:) : |
25+
| rncryptor.swift:59:29:59:29 | abcdef123456 : | semmle.label | abcdef123456 : |
26+
| rncryptor.swift:60:24:60:30 | call to Data.init(_:) : | semmle.label | call to Data.init(_:) : |
27+
| rncryptor.swift:60:29:60:29 | 0 : | semmle.label | 0 : |
28+
| rncryptor.swift:63:57:63:57 | myConstantSalt1 | semmle.label | myConstantSalt1 |
29+
| rncryptor.swift:65:55:65:55 | myConstantSalt2 | semmle.label | myConstantSalt2 |
30+
| rncryptor.swift:68:106:68:106 | myConstantSalt1 | semmle.label | myConstantSalt1 |
31+
| rncryptor.swift:69:131:69:131 | myConstantSalt2 | semmle.label | myConstantSalt2 |
32+
| rncryptor.swift:71:106:71:106 | myConstantSalt1 | semmle.label | myConstantSalt1 |
33+
| rncryptor.swift:72:131:72:131 | myConstantSalt2 | semmle.label | myConstantSalt2 |
34+
| rncryptor.swift:75:127:75:127 | myConstantSalt1 | semmle.label | myConstantSalt1 |
35+
| rncryptor.swift:76:152:76:152 | myConstantSalt2 | semmle.label | myConstantSalt2 |
36+
| rncryptor.swift:78:135:78:135 | myConstantSalt1 | semmle.label | myConstantSalt1 |
37+
| rncryptor.swift:79:160:79:160 | myConstantSalt2 | semmle.label | myConstantSalt2 |
738
| test.swift:43:35:43:130 | [...] : | semmle.label | [...] : |
839
| test.swift:51:49:51:49 | constantSalt | semmle.label | constantSalt |
940
| test.swift:56:59:56:59 | constantSalt | semmle.label | constantSalt |
1041
| test.swift:62:59:62:59 | constantSalt | semmle.label | constantSalt |
1142
| test.swift:67:53:67:53 | constantSalt | semmle.label | constantSalt |
1243
subpaths
44+
| rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | rncryptor.swift:59:24:59:43 | call to Data.init(_:) : |
45+
| rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:5:5:5:29 | [summary param] 0 in Data.init(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in Data.init(_:) : | rncryptor.swift:60:24:60:30 | call to Data.init(_:) : |
1346
#select
47+
| rncryptor.swift:63:57:63:57 | myConstantSalt1 | rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:63:57:63:57 | myConstantSalt1 | The value 'abcdef123456' is used as a constant salt, which is insecure for hashing passwords. |
48+
| rncryptor.swift:65:55:65:55 | myConstantSalt2 | rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:65:55:65:55 | myConstantSalt2 | The value '0' is used as a constant salt, which is insecure for hashing passwords. |
49+
| rncryptor.swift:68:106:68:106 | myConstantSalt1 | rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:68:106:68:106 | myConstantSalt1 | The value 'abcdef123456' is used as a constant salt, which is insecure for hashing passwords. |
50+
| rncryptor.swift:69:131:69:131 | myConstantSalt2 | rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:69:131:69:131 | myConstantSalt2 | The value '0' is used as a constant salt, which is insecure for hashing passwords. |
51+
| rncryptor.swift:71:106:71:106 | myConstantSalt1 | rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:71:106:71:106 | myConstantSalt1 | The value 'abcdef123456' is used as a constant salt, which is insecure for hashing passwords. |
52+
| rncryptor.swift:72:131:72:131 | myConstantSalt2 | rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:72:131:72:131 | myConstantSalt2 | The value '0' is used as a constant salt, which is insecure for hashing passwords. |
53+
| rncryptor.swift:75:127:75:127 | myConstantSalt1 | rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:75:127:75:127 | myConstantSalt1 | The value 'abcdef123456' is used as a constant salt, which is insecure for hashing passwords. |
54+
| rncryptor.swift:76:152:76:152 | myConstantSalt2 | rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:76:152:76:152 | myConstantSalt2 | The value '0' is used as a constant salt, which is insecure for hashing passwords. |
55+
| rncryptor.swift:78:135:78:135 | myConstantSalt1 | rncryptor.swift:59:29:59:29 | abcdef123456 : | rncryptor.swift:78:135:78:135 | myConstantSalt1 | The value 'abcdef123456' is used as a constant salt, which is insecure for hashing passwords. |
56+
| rncryptor.swift:79:160:79:160 | myConstantSalt2 | rncryptor.swift:60:29:60:29 | 0 : | rncryptor.swift:79:160:79:160 | myConstantSalt2 | The value '0' is used as a constant salt, which is insecure for hashing passwords. |
1457
| test.swift:51:49:51:49 | constantSalt | test.swift:43:35:43:130 | [...] : | test.swift:51:49:51:49 | constantSalt | The value '[...]' is used as a constant salt, which is insecure for hashing passwords. |
1558
| test.swift:56:59:56:59 | constantSalt | test.swift:43:35:43:130 | [...] : | test.swift:56:59:56:59 | constantSalt | The value '[...]' is used as a constant salt, which is insecure for hashing passwords. |
1659
| test.swift:62:59:62:59 | constantSalt | test.swift:43:35:43:130 | [...] : | test.swift:62:59:62:59 | constantSalt | The value '[...]' is used as a constant salt, which is insecure for hashing passwords. |
17-
| test.swift:67:53:67:53 | constantSalt | test.swift:43:35:43:130 | [...] : | test.swift:67:53:67:53 | constantSalt | The value '[...]' is used as a constant salt, which is insecure for hashing passwords. |
60+
| test.swift:67:53:67:53 | constantSalt | test.swift:43:35:43:130 | [...] : | test.swift:67:53:67:53 | constantSalt | The value '[...]' is used as a constant salt, which is insecure for hashing passwords. |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
2+
// --- stubs ---
3+
4+
class Data {
5+
init<S>(_ elements: S) {}
6+
}
7+
8+
class NSObject
9+
{
10+
}
11+
12+
struct _RNCryptorSettings {
13+
// ...
14+
}
15+
typealias RNCryptorSettings = _RNCryptorSettings
16+
17+
let kRNCryptorAES256Settings = RNCryptorSettings()
18+
19+
struct _RNCryptorKeyDerivationSettings {
20+
// ...
21+
}
22+
typealias RNCryptorKeyDerivationSettings = _RNCryptorKeyDerivationSettings
23+
24+
typealias RNCryptorHandler = () -> Void // simplified
25+
26+
class RNCryptor : NSObject
27+
{
28+
func key(forPassword password: String?, salt: Data?, settings keySettings: RNCryptorKeyDerivationSettings) -> Data? { return nil }
29+
func keyForPassword(_ password: String?, salt: Data?, settings keySettings: RNCryptorKeyDerivationSettings) -> Data? { return nil }
30+
}
31+
32+
class RNEncryptor : RNCryptor
33+
{
34+
override init() {}
35+
36+
init(settings: RNCryptorSettings, password: String, iv anIV: Data?, encryptionSalt anEncryptionSalt: Data?, hmacSalt anHMACSalt: Data?, handler: RNCryptorHandler?) {}
37+
init(settings: RNCryptorSettings, password: String, IV anIV: Data?, encryptionSalt anEncryptionSalt: Data?, HMACSalt anHMACSalt: Data?, handler: RNCryptorHandler?) {}
38+
39+
func encryptData(_ data: Data?, with settings: RNCryptorSettings, password: String?, iv anIV: Data?, encryptionSalt anEncryptionSalt: Data?, hmacSalt anHMACSalt: Data?) throws -> Data { return Data(0) }
40+
func encryptData(_ data: Data?, withSettings settings: RNCryptorSettings, password: String?, IV anIV: Data?, encryptionSalt anEncryptionSalt: Data?, HMACSalt anHMACSalt: Data?) throws -> Data { return Data(0) }
41+
}
42+
43+
// --- tests ---
44+
45+
func getARandomString() -> String {
46+
let charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
47+
return String("................".map{_ in charset.randomElement()!})
48+
}
49+
50+
func test(myPassword: String) {
51+
// RNCryptor
52+
let myEncryptor = RNEncryptor()
53+
let myData = Data(0)
54+
let myKeyDerivationSettings = RNCryptorKeyDerivationSettings()
55+
let myHandler = {}
56+
let myIV = Data(0)
57+
let myRandomSalt1 = Data(getARandomString())
58+
let myRandomSalt2 = Data(getARandomString())
59+
let myConstantSalt1 = Data("abcdef123456")
60+
let myConstantSalt2 = Data(0)
61+
62+
let _ = myEncryptor.key(forPassword: myPassword, salt: myRandomSalt1, settings: myKeyDerivationSettings) // GOOD
63+
let _ = myEncryptor.key(forPassword: myPassword, salt: myConstantSalt1, settings: myKeyDerivationSettings) // BAD
64+
let _ = myEncryptor.keyForPassword(myPassword, salt: myRandomSalt2, settings: myKeyDerivationSettings) // GOOD
65+
let _ = myEncryptor.keyForPassword(myPassword, salt: myConstantSalt2, settings: myKeyDerivationSettings) // BAD
66+
67+
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myRandomSalt2, handler: myHandler) // GOOD
68+
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myConstantSalt1, hmacSalt: myRandomSalt2, handler: myHandler) // BAD
69+
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myConstantSalt2, handler: myHandler) // BAD
70+
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myRandomSalt2, handler: myHandler) // GOOD
71+
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myConstantSalt1, HMACSalt: myRandomSalt2, handler: myHandler) // BAD
72+
let _ = RNEncryptor(settings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myConstantSalt2, handler: myHandler) // BAD
73+
74+
let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myRandomSalt2) // GOOD
75+
let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myConstantSalt1, hmacSalt: myRandomSalt2) // BAD
76+
let _ = try? myEncryptor.encryptData(myData, with: kRNCryptorAES256Settings, password: myPassword, iv: myIV, encryptionSalt: myRandomSalt1, hmacSalt: myConstantSalt2) // BAD
77+
let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myRandomSalt2) // GOOD
78+
let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myConstantSalt1, HMACSalt: myRandomSalt2) // BAD
79+
let _ = try? myEncryptor.encryptData(myData, withSettings: kRNCryptorAES256Settings, password: myPassword, IV: myIV, encryptionSalt: myRandomSalt1, HMACSalt: myConstantSalt2) // BAD
80+
}

0 commit comments

Comments
 (0)