Skip to content

Commit

Permalink
Add golang_org_x_weak_cipher and testing (#194)
Browse files Browse the repository at this point in the history
Signed-off-by: Eric Brown <eric.brown@securesauce.dev>
  • Loading branch information
ericwb committed Jan 2, 2024
1 parent 6b329ac commit b77d788
Show file tree
Hide file tree
Showing 12 changed files with 405 additions and 3 deletions.
155 changes: 155 additions & 0 deletions precli/rules/go/golang_org_x_crypto/weak_cipher.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright 2024 Secure Saurce LLC
r"""
====================================================================
Use of a Broken or Risky Cryptographic Algorithm in X Crypto Package
====================================================================
Using weak ciphers for cryptographic algorithms can pose significant security
risks, and it's generally advised to avoid them in favor of stronger, more
secure algorithms. Here's some guidance that advises against using weak
ciphers like Blowfish, CAST5, TEA/XTEA, and Twofish:
Blowfish: Developed in 1993, Blowfish is a block cipher known for its
simplicity. However, its small block size of 64 bits makes it susceptible to
birthday attacks in modern contexts. This vulnerability is significant when
encrypting large amounts of data, which is common in current applications.
CAST5 (CAST-128): CAST5, a symmetric encryption algorithm, suffers from
similar issues as Blowfish due to its 64-bit block size. While it was
considered secure for its time, modern applications typically require
algorithms with larger block sizes for enhanced security.
TEA/XTEA: The Tiny Encryption Algorithm (TEA) and its successor, eXtended
TEA (XTEA), are lightweight block ciphers. They are notable for their
simplicity and ease of implementation but have known vulnerabilities,
including susceptibility to differential cryptanalysis. These weaknesses
make them less suitable for applications where strong security is a priority.
Twofish: As a finalist in the Advanced Encryption Standard (AES) competition,
Twofish is a respected algorithm. However, it was not selected as the
standard, and over time, AES has become the more tested and trusted choice
in most cryptographic applications.
In summary, there is a consensus among reputable standards organizations,
industry experts, and security professionals that weak ciphers like Blowfish,
CAST5, TEA/XTEA, and Twofish should be avoided due to their known
vulnerabilities and weaknesses. Instead, it is advisable to use stronger,
more secure cryptographic algorithms and adhere to industry best practices
and regulatory requirements for encryption and security.
-------
Example
-------
.. code-block:: python
:linenos:
:emphasize-lines: 11
package main
import (
"log"
"golang.org/x/crypto/twofish"
)
func main() {
key := []byte("examplekey123456")
_, err := twofish.NewCipher(key)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
-----------
Remediation
-----------
It is advisable to use stronger, more secure cryptographic algorithms such as
AES.
.. code-block:: python
:linenos:
:emphasize-lines: 5,11
package main
import (
"log"
"crypto/aes"
)
func main() {
key := []byte("examplekey123456")
_, err := aes.NewCipher(key)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
.. seealso::
- `Use of a Broken or Risky Cryptographic Algorithm in Crypto Package <https://docs.securesauce.dev/rules/GO502>`_
- `blowfish package - golang.org_x_crypto_twofish - Go Packages <https://pkg.go.dev/golang.org/x/crypto/blowfish>`_
- `cast5 package - golang.org_x_crypto_twofish - Go Packages <https://pkg.go.dev/golang.org/x/crypto/cast5>`_
- `tea package - golang.org_x_crypto_twofish - Go Packages <https://pkg.go.dev/golang.org/x/crypto/tea>`_
- `twofish package - golang.org_x_crypto_twofish - Go Packages <https://pkg.go.dev/golang.org/x/crypto/twofish>`_
- `xtea package - golang.org_x_crypto_twofish - Go Packages <https://pkg.go.dev/golang.org/x/crypto/xtea>`_
- `CWE-327: Use of a Broken or Risky Cryptographic Algorithm <https://cwe.mitre.org/data/definitions/327.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 WeakCipher(Rule):
def __init__(self, id: str):
super().__init__(
id=id,
name="use_of_a_broken_or_risky_cryptographic_algorithm",
full_descr=__doc__,
cwe_id=327,
message="Weak ciphers like {} should be avoided due to their "
"known vulnerabilities and weaknesses.",
targets=("call"),
wildcards={},
config=Config(enabled=False),
)

def analyze(self, context: dict, **kwargs: dict) -> Result:
call = kwargs.get("call")

if call.name_qualified in [
"golang.org/x/crypto/blowfish.NewCipher",
"golang.org/x/crypto/blowfish.NewSaltedCipher",
"golang.org/x/crypto/cast5.NewCipher",
"golang.org/x/crypto/tea.NewCipher",
"golang.org/x/crypto/tea.NewCipherWithRounds",
"golang.org/x/crypto/twofish.NewCipher",
"golang.org/x/crypto/xtea.NewCipher",
]:
# TODO: Need to remove arguments for NewSaltedCipher and
# NewCipherWithRounds
fixes = Rule.get_fixes(
context=context,
deleted_location=Location(node=call.function_node),
description="It is advisable to use a stronger, more "
"secure cryptographic algorithm like AES.",
inserted_content="aes.NewCipher",
)
return Result(
rule_id=self.id,
location=Location(
file_name=context["file_name"],
node=call.function_node,
),
level=Level.ERROR,
message=self.message.format(call.name),
fixes=fixes,
)
4 changes: 3 additions & 1 deletion precli/rules/go/golang_org_x_crypto/weak_hash.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
.. seealso::
- `Reversible One Way Hash in X Crypto Package <https://docs.securesauce.dev/rules/GO502>`_
- `Reversible One Way Hash in X Crypto Package <https://docs.securesauce.dev/rules/GO503>`_
- `md4 package - golang.org_x_crypto_md4 - Go Packages <https://pkg.go.dev/golang.org/x/crypto/md4>`_
- `ripemd160 package - golang.org_x_crypto_ripemd160 - Go Packages <https://pkg.go.dev/golang.org/x/crypto/ripemd160>`_
- `CWE-328: Use of Weak Hash <https://cwe.mitre.org/data/definitions/328.html>`_
Expand All @@ -76,6 +76,7 @@
.. 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
Expand All @@ -93,6 +94,7 @@ def __init__(self, id: str):
"expectations.",
targets=("call"),
wildcards={},
config=Config(enabled=False),
)

def analyze(self, context: dict, **kwargs: dict) -> Result:
Expand Down
5 changes: 4 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ precli.rules.go =
# precli/rules/go/golang_org_x_crypto/ssh_insecure_ignore_hostkey.py
GO501 = precli.rules.go.golang_org_x_crypto.ssh_insecure_ignore_hostkey:SshInsecureIgnoreHostKey

# precli/rules/go/golang_org_x_crypto/weak_cipher.py
GO502 = precli.rules.go.golang_org_x_crypto.weak_cipher:WeakCipher

# precli/rules/go/golang_org_x_crypto/weak_hash.py
GO502 = precli.rules.go.golang_org_x_crypto.weak_hash:WeakHash
GO503 = precli.rules.go.golang_org_x_crypto.weak_hash:WeakHash

precli.rules.python =
# precli/rules/python/stdlib/assert/assert.py
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// level: ERROR
// start_line: 17
// end_line: 17
// start_column: 14
// end_column: 32
package main

import (
"log"

"golang.org/x/crypto/blowfish"
)

func main() {
key := []byte("examplekey123456")

_, err := blowfish.NewCipher(key)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// level: ERROR
// start_line: 18
// end_line: 18
// start_column: 14
// end_column: 38
package main

import (
"log"

"golang.org/x/crypto/blowfish"
)

func main() {
key := []byte("examplekey123456")
salt := []byte("1234567890abcdef")

_, err := blowfish.NewSaltedCipher(key, salt)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// level: ERROR
// start_line: 17
// end_line: 17
// start_column: 14
// end_column: 29
package main

import (
"log"

"golang.org/x/crypto/cast5"
)

func main() {
key := []byte("examplekey123456")

_, err := cast5.NewCipher(key)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// level: ERROR
// start_line: 17
// end_line: 17
// start_column: 14
// end_column: 27
package main

import (
"log"

"golang.org/x/crypto/tea"
)

func main() {
key := []byte("examplekey123456")

_, err := tea.NewCipher(key)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// level: ERROR
// start_line: 17
// end_line: 17
// start_column: 14
// end_column: 37
package main

import (
"log"

"golang.org/x/crypto/tea"
)

func main() {
key := []byte("examplekey123456")

_, err := tea.NewCipherWithRounds(key, 64)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// level: ERROR
// start_line: 35
// end_line: 35
// start_column: 18
// end_column: 35
package main

import (
"crypto/cipher"
"encoding/hex"
"fmt"
"golang.org/x/crypto/twofish"
"log"
)

// pkcs7Pad pads the plaintext to be a multiple of the block size
func pkcs7Pad(plaintext []byte, blockSize int) []byte {
padding := blockSize - len(plaintext)%blockSize
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
return append(plaintext, padtext...)
}

// pkcs7Unpad removes the padding from the plaintext
func pkcs7Unpad(plaintext []byte) []byte {
length := len(plaintext)
padLen := int(plaintext[length-1])
return plaintext[:(length - padLen)]
}

func main() {
// Twofish key (can be 16, 24, or 32 bytes)
key := []byte("examplekey123456") // 16 bytes for a 128-bit key

// Create a new Twofish cipher block with the key
block, err := twofish.NewCipher(key)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}

// The plaintext that needs to be encrypted
plaintext := []byte("Hello, Twofish!")

// Pad plaintext to be a multiple of the block size
paddedPlaintext := pkcs7Pad(plaintext, twofish.BlockSize)

ciphertext := make([]byte, len(paddedPlaintext))
for i := 0; i < len(paddedPlaintext); i += twofish.BlockSize {
block.Encrypt(ciphertext[i:i+twofish.BlockSize], paddedPlaintext[i:i+twofish.BlockSize])
}

fmt.Printf("Ciphertext: %x\n", ciphertext)

// Decrypting the ciphertext
decrypted := make([]byte, len(ciphertext))
for i := 0; i < len(ciphertext); i += twofish.BlockSize {
block.Decrypt(decrypted[i:i+twofish.BlockSize], ciphertext[i:i+twofish.BlockSize])
}

// Remove padding
decrypted = pkcs7Unpad(decrypted)

fmt.Printf("Decrypted: %s\n", decrypted)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// level: ERROR
// start_line: 17
// end_line: 17
// start_column: 14
// end_column: 28
package main

import (
"log"

"golang.org/x/crypto/xtea"
)

func main() {
key := []byte("examplekey123456")

_, err := xtea.NewCipher(key)
if err != nil {
log.Fatalf("Failed to create cipher: %v", err)
}
}
Loading

0 comments on commit b77d788

Please sign in to comment.