diff --git a/src/main/java/org/pqca/scanning/go/GoScannerService.java b/src/main/java/org/pqca/scanning/go/GoScannerService.java index 29b5a3d..e19676e 100644 --- a/src/main/java/org/pqca/scanning/go/GoScannerService.java +++ b/src/main/java/org/pqca/scanning/go/GoScannerService.java @@ -26,7 +26,7 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; -import java.util.UUID; +import org.apache.commons.io.FileUtils; import org.pqca.errors.ClientDisconnected; import org.pqca.indexing.ProjectModule; import org.pqca.progress.IProgressDispatcher; @@ -46,8 +46,6 @@ public final class GoScannerService extends ScannerService { - private final GoConverter goConverter; - public GoScannerService(@Nonnull File projectDirectory) { this(null, projectDirectory); } @@ -55,27 +53,6 @@ public GoScannerService(@Nonnull File projectDirectory) { public GoScannerService( @Nullable IProgressDispatcher progressDispatcher, @Nonnull File projectDirectory) { super(progressDispatcher, projectDirectory); - - try { - DefaultTempFolder tempFolder = new DefaultTempFolder(createDirectory()); - goConverter = new GoConverter(tempFolder.newDir()); - } catch (IOException ioe) { - throw new IllegalStateException(ioe); - } - } - - @Nonnull - private File createDirectory() throws IOException { - // create directory - final String folderId = UUID.randomUUID().toString().replace("-", ""); - final File tempDir = new File(this.projectDirectory + File.separator + folderId); - if (tempDir.exists()) { - throw new IOException("Temp dir already exists " + tempDir.getPath()); - } - if (!tempDir.mkdirs()) { - throw new IOException("Could not create temp dir" + tempDir.getPath()); - } - return tempDir; } @Override @@ -88,31 +65,45 @@ private File createDirectory() throws IOException { int numberOfScannedLines = 0; int numberOfScannedFiles = 0; - GoCheck visitor = new GoDetectionCollectionRule(this); - GoChecks checks = new GoRuleChecks(visitor); - final SensorContextTester sensorContext = SensorContextTester.create(projectDirectory); - // Go scanner (CryptoGoSensor) reads files from context - index.forEach(project -> project.inputFileList().forEach(sensorContext.fileSystem()::add)); - - for (ProjectModule project : index) { - numberOfScannedFiles += project.inputFileList().size(); - numberOfScannedLines += - project.inputFileList().stream().mapToInt(InputFile::lines).sum(); - - final String projectStr = - project.identifier() + " (" + counter + "/" + index.size() + ")"; - if (this.progressDispatcher != null) { - this.progressDispatcher.send( - new ProgressMessage( - ProgressMessageType.LABEL, "Scanning go project " + projectStr)); - } - LOGGER.info("Scanning go project {}", projectStr); - - CryptoGoSensor.execute((SensorContext) sensorContext, goConverter, checks); + File goTempFolder = new DefaultTempFolder(this.projectDirectory).newDir(); - counter += 1; + try { + GoConverter goConverter = new GoConverter(goTempFolder); + GoCheck visitor = new GoDetectionCollectionRule(this); + GoChecks checks = new GoRuleChecks(visitor); + final SensorContextTester sensorContext = SensorContextTester.create(projectDirectory); + + // Go scanner (CryptoGoSensor) reads files from context + index.forEach( + project -> project.inputFileList().forEach(sensorContext.fileSystem()::add)); + + for (ProjectModule project : index) { + numberOfScannedFiles += project.inputFileList().size(); + numberOfScannedLines += + project.inputFileList().stream().mapToInt(InputFile::lines).sum(); + + final String projectStr = + project.identifier() + " (" + counter + "/" + index.size() + ")"; + if (this.progressDispatcher != null) { + this.progressDispatcher.send( + new ProgressMessage( + ProgressMessageType.LABEL, + "Scanning go project " + projectStr)); + } + LOGGER.info("Scanning go project {}", projectStr); + + CryptoGoSensor.execute((SensorContext) sensorContext, goConverter, checks); + + counter += 1; + } + LOGGER.info("Scanned {} go projects", index.size()); + } finally { + try { + FileUtils.deleteDirectory(goTempFolder); + } catch (IOException e) { + LOGGER.error("Failed to delete temp dir {}", goTempFolder); + } } - LOGGER.info("Scanned {} go projects", index.size()); return new ScanResultDTO( scanTimeStart, @@ -134,7 +125,6 @@ public List all() { return this.checks; } - @SuppressWarnings("null") public RuleKey ruleKey(GoCheck check) { return RuleKey.of("sonar-cryptography", "go-rule"); } diff --git a/src/test/java/org/pqca/indexing/GoIndexServiceTest.java b/src/test/java/org/pqca/indexing/GoIndexServiceTest.java index 3611860..5cb7f30 100644 --- a/src/test/java/org/pqca/indexing/GoIndexServiceTest.java +++ b/src/test/java/org/pqca/indexing/GoIndexServiceTest.java @@ -32,11 +32,21 @@ class GoIndexServiceTest { @Test void testDefaultExclusion() throws ClientDisconnected { final GoIndexService goIndexService = - new GoIndexService(new File("src/test/testdata/go/simple")); + new GoIndexService(new File("src/test/testdata/go/gocrypto")); final List projectModules = goIndexService.index(null); assertThat(projectModules).hasSize(1); - assertThat(projectModules.getFirst().inputFileList()) - .extracting(Object::toString) - .containsExactlyInAnyOrder("go.mod", "module1/file.go"); + assertThat(projectModules.getFirst().identifier()).isEqualTo(""); + assertThat(projectModules.getFirst().inputFileList()).hasSize(36); + } + + @Test + void testCustomExclusion() throws ClientDisconnected { + final GoIndexService goIndexService = + new GoIndexService(new File("src/test/testdata/go/gocrypto")); + goIndexService.setExcludePatterns(List.of("RSA")); + final List projectModules = goIndexService.index(null); + assertThat(projectModules).hasSize(1); + assertThat(projectModules.getFirst().identifier()).isEqualTo(""); + assertThat(projectModules.getFirst().inputFileList()).hasSize(31); } } diff --git a/src/test/java/org/pqca/scanning/GoScannerServiceTest.java b/src/test/java/org/pqca/scanning/GoScannerServiceTest.java new file mode 100644 index 0000000..1ee297e --- /dev/null +++ b/src/test/java/org/pqca/scanning/GoScannerServiceTest.java @@ -0,0 +1,88 @@ +/* + * CBOMkit-lib + * Copyright (C) 2025 PQCA + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.pqca.scanning; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.File; +import java.util.List; +import org.junit.jupiter.api.Test; +import org.pqca.errors.ClientDisconnected; +import org.pqca.indexing.ProjectModule; +import org.pqca.indexing.go.GoIndexService; +import org.pqca.scanning.go.GoScannerService; +import org.pqca.utils.AssertableCBOM; + +class GoScannerServiceTest { + + @Test + void test() throws ClientDisconnected { + // indexing + final File projectDirectory = new File("src/test/testdata/go/gocrypto"); + final GoIndexService goIndexService = new GoIndexService(projectDirectory); + final List goModules = goIndexService.index(null); + assertThat(goModules).hasSize(1); + final ProjectModule projectModule = goModules.getFirst(); + assertThat(projectModule.inputFileList()).isNotEmpty(); + // scanning + final GoScannerService goScannerService = new GoScannerService(projectDirectory); + ScanResultDTO scanResult = goScannerService.scan(goModules); + + // check - verify cryptographic assets are detected + AssertableCBOM assertableCBOM = new AssertableCBOM(scanResult.cbom()); + assertThat(scanResult.cbom().cycloneDXbom().getComponents()).hasSize(27); + assertableCBOM.hasNumberOfDetections(69); + + assertThat( + assertableCBOM.hasDetectionWithNameAt( + "SHA256", + "src/test/testdata/go/gocrypto/GoCryptoSHA256TestFile.go", + 10)) + .isTrue(); + + assertThat( + assertableCBOM.hasDetectionWithNameAt( + "AES-GCM", + "src/test/testdata/go/gocrypto/GoCryptoAESTestFile.go", + 18)) + .isTrue(); + + assertThat( + assertableCBOM.hasDetectionWithNameAt( + "RSA-2048", + "src/test/testdata/go/gocrypto/GoCryptoRSATestFile.go", + 10)) + .isTrue(); + + assertThat( + assertableCBOM.hasDetectionWithNameAt( + "HMAC-SHA256", + "src/test/testdata/go/gocrypto/GoCryptoHMACTestFile.go", + 11)) + .isTrue(); + + assertThat( + assertableCBOM.hasDetectionWithNameAt( + "PBKDF2", + "src/test/testdata/go/gocrypto/GoCryptoPBKDF2TestFile.go", + 15)) + .isTrue(); + } +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoAESGCMEncryptTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoAESGCMEncryptTestFile.go new file mode 100644 index 0000000..34b8569 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoAESGCMEncryptTestFile.go @@ -0,0 +1,37 @@ +package main + +import ( + "crypto/aes" + "crypto/cipher" + crand "crypto/rand" + "encoding/base64" + "io" +) + +// Encrypt encrypts "data" with the specified "key" (must be valid 32 char AES key). +// +// This method uses AES-256-GCM block cypher mode. +func Encrypt(data []byte, key string) (string, error) { + block, err := aes.NewCipher([]byte(key)) // Noncompliant {{(AuthenticatedEncryption) AES-GCM}} + if err != nil { + return "", err + } + + gcm, err := cipher.NewGCM(block) + if err != nil { + return "", err + } + + nonce := make([]byte, gcm.NonceSize()) + + // populates the nonce with a cryptographically secure random sequence + if _, err := io.ReadFull(crand.Reader, nonce); err != nil { + return "", err + } + + cipherByte := gcm.Seal(nonce, nonce, data, nil) + + result := base64.StdEncoding.EncodeToString(cipherByte) + + return result, nil +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoAESGCMWithNonceSizeTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoAESGCMWithNonceSizeTestFile.go new file mode 100644 index 0000000..02ede48 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoAESGCMWithNonceSizeTestFile.go @@ -0,0 +1,42 @@ +package main + +import ( + "crypto/aes" + "crypto/cipher" +) + +// AES-GCM Decryption with custom nonce size +func AesGcmDecrypt(cipherText, cek, nonce, authTag, aad []byte) ([]byte, error) { + cipherTextWithAuthTag := append(cipherText, authTag...) + + block, err := aes.NewCipher(cek) // Noncompliant {{(AuthenticatedEncryption) AES-GCM}} + if err != nil { + return nil, err + } + aesgcm, err := cipher.NewGCMWithNonceSize(block, len(nonce)) + if err != nil { + return nil, err + } + plainText, err := aesgcm.Open(nil, nonce, cipherTextWithAuthTag, aad) + if err != nil { + return nil, err + } + return plainText, nil +} + +// AES-GCM Encryption with custom nonce size +func AesGcmEncrypt(plainText, cek, nonce, aad []byte) ([]byte, []byte, error) { + _len := len(plainText) + block, err := aes.NewCipher(cek) // Noncompliant {{(AuthenticatedEncryption) AES-GCM}} + if err != nil { + return nil, nil, err + } + + aesGcm, err := cipher.NewGCMWithNonceSize(block, len(nonce)) + if err != nil { + return nil, nil, err + } + + cipherText := aesGcm.Seal(nil, nonce, plainText, aad) + return cipherText[:_len], cipherText[_len:], nil +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoAESTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoAESTestFile.go new file mode 100644 index 0000000..582ec2d --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoAESTestFile.go @@ -0,0 +1,41 @@ +package main + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "io" +) + +func main() { + // Generate a random 32-byte key (AES-256) + key := make([]byte, 32) + if _, err := io.ReadFull(rand.Reader, key); err != nil { + panic(err) + } + + // Create a new AES cipher block - this should be detected + block, err := aes.NewCipher(key) // Noncompliant {{(AuthenticatedEncryption) AES256-GCM}} + if err != nil { + panic(err) + } + + // Create a GCM mode cipher + gcm, err := cipher.NewGCM(block) + if err != nil { + panic(err) + } + + // Example plaintext + plaintext := []byte("Hello, World!") + + // Generate a random nonce + nonce := make([]byte, gcm.NonceSize()) + if _, err := io.ReadFull(rand.Reader, nonce); err != nil { + panic(err) + } + + // Encrypt + ciphertext := gcm.Seal(nonce, nonce, plaintext, nil) + _ = ciphertext +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoDESTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoDESTestFile.go new file mode 100644 index 0000000..bca1166 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoDESTestFile.go @@ -0,0 +1,14 @@ +package main + +import ( + "crypto/des" +) + +func main() { + key := make([]byte, 8) + block, err := des.NewCipher(key) // Noncompliant {{(BlockCipher) DES64}} + if err != nil { + panic(err) + } + _ = block +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoDSATestFile.go b/src/test/testdata/go/gocrypto/GoCryptoDSATestFile.go new file mode 100644 index 0000000..ad5a442 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoDSATestFile.go @@ -0,0 +1,34 @@ +package main + +import ( + "crypto/dsa" + "crypto/rand" +) + +func main() { + // Generate DSA parameters with L2048N256 size + params := new(dsa.Parameters) + err := dsa.GenerateParameters(params, rand.Reader, dsa.L2048N256) + if err != nil { + panic(err) + } + + // Generate a DSA key pair + privateKey := new(dsa.PrivateKey) + privateKey.Parameters = *params + err = dsa.GenerateKey(privateKey, rand.Reader) // Noncompliant {{(Signature) DSA}} + if err != nil { + panic(err) + } + + // Sign a hash + hash := []byte("test message hash") + r, s, err := dsa.Sign(rand.Reader, privateKey, hash) // Noncompliant {{(Signature) DSA}} + if err != nil { + panic(err) + } + + // Verify the signature + valid := dsa.Verify(&privateKey.PublicKey, hash, r, s) // Noncompliant {{(Signature) DSA}} + _ = valid +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoECDHNewPrivateKeyTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoECDHNewPrivateKeyTestFile.go new file mode 100644 index 0000000..8f34493 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoECDHNewPrivateKeyTestFile.go @@ -0,0 +1,19 @@ +package main + +import ( + "crypto/ecdh" +) + +func main() { + // Test NewPrivateKey with P256 curve + curve := ecdh.P256() // Noncompliant {{(KeyAgreement) ECDH}} + + // Create a private key from raw bytes (32 bytes for P256) + privateKeyBytes := make([]byte, 32) + privateKey, err := curve.NewPrivateKey(privateKeyBytes) + if err != nil { + panic(err) + } + + _ = privateKey +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoECDHNewPublicKeyTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoECDHNewPublicKeyTestFile.go new file mode 100644 index 0000000..7c8e812 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoECDHNewPublicKeyTestFile.go @@ -0,0 +1,19 @@ +package main + +import ( + "crypto/ecdh" +) + +func main() { + // Test NewPublicKey with X25519 curve + curve := ecdh.X25519() // Noncompliant {{(KeyAgreement) ECDH}} + + // Create a public key from raw bytes (32 bytes for X25519) + publicKeyBytes := make([]byte, 32) + publicKey, err := curve.NewPublicKey(publicKeyBytes) + if err != nil { + panic(err) + } + + _ = publicKey +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoECDHTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoECDHTestFile.go new file mode 100644 index 0000000..1bbd475 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoECDHTestFile.go @@ -0,0 +1,19 @@ +package main + +import ( + "crypto/ecdh" + "crypto/rand" +) + +func main() { + // Get the P256 curve + curve := ecdh.P256() // Noncompliant {{(KeyAgreement) ECDH}} + + // Generate a key pair + privateKey, err := curve.GenerateKey(rand.Reader) + if err != nil { + panic(err) + } + + _ = privateKey +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoECDSASignASN1TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoECDSASignASN1TestFile.go new file mode 100644 index 0000000..c44e6f6 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoECDSASignASN1TestFile.go @@ -0,0 +1,19 @@ +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" +) + +func main() { + // Sign the hash using SignASN1 + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // Noncompliant {{(Signature) ECDSA}} + + var hash []byte + sig, err := ecdsa.SignASN1(rand.Reader, privateKey, hash) // Noncompliant {{(Signature) ECDSA}} + if err != nil { + panic(err) + } + _ = sig +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoECDSATestFile.go b/src/test/testdata/go/gocrypto/GoCryptoECDSATestFile.go new file mode 100644 index 0000000..003dfa1 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoECDSATestFile.go @@ -0,0 +1,16 @@ +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" +) + +func main() { + // Generate an ECDSA key pair using P-256 curve + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // Noncompliant {{(Signature) ECDSA}} + if err != nil { + panic(err) + } + _ = privateKey +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoECDSAVerifyASN1TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoECDSAVerifyASN1TestFile.go new file mode 100644 index 0000000..583d7b2 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoECDSAVerifyASN1TestFile.go @@ -0,0 +1,22 @@ +package main + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/rand" +) + +func main() { + // Verify the signature using VerifyASN1 + privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) // Noncompliant {{(Signature) ECDSA}} + if err != nil { + panic(err) + } + + var publicKey = &privateKey.PublicKey + + var hash []byte + var sig []byte + valid := ecdsa.VerifyASN1(publicKey, hash, sig) // Noncompliant {{(Signature) ECDSA}} + _ = valid +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoEd25519SignTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoEd25519SignTestFile.go new file mode 100644 index 0000000..6d54234 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoEd25519SignTestFile.go @@ -0,0 +1,19 @@ +package main + +import ( + "crypto/ed25519" + "crypto/rand" +) + +func main() { + // Generate an Ed25519 key pair + _, priv, err := ed25519.GenerateKey(rand.Reader) // Noncompliant {{(Signature) Ed25519}} + if err != nil { + panic(err) + } + + // Sign a message + message := []byte("test message") + sig := ed25519.Sign(priv, message) // Noncompliant {{(Signature) Ed25519}} + _ = sig +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoEd25519TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoEd25519TestFile.go new file mode 100644 index 0000000..9a76caa --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoEd25519TestFile.go @@ -0,0 +1,18 @@ +package main + +import ( + "crypto/ed25519" + "crypto/rand" +) + +func main() { + // GenerateKey - generates a public/private key pair + _, _, err := ed25519.GenerateKey(rand.Reader) // Noncompliant {{(Signature) Ed25519}} + if err != nil { + panic(err) + } + + // NewKeyFromSeed - creates a private key from seed + seed := make([]byte, ed25519.SeedSize) + _ = ed25519.NewKeyFromSeed(seed) // Noncompliant {{(Signature) Ed25519}} +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoEd25519VerifyTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoEd25519VerifyTestFile.go new file mode 100644 index 0000000..f7e554f --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoEd25519VerifyTestFile.go @@ -0,0 +1,20 @@ +package main + +import ( + "crypto/ed25519" + "crypto/rand" +) + +func main() { + // Generate an Ed25519 key pair + pub, _, err := ed25519.GenerateKey(rand.Reader) // Noncompliant {{(Signature) Ed25519}} + if err != nil { + panic(err) + } + + // Verify a signature + var message []byte + var sig []byte + valid := ed25519.Verify(pub, message, sig) // Noncompliant {{(Signature) Ed25519}} + _ = valid +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoEllipticTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoEllipticTestFile.go new file mode 100644 index 0000000..72177be --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoEllipticTestFile.go @@ -0,0 +1,24 @@ +package main + +import ( + "crypto/elliptic" + "fmt" +) + +func main() { + // Test P-224 curve + p224 := elliptic.P224() + fmt.Println("P-224:", p224.Params().Name) + + // Test P-256 curve + p256 := elliptic.P256() + fmt.Println("P-256:", p256.Params().Name) + + // Test P-384 curve + p384 := elliptic.P384() + fmt.Println("P-384:", p384.Params().Name) + + // Test P-521 curve + p521 := elliptic.P521() + fmt.Println("P-521:", p521.Params().Name) +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoHKDFExpandTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoHKDFExpandTestFile.go new file mode 100644 index 0000000..83c0710 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoHKDFExpandTestFile.go @@ -0,0 +1,19 @@ +package main + +import ( + "crypto/sha256" + "golang.org/x/crypto/hkdf" +) + +func main() { + secret := []byte("secret") + salt := []byte("salt") + info := []byte("info") + + // HKDF Extract step + prk := hkdf.Extract(sha256.New, secret, salt) + + // HKDF Expand step + reader := hkdf.Expand(sha256.New, prk, info, 32) // Noncompliant {{(KeyDerivationFunction) HKDF-SHA256}} + _ = reader +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoHKDFTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoHKDFTestFile.go new file mode 100644 index 0000000..019751d --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoHKDFTestFile.go @@ -0,0 +1,16 @@ +package main + +import ( + "crypto/sha256" + "golang.org/x/crypto/hkdf" +) + +func main() { + secret := []byte("secret") + salt := []byte("salt") + info := []byte("info") + + // HKDF Key derivation + reader := hkdf.New(sha256.New, secret, salt, info) // Noncompliant {{(KeyDerivationFunction) HKDF-SHA256}} + _ = reader +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoHMACTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoHMACTestFile.go new file mode 100644 index 0000000..3f8d4a8 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoHMACTestFile.go @@ -0,0 +1,14 @@ +package main + +import ( + "crypto/hmac" + "crypto/sha256" + "fmt" +) + +func main() { + key := []byte("secret-key") + h := hmac.New(sha256.New, key) // Noncompliant {{(Mac) HMAC-SHA256}} + h.Write([]byte("hello")) + fmt.Printf("%x\n", h.Sum(nil)) +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoMD5TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoMD5TestFile.go new file mode 100644 index 0000000..56b8b13 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoMD5TestFile.go @@ -0,0 +1,17 @@ +package main + +import ( + "crypto/md5" + "fmt" +) + +func main() { + h := md5.New() // Noncompliant {{(MessageDigest) MD5}} + h.Write([]byte("hello")) + sum := h.Sum(nil) + fmt.Printf("%x\n", sum) + + // Also test md5.Sum directly + checksum := md5.Sum([]byte("data")) // Noncompliant {{(MessageDigest) MD5}} + fmt.Printf("%x\n", checksum) +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoMLKEM1024TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoMLKEM1024TestFile.go new file mode 100644 index 0000000..38b4031 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoMLKEM1024TestFile.go @@ -0,0 +1,15 @@ +package main + +import ( + "crypto/mlkem" +) + +func main() { + // Generate an ML-KEM-1024 decapsulation key + dk, err := mlkem.GenerateKey1024() // Noncompliant {{(KeyEncapsulationMechanism) ML-KEM-1024}} + if err != nil { + panic(err) + } + + _ = dk +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoMLKEMNewDecapsulationKeyTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoMLKEMNewDecapsulationKeyTestFile.go new file mode 100644 index 0000000..2b2f972 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoMLKEMNewDecapsulationKeyTestFile.go @@ -0,0 +1,16 @@ +package main + +import ( + "crypto/mlkem" +) + +func main() { + // Create an ML-KEM-768 decapsulation key from a seed (SeedSize = 64) + seed := make([]byte, 64) + dk, err := mlkem.NewDecapsulationKey768(seed) // Noncompliant {{(KeyEncapsulationMechanism) ML-KEM-768}} + if err != nil { + panic(err) + } + + _ = dk +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoMLKEMTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoMLKEMTestFile.go new file mode 100644 index 0000000..ea84cfe --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoMLKEMTestFile.go @@ -0,0 +1,15 @@ +package main + +import ( + "crypto/mlkem" +) + +func main() { + // Generate an ML-KEM-768 decapsulation key + dk, err := mlkem.GenerateKey768() // Noncompliant {{(KeyEncapsulationMechanism) ML-KEM-768}} + if err != nil { + panic(err) + } + + _ = dk +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoPBKDF2StdlibTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoPBKDF2StdlibTestFile.go new file mode 100644 index 0000000..9d63628 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoPBKDF2StdlibTestFile.go @@ -0,0 +1,18 @@ +package main + +import ( + "crypto/pbkdf2" + "crypto/sha256" +) + +func main() { + salt := make([]byte, 16) + + // PBKDF2 Key derivation using stdlib API (Go 1.24+) + key, err := pbkdf2.Key(sha256.New, "password", salt, 600000, 32) // Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF2-SHA256}} + if err != nil { + panic(err) + } + + _ = key +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoPBKDF2TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoPBKDF2TestFile.go new file mode 100644 index 0000000..bfc157a --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoPBKDF2TestFile.go @@ -0,0 +1,17 @@ +package main + +import ( + "crypto/sha256" + "golang.org/x/crypto/pbkdf2" +) + +func main() { + password := []byte("password") + salt := []byte("salt") + iterations := 10000 + keyLen := 32 + + // PBKDF2 Key derivation + key := pbkdf2.Key(password, salt, iterations, keyLen, sha256.New) // Noncompliant {{(PasswordBasedKeyDerivationFunction) PBKDF2-SHA256}} + _ = key +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoRC4TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoRC4TestFile.go new file mode 100644 index 0000000..a495512 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoRC4TestFile.go @@ -0,0 +1,20 @@ +package main + +import ( + "crypto/rc4" +) + +func main() { + key := make([]byte, 16) + + // Create a new RC4 cipher with a 128-bit key + cipher, err := rc4.NewCipher(key) // Noncompliant {{(StreamCipher) RC4}} + if err != nil { + panic(err) + } + + // Encrypt data using XOR key stream + src := []byte("plaintext") + dst := make([]byte, len(src)) + cipher.XORKeyStream(dst, src) +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoRSAEncryptOAEPTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoRSAEncryptOAEPTestFile.go new file mode 100644 index 0000000..94b29d9 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoRSAEncryptOAEPTestFile.go @@ -0,0 +1,24 @@ +package main + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/sha256" +) + +func main() { + // Generate a 2048-bit RSA key + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // Noncompliant {{(PublicKeyEncryption) RSA-2048}} + if err != nil { + panic(err) + } + + var pub = &privateKey.PublicKey + + // Encrypt with RSA-OAEP using SHA-256 + ciphertext, err2 := rsa.EncryptOAEP(sha256.New(), rand.Reader, pub, []byte("hello"), nil) // Noncompliant {{(PublicKeyEncryption) RSA-OAEP}} + if err2 != nil { + panic(err2) + } + _ = ciphertext +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoRSAEncryptPKCS1v15TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoRSAEncryptPKCS1v15TestFile.go new file mode 100644 index 0000000..14e059b --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoRSAEncryptPKCS1v15TestFile.go @@ -0,0 +1,23 @@ +package main + +import ( + "crypto/rand" + "crypto/rsa" +) + +func main() { + // Generate a 2048-bit RSA key + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // Noncompliant {{(PublicKeyEncryption) RSA-2048}} + if err != nil { + panic(err) + } + + var pub = &privateKey.PublicKey + + // Encrypt with RSA PKCS#1 v1.5 + ciphertext, err2 := rsa.EncryptPKCS1v15(rand.Reader, pub, []byte("hello")) // Noncompliant {{(PublicKeyEncryption) RSA-2048}} + if err2 != nil { + panic(err2) + } + _ = ciphertext +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoRSASignPKCS1v15TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoRSASignPKCS1v15TestFile.go new file mode 100644 index 0000000..6ec1189 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoRSASignPKCS1v15TestFile.go @@ -0,0 +1,26 @@ +package main + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" +) + +func main() { + // Generate a 2048-bit RSA key + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // Noncompliant {{(PublicKeyEncryption) RSA-2048}} + if err != nil { + panic(err) + } + + var priv = privateKey + + hashed := []byte("hash of message that is 32 bytes") + + // Sign with RSA PKCS#1 v1.5 using SHA-256 + sig, err2 := rsa.SignPKCS1v15(rand.Reader, priv, crypto.SHA256, hashed) // Noncompliant {{(Signature) RSA}} + if err2 != nil { + panic(err2) + } + _ = sig +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoRSASignPSSTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoRSASignPSSTestFile.go new file mode 100644 index 0000000..8c97fa9 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoRSASignPSSTestFile.go @@ -0,0 +1,26 @@ +package main + +import ( + "crypto" + "crypto/rand" + "crypto/rsa" +) + +func main() { + // Generate a 2048-bit RSA key + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // Noncompliant {{(PublicKeyEncryption) RSA-2048}} + if err != nil { + panic(err) + } + + var priv = privateKey + + hashed := []byte("hash of message that is 32 bytes") + + // Sign with RSA-PSS using SHA-256 + sig, err2 := rsa.SignPSS(rand.Reader, priv, crypto.SHA256, hashed, nil) // Noncompliant {{(Signature) RSA}} + if err2 != nil { + panic(err2) + } + _ = sig +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoRSATestFile.go b/src/test/testdata/go/gocrypto/GoCryptoRSATestFile.go new file mode 100644 index 0000000..15c1d63 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoRSATestFile.go @@ -0,0 +1,15 @@ +package main + +import ( + "crypto/rand" + "crypto/rsa" +) + +func main() { + // Generate a 2048-bit RSA key + privateKey, err := rsa.GenerateKey(rand.Reader, 2048) // Noncompliant {{(PublicKeyEncryption) RSA-2048}} + if err != nil { + panic(err) + } + _ = privateKey +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoRandTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoRandTestFile.go new file mode 100644 index 0000000..0556bd7 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoRandTestFile.go @@ -0,0 +1,15 @@ +package main + +import ( + "crypto/rand" + "fmt" +) + +func main() { + key := make([]byte, 32) + _, err := rand.Read(key) // Noncompliant {{(PseudorandomNumberGenerator) NATIVEPRNG}} + if err != nil { + panic(err) + } + fmt.Printf("%x\n", key) +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoSHA1TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoSHA1TestFile.go new file mode 100644 index 0000000..39a3bc8 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoSHA1TestFile.go @@ -0,0 +1,17 @@ +package main + +import ( + "crypto/sha1" + "fmt" +) + +func main() { + h := sha1.New() // Noncompliant {{(MessageDigest) SHA1}} + h.Write([]byte("hello")) + sum := h.Sum(nil) + fmt.Printf("%x\n", sum) + + // Also test sha1.Sum directly + checksum := sha1.Sum([]byte("data")) // Noncompliant {{(MessageDigest) SHA1}} + fmt.Printf("%x\n", checksum) +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoSHA256TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoSHA256TestFile.go new file mode 100644 index 0000000..1a4afa3 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoSHA256TestFile.go @@ -0,0 +1,28 @@ +package main + +import ( + "crypto/sha256" + "fmt" +) + +func main() { + // Test sha256.New() - SHA-256 + h := sha256.New() // Noncompliant {{(MessageDigest) SHA256}} + h.Write([]byte("hello")) + sum := h.Sum(nil) + fmt.Printf("%x\n", sum) + + // Test sha256.New224() - SHA-224 + h224 := sha256.New224() // Noncompliant {{(MessageDigest) SHA224}} + h224.Write([]byte("hello")) + sum224 := h224.Sum(nil) + fmt.Printf("%x\n", sum224) + + // Test sha256.Sum256() - SHA-256 + sum256 := sha256.Sum256([]byte("data")) // Noncompliant {{(MessageDigest) SHA256}} + _ = sum256 + + // Test sha256.Sum224() - SHA-224 + sum224Direct := sha256.Sum224([]byte("data")) // Noncompliant {{(MessageDigest) SHA224}} + _ = sum224Direct +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoSHA3TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoSHA3TestFile.go new file mode 100644 index 0000000..c564de6 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoSHA3TestFile.go @@ -0,0 +1,20 @@ +package main + +import ( + "golang.org/x/crypto/sha3" +) + +func main() { + // SHA3-256 hash + h256 := sha3.New256() // Noncompliant {{(MessageDigest) SHA3-256}} + h256.Write([]byte("test")) + _ = h256.Sum(nil) + + // SHA3-512 hash + h512 := sha3.New512() // Noncompliant {{(MessageDigest) SHA3-512}} + _ = h512 + + // Sum256 - direct hash computation + hash := sha3.Sum256([]byte("test")) // Noncompliant {{(MessageDigest) SHA3-256}} + _ = hash +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoSHA512TestFile.go b/src/test/testdata/go/gocrypto/GoCryptoSHA512TestFile.go new file mode 100644 index 0000000..9382ed8 --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoSHA512TestFile.go @@ -0,0 +1,28 @@ +package main + +import ( + "crypto/sha512" + "fmt" +) + +func main() { + // Test sha512.New() - SHA-512 + h := sha512.New() // Noncompliant {{(MessageDigest) SHA512}} + h.Write([]byte("hello")) + sum := h.Sum(nil) + fmt.Printf("%x\n", sum) + + // Test sha512.New384() - SHA-384 + h384 := sha512.New384() // Noncompliant {{(MessageDigest) SHA384}} + h384.Write([]byte("hello")) + sum384 := h384.Sum(nil) + fmt.Printf("%x\n", sum384) + + // Test sha512.Sum512() - SHA-512 + sum512 := sha512.Sum512([]byte("data")) // Noncompliant {{(MessageDigest) SHA512}} + _ = sum512 + + // Test sha512.Sum384() - SHA-384 + sum384Direct := sha512.Sum384([]byte("data")) // Noncompliant {{(MessageDigest) SHA384}} + _ = sum384Direct +} diff --git a/src/test/testdata/go/gocrypto/GoCryptoTLSTestFile.go b/src/test/testdata/go/gocrypto/GoCryptoTLSTestFile.go new file mode 100644 index 0000000..2e3f5da --- /dev/null +++ b/src/test/testdata/go/gocrypto/GoCryptoTLSTestFile.go @@ -0,0 +1,22 @@ +package main + +import ( + "crypto/tls" +) + +func main() { + // Dial a TLS connection + conf := tls.Config{ // Noncompliant {{(TLS) TLSv1.2}} + MinVersion: tls.VersionTLS12, + CipherSuites: []uint16{ + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + }, + } + + conn, err := tls.Dial("tcp", "example.com:443", &conf) + if err != nil { + panic(err) + } + defer conn.Close() +}