diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 01b610238..b2ab6fb6c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,7 @@ env: LC_ALL: C.UTF-8 GRADLE_CACHE_USERNAME: ${{ secrets.GRADLE_CACHE_USERNAME }} GRADLE_CACHE_PASSWORD: ${{ secrets.GRADLE_CACHE_PASSWORD }} + CG_EXEC: ionice -c 2 -n 2 nice -n 19 jobs: build: @@ -38,6 +39,13 @@ jobs: - name: Checkout Code uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: "0" + + - name: Setup NodeJS + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + with: + node-version: 18 - name: Setup Java uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 @@ -51,8 +59,91 @@ jobs: cache-read-only: false - name: Build SDK & Javadoc + id: gradle-build run: ./gradlew assemble + - name: Setup Snyk + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + if: >- + ${{ + steps.gradle-build.conclusion == 'success' && + ( + github.event.pull_request.head.repo.full_name == github.repository || + github.event_name == 'push' + ) && + !cancelled() + }} + run: ${CG_EXEC} npm install -g snyk snyk-to-html @wcj/html-to-markdown-cli + + - name: Snyk Scan + id: snyk + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + if: >- + ${{ + steps.gradle-build.conclusion == 'success' && + ( + github.event.pull_request.head.repo.full_name == github.repository || + github.event_name == 'push' + ) && + !cancelled() + }} + run: ${CG_EXEC} snyk test --all-projects --severity-threshold=high --policy-path=.snyk --json-file-output=snyk-test.json --org=hiero-client-sdks + + - name: Snyk Code + id: snyk-code + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + if: >- + ${{ + steps.gradle-build.conclusion == 'success' && + ( + github.event.pull_request.head.repo.full_name == github.repository || + github.event_name == 'push' + ) && + !cancelled() + }} + run: ${CG_EXEC} snyk code test --severity-threshold=high --json-file-output=snyk-code.json --org=hiero-client-sdks --policy-path=.snyk + + - name: Publish Snyk Results + if: >- + ${{ + steps.gradle-build.conclusion == 'success' && + ( + github.event.pull_request.head.repo.full_name == github.repository || + github.event_name == 'push' + ) && + !cancelled() + }} + run: | + if [[ -f "snyk-test.json" && -n "$(cat snyk-test.json | tr -d '[:space:]')" ]]; then + snyk-to-html -i snyk-test.json -o snyk-test.html --summary + html-to-markdown snyk-test.html -o snyk + cat snyk/snyk-test.html.md >> $GITHUB_STEP_SUMMARY + fi + + if [[ -f "snyk-code.json" && -n "$(cat snyk-code.json | tr -d '[:space:]')" ]]; then + snyk-to-html -i snyk-code.json -o snyk-code.html --summary + html-to-markdown snyk-code.html -o snyk + cat snyk/snyk-code.html.md >> $GITHUB_STEP_SUMMARY + fi + + - name: Check Snyk Files + if: ${{ always() }} + run: | + echo "::group::Snyk File List" + ls -lah snyk* || true + echo "::endgroup::" + + echo "::group::Snyk Test Contents" + cat snyk-test.json || true + echo "::endgroup::" + + echo "::group::Snyk Code Contents" + cat snyk-code.json || true + echo "::endgroup::" + test: name: Unit and Integration Tests runs-on: hiero-client-sdk-linux-medium diff --git a/.github/workflows/snyk-monitor.yml b/.github/workflows/snyk-monitor.yml new file mode 100644 index 000000000..7a2f41ff6 --- /dev/null +++ b/.github/workflows/snyk-monitor.yml @@ -0,0 +1,58 @@ +# SPDX-License-Identifier: Apache-2.0 +name: "Snyk Monitor" + +on: + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + security-events: write + +jobs: + snyk: + name: Snyk Monitor + runs-on: hiero-client-sdk-linux-medium + steps: + - name: Harden Runner + uses: step-security/harden-runner@cb605e52c26070c328afc4562f0b4ada7618a84e # v2.10.4 + with: + egress-policy: audit + + - name: Checkout + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Setup Java + uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 + with: + distribution: temurin + java-version: "17.0.13" + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@94baf225fe0a508e581a564467443d0e2379123b # v4.3.0 + with: + gradle-version: wrapper + + - name: Disable Gradle Configuration Cache + run: sed -i 's/^org.gradle.configuration-cache=.*$/org.gradle.configuration-cache=false/' gradle.properties + + - name: Compile + run: ./gradlew assemble + + - name: Setup NodeJS + uses: actions/setup-node@1d0ff469b7ec7b3cb9d8673fde0c81c44821de2a # v4.2.0 + with: + node-version: 18 + + - name: Setup Snyk + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + run: npm install -g snyk + + - name: Run Snyk Monitor + continue-on-error: true + env: + SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} + run: snyk monitor --all-projects --policy-path=.snyk --trust-policies diff --git a/.gitignore b/.gitignore index 22fa8f6f0..b292fe90f 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ gradle.properties .DS_Store /examples/address-book.proto.bin local.properties + +.dccache +snyk-test.json \ No newline at end of file diff --git a/.snyk b/.snyk new file mode 100644 index 000000000..afed15d29 --- /dev/null +++ b/.snyk @@ -0,0 +1,16 @@ +# Snyk (https://snyk.io) policy file, patches or ignores known vulnerabilities. +version: v1.25.0 +# ignores vulnerabilities until expiry date; change duration by modifying expiry date +ignore: + SNYK-JAVA-NETMINIDEV-8689573: + - '*': + reason: No net-minidev version with a fix is available + expires: 2025-06-30T00:00:00.000Z + created: 2025-02-12T14:49:55Z +patch: {} +exclude: + global: + - >- + sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java + - >- + sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java \ No newline at end of file diff --git a/examples/settings.gradle.kts b/examples/settings.gradle.kts index 0780aa45e..cfe4004c2 100644 --- a/examples/settings.gradle.kts +++ b/examples/settings.gradle.kts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -plugins { id("org.hiero.gradle.build") version "0.3.0" } +plugins { id("org.hiero.gradle.build") version "0.3.4" } @Suppress("UnstableApiUsage") dependencyResolutionManagement { repositories.mavenCentral() } diff --git a/hiero-dependency-versions/build.gradle.kts b/hiero-dependency-versions/build.gradle.kts index 2bba192c7..53769e72d 100644 --- a/hiero-dependency-versions/build.gradle.kts +++ b/hiero-dependency-versions/build.gradle.kts @@ -9,11 +9,14 @@ plugins { group = "org.hiero" val bouncycastle = "1.80" -val grpc = "1.69.1" +val grpc = "1.70.0" val protobuf = "4.29.3" val slf4j = "2.0.16" -dependencies { api(platform("org.springframework.boot:spring-boot-dependencies:3.4.2")) } +dependencies { + api(platform("org.springframework.boot:spring-boot-dependencies:3.4.2")) + api(platform("io.netty:netty-bom:4.1.118.Final")) +} dependencies.constraints { api("com.esaulpaugh:headlong:12.3.3") { because("com.esaulpaugh.headlong") } diff --git a/sdk/build.gradle.kts b/sdk/build.gradle.kts index ced6ffc1c..bd93e342b 100644 --- a/sdk/build.gradle.kts +++ b/sdk/build.gradle.kts @@ -31,8 +31,6 @@ testModuleInfo { requires("org.junit.jupiter.params") requires("org.mockito") - requiresStatic("java.annotation") - runtimeOnly("io.grpc.netty.shaded") runtimeOnly("org.slf4j.simple") } diff --git a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java index 383386475..477e2fa41 100644 --- a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java +++ b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyECDSA.java @@ -163,6 +163,16 @@ public PrivateKey derive(int index) { /** * Create an ECDSA key from seed. + * Implement the published algorithm as defined in BIP32 in order to derive the primary account key from the + * original (and never stored) master key. + * The original master key, which is a secure key generated according to the BIP39 specification, is input to this + * operation, and provides the base cryptographic seed material required to ensure the output is sufficiently random + * to maintain strong cryptographic assurances. + * The fromSeed() method must be provided with cryptographically secure material; otherwise, it will produce + * insecure output. + * + * @see BIP-32 Definition + * @see BIP-39 Definition * * @param seed the seed bytes * @return the new key @@ -180,6 +190,19 @@ public static PrivateKey fromSeed(byte[] seed) { /** * Create a derived key. + * The industry standard protocol for deriving an active ECDSA keypair from a BIP39 master key is described in + * BIP32. By using this deterministic mechanism to derive cryptographically secure keypairs from a single original + * secret, the user maintains secure access to their wallet, even if they lose access to a particular system or + * wallet local data store. + * The active keypair can always be re-derived from the original master key. + * The use of the fixed "key" values in this code is defined by this deterministic protocol, and this data is mixed, + * in a deterministic but cryptographically secure manner, with the original master key and/or other derived keys + * "higher" in the tree to produce a cryptographically secure derived key. + * This "Key Derivation Function" makes use of secure hash algorithm and a secure hash based message authentication + * code to produce an initialization vector, and then produces the actual key from a portion of that vector. + * + * @see BIP-32 Definition + * @see BIP-39 Definition * * @param deriveData data to derive the key * @return the new key diff --git a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java index 7a5544818..30c490a8a 100644 --- a/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java +++ b/sdk/src/main/java/com/hedera/hashgraph/sdk/PrivateKeyED25519.java @@ -69,12 +69,23 @@ static PrivateKeyED25519 fromPrivateKeyInfoInternal(PrivateKeyInfo privateKeyInf /** * Create an ED25519 key from seed. + * Implement the published algorithm as defined in BIP32 in order to derive the primary account key from the + * original (and never stored) master key. + * The original master key, which is a secure key generated according to the BIP39 specification, is input to this + * operation, and provides the base cryptographic seed material required to ensure the output is sufficiently random + * to maintain strong cryptographic assurances. + * The fromSeed() method must be provided with cryptographically secure material; otherwise, it will produce + * insecure output. + * + * @see BIP-32 Definition + * @see BIP-39 Definition * * @param seed the seed bytes * @return the new key */ public static PrivateKey fromSeed(byte[] seed) { var hmacSha512 = new HMac(new SHA512Digest()); + hmacSha512.init(new KeyParameter("ed25519 seed".getBytes(StandardCharsets.UTF_8))); hmacSha512.update(seed, 0, seed.length); @@ -86,6 +97,20 @@ public static PrivateKey fromSeed(byte[] seed) { /** * Create a derived key. + * The industry standard protocol for deriving an active ed25519 keypair from a BIP39 master key is described in + * BIP32. By using this deterministic mechanism to derive cryptographically secure keypairs from a single original + * secret, the user maintains secure access to their wallet, even if they lose access to a particular system or + * wallet local data store. + * The active keypair can always be re-derived from the original master key. + * The use of the fixed "key" values in this code is defined by this deterministic protocol, and this data is mixed, + * in a deterministic but cryptographically secure manner, with the original master key and/or other derived keys + * "higher" in the tree to produce a cryptographically secure derived key. + * This "Key Derivation Function" makes use of secure hash algorithm and a secure hash + * based message authentication code to produce an initialization vector, and then + * produces the actual key from a portion of that vector. + * + * @see BIP-32 Definition + * @see BIP-39 Definition * * @param deriveData data to derive the key * @return the new key diff --git a/settings.gradle.kts b/settings.gradle.kts index 6cbbcdcb3..0523c1d0f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: Apache-2.0 -plugins { id("org.hiero.gradle.build") version "0.3.1" } +plugins { id("org.hiero.gradle.build") version "0.3.4" } rootProject.name = "hedera-sdk-java"