-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add Go rule for weak rsa and dsa key sizes (#190)
Signed-off-by: Eric Brown <eric.brown@securesauce.dev>
- Loading branch information
Showing
9 changed files
with
263 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
# Copyright 2023 Secure Saurce LLC | ||
r""" | ||
================================================================ | ||
Inadequate Encryption Strength Using Weak Keys in Crypto Package | ||
================================================================ | ||
Using weak key sizes for cryptographic algorithms like RSA and DSA can | ||
compromise the security of your encryption and digital signatures. Here's a | ||
brief overview of the risks associated with weak key sizes for these | ||
algorithms: | ||
RSA (Rivest-Shamir-Adleman): | ||
RSA is widely used for both encryption and digital signatures. Weak key sizes | ||
in RSA can be vulnerable to factorization attacks, such as the famous RSA-129 | ||
challenge, which was factored in 1994 after 17 years of effort. Using small | ||
key sizes makes it easier for attackers to factor the modulus and recover | ||
the private key. | ||
It's generally recommended to use RSA key sizes of 2048 bits or more for | ||
security in the present day, with 3072 bits or higher being increasingly | ||
preferred for long-term security. | ||
DSA (Digital Signature Algorithm): | ||
DSA is used for digital signatures and relies on the discrete logarithm | ||
problem. Using weak key sizes in DSA can make it susceptible to attacks that | ||
involve solving the discrete logarithm problem, like the GNFS (General | ||
Number Field Sieve) algorithm. | ||
For DSA, key sizes of 2048 bits or more are recommended for modern security. | ||
Note that DSA is not as commonly used as RSA or ECC for new applications, and | ||
ECDSA (Elliptic Curve Digital Signature Algorithm) is often preferred due to | ||
its efficiency and strong security properties. | ||
------- | ||
Example | ||
------- | ||
.. code-block:: python | ||
:linenos: | ||
:emphasize-lines: 10 | ||
package main | ||
import ( | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"log" | ||
) | ||
func main() { | ||
privateKey, err := rsa.GenerateKey(rand.Reader, 1024) | ||
if err != nil { | ||
log.Fatalf("Failed to generate key: %v", err) | ||
} | ||
} | ||
----------- | ||
Remediation | ||
----------- | ||
Its recommended to increase the key size to at least 2048 for DSA and RSA | ||
algorithms. | ||
.. code-block:: python | ||
:linenos: | ||
:emphasize-lines: 10 | ||
package main | ||
import ( | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"log" | ||
) | ||
func main() { | ||
privateKey, err := rsa.GenerateKey(rand.Reader, 2048) | ||
if err != nil { | ||
log.Fatalf("Failed to generate key: %v", err) | ||
} | ||
} | ||
.. seealso:: | ||
- `Inadequate Encryption Strength Using Weak Keys in Crypto Package <https://docs.securesauce.dev/rules/GO003>`_ | ||
- `dsa package - crypto_dsa - Go Packages <https://pkg.go.dev/crypto/dsa#ParameterSizes>`_ | ||
- `rsa package - crypto_rsa - Go Packages <https://pkg.go.dev/crypto/rsa#GenerateKey>`_ | ||
- `CWE-326: Inadequate Encryption Strength <https://cwe.mitre.org/data/definitions/326.html>`_ | ||
.. versionadded:: 1.0.0 | ||
""" # noqa: E501 | ||
from precli.core.config import Config | ||
from precli.core.level import Level | ||
from precli.core.location import Location | ||
from precli.core.result import Result | ||
from precli.rules import Rule | ||
|
||
|
||
class WeakKey(Rule): | ||
def __init__(self, id: str): | ||
super().__init__( | ||
id=id, | ||
name="inadequate_encryption_strength", | ||
full_descr=__doc__, | ||
cwe_id=326, | ||
message="Using {} key sizes less than {} bits is considered " | ||
"vulnerable to attacks.", | ||
targets=("call"), | ||
wildcards={}, | ||
config=Config(enabled=False), | ||
) | ||
|
||
def analyze(self, context: dict, **kwargs: dict) -> Result: | ||
call = kwargs.get("call") | ||
|
||
if call.name_qualified in ["crypto/dsa.GenerateParameters"]: | ||
argument = call.get_argument(position=2) | ||
sizes = argument.value | ||
|
||
if sizes == "crypto/dsa.L1024N160": | ||
fixes = Rule.get_fixes( | ||
context=context, | ||
deleted_location=Location(node=argument.identifier_node), | ||
description="Use a minimum key size of 2048 for DSA keys.", | ||
inserted_content="L2048N224", | ||
) | ||
|
||
return Result( | ||
rule_id=self.id, | ||
location=Location( | ||
file_name=context["file_name"], | ||
node=argument.identifier_node, | ||
), | ||
level=Level.ERROR, | ||
message=self.message.format("DSA", 2048), | ||
fixes=fixes, | ||
) | ||
elif call.name_qualified in ["crypto/rsa.GenerateKey"]: | ||
argument = call.get_argument(position=1) | ||
bits = argument.value | ||
|
||
if bits < 2048: | ||
fixes = Rule.get_fixes( | ||
context=context, | ||
deleted_location=Location(node=argument.node), | ||
description="Use a minimum key size of 2048 for RSA keys.", | ||
inserted_content="2048", | ||
) | ||
|
||
return Result( | ||
rule_id=self.id, | ||
location=Location( | ||
file_name=context["file_name"], | ||
node=argument.node, | ||
), | ||
level=Level.ERROR if bits <= 1024 else Level.WARNING, | ||
message=self.message.format("RSA", 2048), | ||
fixes=fixes, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
tests/unit/rules/go/stdlib/crypto/examples/weak_cipher_des.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
// level: ERROR | ||
// start_line: 19 | ||
// end_line: 19 | ||
// start_column: 38 | ||
// end_column: 41 | ||
package main | ||
|
||
import ( | ||
|
5 changes: 5 additions & 0 deletions
5
tests/unit/rules/go/stdlib/crypto/examples/weak_hash_md5_new.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
// level: ERROR | ||
// start_line: 14 | ||
// end_line: 14 | ||
// start_column: 38 | ||
// end_column: 41 | ||
package main | ||
|
||
import ( | ||
|
5 changes: 5 additions & 0 deletions
5
tests/unit/rules/go/stdlib/crypto/examples/weak_hash_sha1_new.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,8 @@ | ||
// level: ERROR | ||
// start_line: 9 | ||
// end_line: 9 | ||
// start_column: 38 | ||
// end_column: 41 | ||
package main | ||
|
||
import ( | ||
|
41 changes: 41 additions & 0 deletions
41
tests/unit/rules/go/stdlib/crypto/examples/weak_key_dsa_1024.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// level: ERROR | ||
// start_line: 21 | ||
// end_line: 21 | ||
// start_column: 38 | ||
// end_column: 41 | ||
package main | ||
|
||
import ( | ||
"crypto/dsa" | ||
"crypto/rand" | ||
"fmt" | ||
"log" | ||
"math/big" | ||
) | ||
|
||
func main() { | ||
// Define DSA parameters | ||
var params dsa.Parameters | ||
|
||
// Generate DSA parameters; here we choose a 1024-bit key size | ||
if err := dsa.GenerateParameters(¶ms, rand.Reader, dsa.L1024N160); err != nil { | ||
log.Fatalf("Failed to generate DSA parameters: %v", err) | ||
} | ||
|
||
// Generate DSA keys | ||
privateKey := new(dsa.PrivateKey) | ||
privateKey.PublicKey.Parameters = params | ||
if err := dsa.GenerateKey(privateKey, rand.Reader); err != nil { | ||
log.Fatalf("Failed to generate DSA key: %v", err) | ||
} | ||
|
||
// Extract the public key | ||
publicKey := privateKey.PublicKey | ||
|
||
// Print the public key | ||
fmt.Printf("Public Key:\n P:%s\n Q:%s\n G:%s\n Y:%s\n", | ||
publicKey.P.String(), publicKey.Q.String(), publicKey.G.String(), publicKey.Y.String()) | ||
|
||
// Print the private key | ||
fmt.Printf("Private Key:\n X:%s\n", privateKey.X.String()) | ||
} |
39 changes: 39 additions & 0 deletions
39
tests/unit/rules/go/stdlib/crypto/examples/weak_key_rsa_1024.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// level: ERROR | ||
// start_line: 18 | ||
// end_line: 18 | ||
// start_column: 38 | ||
// end_column: 41 | ||
package main | ||
|
||
import ( | ||
"crypto/rand" | ||
"crypto/rsa" | ||
"crypto/x509" | ||
"encoding/pem" | ||
"log" | ||
) | ||
|
||
func main() { | ||
// Generate the RSA key | ||
privateKey, err := rsa.GenerateKey(rand.Reader, 1024) | ||
if err != nil { | ||
log.Fatalf("Failed to generate key: %v", err) | ||
} | ||
|
||
// Extract the public key from the private key | ||
publicKey := &privateKey.PublicKey | ||
|
||
// Encode the public key to PEM format | ||
publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey) | ||
if err != nil { | ||
log.Fatalf("Failed to marshal public key: %v", err) | ||
} | ||
|
||
publicKeyPEM := pem.EncodeToMemory(&pem.Block{ | ||
Type: "RSA PUBLIC KEY", | ||
Bytes: publicKeyBytes, | ||
}) | ||
|
||
// Print the public key | ||
log.Println(string(publicKeyPEM)) | ||
} |