Sunday, October 25, 2026

updatejdk 2.0.0: Keep Your JDKs Up to Date – Without a Package Manager

I have just released updatejdk.sh 2.0.0, a single Bash script that lists, installs, updates and downloads JDKs and JREs on macOS and Linux. It installs Eclipse Temurin by default, and other distributions like Zulu, Corretto or Liberica if you ask for them. It verifies every download by its checksum, and one command brings everything you have installed up to date.

Why another JDK tool?

I like to keep several feature versions side by side, sometimes from different vendors, and I don't want a package manager or a runtime of its own just for that. The vendors publish plain tarballs, and their APIs say which release is the latest. A small script is enough to put the two together.

updatejdk.sh is a new development based on the ideas of update_jdk from my bashberries project. The last version of update_jdk was 1.20.0, so the version numbers continue at 2.0.0. Unlike its predecessor, it looks up the releases by the Adoptium API and the foojay Disco API rather than taking a URL. It also knows which version is installed, and it handles several distributions, architectures and operating systems.

Getting started

It is one file:

curl -fsSL -o updatejdk.sh https://bit.ly/updatejdk

chmod +x updatejdk.sh


You need bash, curl and tar. You also need jq, but if it is missing, as on macOS before Sequoia, the script downloads a verified copy for the run.

A quick tour

What is available, and what is installed?

$ ./updatejdk.sh -l 21

Asking https://api.adoptium.net/v3 for Temurin 21 releases for macOS aarch64 ...


  VERSION   TYPE  LATEST               FORMATS          INSTALLED

  --------- ----- -------------------- ---------------- ---------

* 21 LTS    jdk   jdk-21.0.13+9        tar.gz pkg       21.0.13+9-LTS (up to date) /Library/Java/JavaVirtualMachines/temurin-21.jdk

  21 LTS    jre   jdk-21.0.13+9        tar.gz pkg


Installed variants are marked with *. If you also have Zulu or Corretto installed, -l lists them as well, each in a table of its own.

Installing and updating:

updatejdk.sh -i lts           # the JDK of the most recent LTS release

updatejdk.sh -i 21:jre        # the JRE of Java 21

updatejdk.sh -i 21 -a zulu    # Azul Zulu 21 from the foojay Disco API

updatejdk.sh -u               # update everything, each from its own source

updatejdk.sh -u -n            # dry run: which updates are there?


A variant is <feature-version>[:jdk|:jre][:<architecture>], and lts and latest work as feature versions too. -l -a lists all distributions you can choose from.

Your own directory with -d/--dir

By default, installations go to /Library/Java/JavaVirtualMachines on macOS and /usr/lib/jvm on Linux. With -d, they go to a directory of your own, and no root privileges are needed. You can use it for a sandbox or a CI cache, but the use case I care most about is bundling runtimes with an application.

Say you build a macOS app on an Intel Mac and want to ship a universal DMG that runs on both Intel and Apple Silicon. You need a JRE for each architecture, and -d gets you both:

updatejdk.sh -d build/jre -i 21:jre:x64       # -> build/jre/temurin-21.jre

updatejdk.sh -d build/jre -i 21:jre:aarch64   # -> build/jre/temurin-21-aarch64.jre

updatejdk.sh -d build/jre -u                  # updates both later


A few details make this practical:

  • Only an installation for another architecture than the machine's has the architecture in its name, so the two don't collide.

  • After unpacking, the script checks that the archive really is for the requested architecture, according to the OS_ARCH of its release file.

  • Another architecture can only be installed with -d, so it never gets in the way of java_home or update-alternatives.

  • -l aarch64 shows what is available for Apple Silicon and marks what you have.

  • -t and -z need to run that java. On an Intel Mac, an aarch64 Java can't run, so the script skips both for it with a warning.

And if your build needs a stable path, -L maintains a relative symbolic link to the installed variant, e.g. build/jre/latest -> temurin-21.jre/Contents/Home.

Just the packages with -g/--get

