This project implements the OPRF and OPAQUE security protocols to provide a way for common services to reduce their attack surfaces including offline attacks from stolen credentials. Usable with standard Java frameworks like Dropwizard and Spring Boot.
| Directory | Description |
|---|---|
hofmann-typescript |
Browser/Node TypeScript client — RFC 9497 OPRF + RFC 9807 OPAQUE-3DH. Built on @noble/curves and @noble/hashes. Includes a Vite-powered interactive demo page. |
| Directory | Description |
|---|---|
hofmann-demo |
Docker Compose environment running the Dropwizard server and the TypeScript demo UI behind HAProxy with TLS 1.3. Self-signed P-256 cert generated via make certs. Run with make up. |
See hofmann-elimination-example for a complete working application demonstrating OPAQUE integration end-to-end.
- Project landing page — overview, protocol diagrams, quick start guides
- Migration guide — how to migrate an existing site from traditional password auth to OPAQUE
- Configuration guide — server configuration, key management, credential store implementation
- Account recovery guide — pluggable account recovery via email, OTP, or custom mechanisms
- Interactive API docs — Swagger UI for OPAQUE and OPRF endpoints
- At runtime: Start your Dropwizard or Spring Boot server and visit
/api-docs/for embedded Swagger UI - Raw OpenAPI specs: OPRF API | OPAQUE API
./gradlew clean build test
cd hofmann-typescript
npm install
npm test
npm run build
This project provides a pure Java implementation of the OPRF and OPAQUE protocols, enabling services to authenticate users without ever storing or transmitting the password or private key material. By using OPRF and OPAQUE, services can significantly reduce the attack surface and protect user credentials even in the event of a server breach — a compromised server database does not expose passwords to offline dictionary attacks because the server never holds a recoverable form of the password.
This project also provides the OPRF primitive on its own. This allows clients to create identifiers from hashing sensitive material that are consistent and reusable across multiple clients without sharing that key material that generated them. The result is an identifier that services can use without learning what data produced it. Useful when that data is sensitive information the client wants to keep private.
This project implements three layered RFCs:
-
Hash-to-Curve (details, rfc 9380): Deterministically maps arbitrary input to an elliptic curve point using Simplified SWU and
expand_message_xmd. Used internally by OPRF. -
OPRF (details, rfc 9497): Oblivious Pseudorandom Functions. The client computes a pseudorandom function on private input using the server's secret key, without the server ever learning the input. Supports P-256/SHA-256, P-384/SHA-384, P-521/SHA-512, and Ristretto255/SHA-512.
-
OPAQUE (details, rfc 9807): Augmented Password-Authenticated Key Exchange. Password-based authentication where the password is never transmitted and a compromised server database does not expose passwords to offline dictionary attacks.
-
Account Recovery (details): Pluggable account recovery that works alongside OPAQUE without modifying the protocol. Users prove their identity through an out-of-band mechanism (email code, SMS OTP, TOTP, etc.) and then re-register with a new password. Implement the
RecoveryChallengerinterface to define your recovery method.
For protocol details, cipher suites, API reference, and wire formats, see the linked docs above.
As of February 2026, this implementation has not undergone a formal security audit. See SECURITY.md for the full security posture, known design decisions, and how to report vulnerabilities.
Initial RFC implementations were produced with the help of AI tooling and reviewed against the RFC specifications by a human (Ned). AIs have also been used to search for direct and side-channel attack vectors, but this is not a substitute for a formal third-party audit.
For a detailed feature comparison table across all projects, see the project landing page. This project is the only known pure-Java, RFC-compliant (9380 + 9497 + 9807) implementation supporting multiple cipher suites that is distributable as a standard Maven artifact with framework integrations. But I link to the other projects in case this does not meet your needs.
Copyright 2026 Ned Wolpert
Licensed 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
http://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.
The Hofmann Elimination is a chemical reaction that involves the elimination of an amine to produce an alkene. This reaction is named after the German chemist August Wilhelm von Hofmann, who first described it in the 19th century. The Hofmann elimination is often used to synthesize alkenes from amines. It does this by treating the quaternary ammonium salt with a strong base, such as sodium hydroxide, which leads to the elimination of the ammonium group and the formation of an alkene. The reaction is typically carried out under heat to facilitate the elimination process.
Unlike other elimination reactions, the Hofmann elimination produces the least substituted alkene as the major product, which is a result of the steric hindrance around the quaternary ammonium salt. This makes it a useful reaction for synthesizing specific alkenes that may be difficult to obtain through other methods.
Just as the Hofmann elimination removes an amine group from a molecule, leaving no trace of the original nitrogen compound in the product, this protocol eliminates the password and private key material from every value that leaves the client. The server evaluates the function, stores credentials, and verifies authentication without ever seeing the sensitive input.