Sometimes you don't want to install anything, just get the package, e.g. for a Windows installer:

updatejdk.sh -g 21:jre:x64 --os windows                # the zip

updatejdk.sh -g 21:jre:x64 --os windows --package msi  # the installer

updatejdk.sh -g 21:jre --package pkg                   # the macOS installer


The package is verified like an installation and saved together with a .sha256 file, so you can check it later by shasum -a 256 -c.

Trust, but verify

Nothing is installed without a checksum. The script takes the SHA-256 from the Adoptium API, from foojay, or from the checksum file next to the package. For Corretto, it uses Corretto's own latest_sha256 endpoint. Liberica only publishes a SHA-1, which is accepted with a note. The script also checks the size, and it refuses archives with absolute paths or `..`. A network error stops the script with its cause, rather than being taken for a missing release.

Linux notes

On Linux, the script supports glibc and musl (Alpine). Installations in /usr/lib/jvm are registered with update-alternatives, with the feature version as the priority, so your distribution's default stays selected. Directories that belong to a system package, like the Temurin RPM, are left to apt or dnf. The script uses sudo, or doas on systems that only have that. If a command like curl is missing, as on a fresh Ubuntu desktop, it tells you the command that installs it.

On both macOS and Linux, -z also updates the time zone data of your installations by Oracle's tzupdater.

Tested on

  • macOS on Apple Silicon, macOS 15 Sequoia (x64) and macOS 14 Sonoma (x64)

  • Ubuntu 26.04 LTS (x64) and Ubuntu 26.04.1 LTS (aarch64)

  • Rocky Linux and Alpine Linux (x64) with Temurin, during development

Get it

The source, the README with all the details, and the release notes are on GitHub: https://github.com/jonelo/updatejdk. Bug reports and wishes are welcome as issues there. updatejdk.sh is licensed under the Apache License 2.0.

updatejdk is an independent project. It is not affiliated with, endorsed or sponsored by Oracle, the Eclipse Foundation or any vendor of the distributions it installs. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates; Eclipse Temurin is a trademark of the Eclipse Foundation.


Saturday, October 17, 2026

Jacksum 4 is on the web!

I am pleased to announce that Jacksum 4 has been released! The current version is 4.0.2.

The step from 3.7 to 4 looks small, but it took three years, and it is bigger than the version number suggests. Jacksum 4 brings 97 new algorithms, new tools to judge the security of an algorithm, a much stricter verification mode, styles that match the native tools byte for byte, documentation in German, and a long list of fixes that make Jacksum more robust than ever. I call it the "trust, but verify" release ;-)

Here is an eagle view comparison chart with Jacksum 3.7.0:

Jacksum 3.7.0Jacksum 4.0.2
Algorithm support
Supported algorithms (including different lengths)489586
Default algorithmSHA3-256SHA3-256
Candidates from round 2 of the NIST SHA-3 competition 1noyes
Candidates from round 1 of the NIST SHA-3 competition 2noyes
Fugue 2.0, Romulus-H 3, belt-hash 4noyes
Verification
Strict check that also fails if files have been added or removednoyes
Ignoring stored hashes, file sizes, or timestamps during a checknoyes
Hash values compared case-insensitively by -c, -e, and -w 5noyes
Algorithm investigation (--info)
Security state "broken" incl. an explanationnoyes
Avalanche effectnoyes
Output and input
Output identical to md5, shasum, openssl dgst (3.x), and digest 6noyes
Style openssl111-dgst for the OpenSSL 1.1.1 namesnoyes
Hash data base (hdb) style, used by ClamAV's sigtoolnoyes
Styles full, without-hashes, without-sizes, without-timestamps, sizes-and-names, timestamps-and-namesnoyes
Timestamp formats in UTCnoyes
z-base-32 and BubbleBabble as input (-q, -k)noyes
Documentation
Help in German (-h de)noyes
Exact help search (--exact)noyes
Algorithm selection guide and use case cookbook (English and German)noyes
Library usage (API)
Query whether an algorithm is brokennoyes
Bundled Bouncy Castle relocated, no clash with your own Bouncy Castlenoyes
Requirements
Java required / recommended11+ / 17+21+ / 25+
LicenseGPLv3+GPLv3+

For the complete picture, including Jacksum 1.0.0 and 1.7.0 and a list of every supported algorithm, see the Feature Comparison Table in the wiki.

The highlights

97 new algorithms

Jacksum now supports 586 algorithms. With the candidates from rounds 1 and 2 of the NIST SHA-3 competition, Jacksum covers that competition much more completely. Fugue 2.0 is the tweak of Fugue that IBM published after the competition had ended. Romulus-H, belt-hash, and two new CRCs (crc64_nvme and crc32_go-koopman) complete the list.

Is my algorithm broken?

Jacksum can tell you now. The output of --info has a new section called "Security:" that says whether an algorithm is considered broken, and -V details also explains why:

$ jacksum -a sha1 --info -V details
  ...
  Security:
    broken:                               yes
      yes, 02/2017: the first identical-prefix collision was computed
      (SHAttered, 2^63.1), and in 01/2020 the first chosen-prefix
      collision followed ...

--info shows the avalanche effect of an algorithm as well, and programs that use Jacksum as a library can query the broken state through the API. If you are not sure which algorithm to pick, read the new Algorithm Selection Guide.

Better verification

--check-strict now also fails if files have been added to or removed from the directory, it prints the result in the summary, and the exit code follows it. With --ignore-hashes, --ignore-sizes, and --ignore-timestamps you decide which stored properties are checked. A file that cannot be read gets the new status ERROR instead of being reported as MISSING. And if a check file has been created with a different algorithm than the selected one, Jacksum names the cause rather than reporting every file as FAILED.

Better compatibility with other tools

The styles bsd, openssl-dgst, and solaris-digest-v now write the algorithm names that the native tools use, so their output is identical to md5, shasum --tag, sha256sum --tag, openssl dgst (OpenSSL 3.x and later), and digest -v on Solaris. If you need the OpenSSL 1.1.1 names (SHA256 instead of SHA2-256), use the new style openssl111-dgst. The new hdb style writes the hash data base format of ClamAV's sigtool.

More robust than ever

Jacksum 4 fixes a lot of bugs, in particular in the multi-threaded engine (out-of-memory errors, possible deadlocks, read errors that could go unnoticed), in the parser, in the encodings, and in a few algorithms. The releases 4.0.1 and 4.0.2 alone close more than 40 GitHub issues. Jacksum also no longer writes an HMAC key in plain text into the header of a check file. The bundled Bouncy Castle has been updated to 1.86.

Documentation in German

The help is available in German now (jacksum -h de), and so are the documents on GitHub. The new Use Cases cookbook (English and German) is organized by goal: "I want to solve this problem".

Please note before you upgrade

  • Jacksum 4 requires Java 21 or later. Java 25 is recommended.
  • An HMAC can no longer be calculated with the algorithms of the ascon family, because there is no standard-compliant HMAC for sponge-based hash functions.
  • Some algorithms return different values now, because the old values were wrong: prng, fletcher16 (input larger than 64 KiB), sum64 (very large input), and truncated HMACs whose length is not a multiple of 8 bits.
  • The style openssl-dgst uses the OpenSSL 3.x names now. Use openssl111-dgst for the old behavior.
  • For API users: the bundled Bouncy Castle has moved from org.bouncycastle to net.jacksum.zzadopt.org.bouncycastle, and the adopted GNU Crypto classes have moved to net.jacksum.zzadopt.org.gnu.crypto.

Have fun with Jacksum 4, and let me know what you think!

Footnotes:
  1. BlueMidnightWish-[224,256,384,512], CubeHash-[224,256,384,512], Hamsi-[224,256,384,512], Shabal-[192,224,256,384,512], and SIMD-[224,256,384,512] ↩

  2. MD6 (md6-8 to md6-512 in steps of 8) and Edon-R-[224,256,384,512] ↩

  3. Romulus-H is one of the finalists of the NIST Lightweight Cryptography competition ↩

  4. belt-hash is the hash function of the Belarusian national standard STB 34.101.31 ↩

  5. unless the encoding has a case-sensitive alphabet, such as Base64 or Z85 ↩

  6. the styles bsd, openssl-dgst, and solaris-digest-v ↩

Tuesday, October 13, 2026

A New Look for HashGarten: Unveiling the Official Logo

I am excited to introduce the brand-new official logo for HashGarten, the graphical frontend for Jacksum!



What's in a Name?

Just as Jacksum plays on the word checksum, HashGarten carries a special meaning of its own.

In a traditional kindergarten, children are nurtured, cherished, and cared for like young plants—a German concept and word that has found its way into languages all around the world. HashGarten borrows this exact sentiment: it is a garden, too, but one carefully cultivated for hash algorithms.


The Design Concept

To match this unique blend of nature and cryptography, the new logo visually reflects HashGarten's core identity:

  • Wordplay & Dual Meaning: The motif combines the stylized shape of a hemp leaf with a modern hash symbol (#) and digital data nodes, bridging the organic idea of a "Garten" with the digital realm of hashing.
  • Authentic Leaf Geometry: The leaf features distinct serrated edges, preserving the iconic natural outline while providing a bold structure for technical details.
  • Seamless Tech Integration: Subtle hash symbols (#) and circuit-like data nodes are embedded directly into the leaf’s veins, seamlessly weaving the cryptographic theme into the organic form.
  • Crisp Scalability: Built with clean vector geometry, the logo maintains its sharp, recognizable silhouette even at small icon sizes—such as 32×32 pixel favicons or application icons.

Check out the project, explore the release, and view the source code over on GitHub!

Wednesday, March 4, 2026

How I fixed Sequoia's screencapture on an OCLP patched MacBookPro8,1

Problem

On an early 2011 MacBook Pro (Model MacBookPro8,1), I upgraded from Catalina 10.15.8 to Sequoia 15.7.1 using OCLP 2.4.1. Following the upgrade, the screen capture features stopped working. While I could still trigger the shortcuts (Cmd+Shift+3 for the whole screen or Cmd+Shift+4 for a selected area), the screenshot images no longer appeared on the desktop as expected.

Investigation

Previously, I successfully upgraded several MacBookPro9,2 models (the Mid-2012 version with user-replaceable RAM and SSD) from Catalina to Sequoia 15.7.4 using OCLP 2.4.1 without any issues. This suggested a specific compatibility problem with the older 8,1 model.

Upon further investigation, I discovered that the screencapture binary crashes immediately on the MacBookPro8,1. Running it via the command line yielded:

% /usr/sbin/screencapture
zsh: killed     /usr/sbin/screencapture  

In contrast, the MacBookPro9,2 handles the command normally:

% /usr/sbin/screencapture
screencapture: no file specified  

Beyond just a difference in file size, using the file command revealed a discrepancy in architectures. On the older model, the binary only contains code for x86_64, whereas the binary on the later model is a Universal binary containing both x86_64 and arm64e. It appears the binary on the 8,1 model may have been stripped or corrupted during the patching process.

The Workaround

Regardless of the root cause, I found that copying the functional binary from the newer model to the older one restores functionality.

However, this isn't as simple as a standard file copy. The /usr/sbin directory is protected by System Integrity Protection (SIP) and the partition is mounted as read-only. Furthermore, reapplying OCLP root patches in the future would likely overwrite the fix.

To solve this, I wrote a shell script to automate the process, making it easy to re-apply the fix whenever necessary without manual re-mounting or complex commands. 

The script is now available here: https://github.com/jonelo/screencapture-fix

Precondition: SIP must be disabled. The script expects an unmodified screencapture binary in the same directory where the script is stored. To restore your screen capture functionality, simply run:

% sudo ./screencapture-fix.sh