This is an automated email from the ASF dual-hosted git repository.

papegaaij pushed a commit to branch crypt-unification
in repository https://gitbox.apache.org/repos/asf/wicket.git

commit 33eaf71733eb3bfb2f71b99b618585db95cb69a4
Author: Emond Papegaaij <[email protected]>
AuthorDate: Fri Jul 3 16:04:56 2026 +0200

    WICKET-7190 Update the user guide for the redesigned crypt API
    
    The "URLs encryption in detail" section still described the Wicket 10 crypt 
API
    (some of it already stale before this work). Bring it in line with the 
redesign:
    
    - ICrypt is shown from its real package org.apache.wicket.core.util.crypt 
with
      the byte-array + URL-safe-String signature and the null-on-failure 
contract.
    - The default implementation is SchemeCrypt (self-describing, authenticated
      ciphertext), not SunJceCrypt/PBEWithMD5AndDES. Document the pluggable
      ICryptScheme, the default AesGcmCryptScheme (JDK-native AES-256-GCM), the
      scheme whitelist / downgrade protection and migration, and the 
AES-256-GCM-SIV
      opt-in (requires Bouncy Castle).
    - The default factory is KeyInSessionCryptFactory (was 
KeyInSessionSunJceCrypt-
      Factory); the stateless note now points to ApplicationKeyCryptFactory.
    
    Also drop the outdated warning in the URL chapter that the default cipher 
"might
    not be strong enough for production": the default is now authenticated
    AES-256-GCM with a per-session key.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
---
 .../src/main/asciidoc/security/security_4.adoc     | 43 +++++++++++++++-------
 .../src/main/asciidoc/urls/urls_6.adoc             |  4 +-
 2 files changed, 31 insertions(+), 16 deletions(-)

diff --git a/wicket-user-guide/src/main/asciidoc/security/security_4.adoc 
b/wicket-user-guide/src/main/asciidoc/security/security_4.adoc
index 17c5939628..8e7dbd644c 100644
--- a/wicket-user-guide/src/main/asciidoc/security/security_4.adoc
+++ b/wicket-user-guide/src/main/asciidoc/security/security_4.adoc
@@ -1,27 +1,45 @@
 
-In chapter <<_generating_structured_and_clear_urls,10.6>> we have seen how to 
encrypt URLs using _CryptoMapper_ request mapper. To encrypt/decrypt page URLs 
_CryptoMapper_ uses an instance of _org.apache.wicket.util.crypt.ICrypt_ 
interface:
+In chapter <<_generating_structured_and_clear_urls,10.6>> we have seen how to 
encrypt URLs using _CryptoMapper_ request mapper. To encrypt/decrypt page URLs 
_CryptoMapper_ uses an instance of the 
_org.apache.wicket.core.util.crypt.ICrypt_ interface:
 
 [source,java]
 ----
 public interface ICrypt
 {
-       String encryptUrlSafe(final String plainText);
+       byte[] encrypt(byte[] plainBytes, byte[] associatedData);
 
-       String decryptUrlSafe(final String encryptedText);
+       byte[] decrypt(byte[] encryptedBytes, byte[] associatedData);
+
+       // URL-safe (Base64) String convenience layer used by CryptoMapper
+       default String encryptUrlSafe(String plainText) { ... }
+
+       default String decryptUrlSafe(String encryptedText) { ... }
 
        ...
 }
 ----
 
-The default implementation for this interface is class 
_org.apache.wicket.util.crypt.SunJceCrypt_. It provides password-based 
cryptography using _PBEWithMD5AndDES_ algorithm coming with the standard 
security providers in the Java Runtime Environment.
+_ICrypt_ works on raw bytes and provides a URL-safe Base64 _String_ layer on 
top. The same interface is used everywhere Wicket encrypts data: encrypted URLs 
(_CryptoMapper_), the page store (see <<_page_storing,the chapter on page 
storing>>) and the "remember me" cookie. Decryption returns `null` on _any_ 
failure (unknown cipher, failed authentication, malformed input) instead of 
throwing, so undecryptable data is uniformly treated as absent.
 
-NOTE: Since Java 9, unlimited strength cryptography is enabled by default. No 
additional configuration is needed.
+The default implementation is _org.apache.wicket.core.util.crypt.SchemeCrypt_. 
It produces *self-describing, authenticated* ciphertext: every ciphertext is 
prefixed with a one-byte marker identifying the cipher (the "scheme") that 
produced it, and the payload is protected with authenticated encryption (AEAD) 
so any tampering is detected on decryption. The actual cipher is a pluggable 
_org.apache.wicket.core.util.crypt.ICryptScheme_; by default this is 
_AesGcmCryptScheme_, which uses JDK- [...]
 
-By using _CryptoMapper(IRequestMapper wrappedMapper, Application application)_ 
constructor the mapper will use the configured 
_org.apache.wicket.util.crypt.ICryptFactory_ from 
_org.apache.wicket.settings.SecuritySettings.getCryptFactory()_. To use a 
stronger cryptography mechanism there are the following options:
+NOTE: Since Java 9 unlimited strength cryptography is enabled by default, so 
AES-256 works out of the box with no additional configuration.
 
-* The first option is to use constructor _CryptoMapper(IRequestMapper 
wrappedMapper, Supplier<ICrypt> cryptProvider)_ and give it an implementation 
of _java.util.function.Supplier_ that returns a custom 
_org.apache.wicket.util.crypt.ICrypt_.
+The scheme is configured application-wide through 
_org.apache.wicket.settings.SecuritySettings_:
 
-* The second option is to register a cipher factory at application level with 
method _setCryptFactory(ICryptFactory cryptFactory)_ of class 
_SecuritySettings_:
+[source,java]
+----
+@Override
+public void init() {
+       super.init();
+       // switch to AES-256-GCM-SIV (nonce-misuse resistant); requires Bouncy 
Castle
+       getSecuritySettings().setCryptScheme(new AesGcmSivCryptScheme());
+       setRootRequestMapper(new CryptoMapper(getRootRequestMapper(), this));
+}
+----
+
+_AesGcmSivCryptScheme_ (AES-256-GCM-SIV) is also available but requires 
https://www.bouncycastle.org/[Bouncy Castle] on the classpath with its provider 
registered. On decryption, the scheme marker must match one of the schemes 
accepted by _SecuritySettings.setWhitelistedCryptSchemes_ (the encryption 
scheme is always accepted); unknown or non-whitelisted schemes are refused, 
which prevents downgrade attacks. To migrate to a stronger scheme without 
breaking existing data, temporarily white [...]
+
+While the scheme decides _how_ data is encrypted, an 
_org.apache.wicket.core.util.crypt.ICryptFactory_ decides _which key_ to use. 
The factory is configured with 
_SecuritySettings.setCryptFactory(ICryptFactory)_:
 
 [source,java]
 ----
@@ -33,11 +51,8 @@ public void init() {
 }
 ----
 
+The default factory is 
_org.apache.wicket.core.util.crypt.KeyInSessionCryptFactory_. It generates a 
unique, random 256-bit key for each user and stores it in her HTTP session. 
This way it helps to protect the application against 
https://owasp.org/www-community/attacks/csrf[CSRF] for each user of the 
application: the url itself serves as an 
https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html[encrypted
 token].
 
-Since version 6.19.0 Wicket uses 
_org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory_ as a default 
factory for _ICrypt_ objects. This factory generates a unique key for each user 
that is stored in her HTTP 
-session. This way it helps to protect the application against 
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)[CSRF]
-for each user of the application. The url itself serves as 
https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet#Encrypted_Token_Pattern[encrypted
 token]
-
-WARNING: _org.apache.wicket.core.util.crypt.KeyInSessionSunJceCryptFactory_ 
binds the http session if it is not already bound! If the application needs to 
run in stateless mode then the application will have to provide a custom 
-implementation of _ICryptFactory_ that stores the user specific keys by other 
means.
+WARNING: _KeyInSessionCryptFactory_ binds the HTTP session if it is not 
already bound! If the application needs to run in stateless mode it must 
provide a factory that does not rely on the session &mdash; for example 
_org.apache.wicket.core.util.crypt.ApplicationKeyCryptFactory_ with a stable, 
application-wide key. Note that an application-wide key means encrypted URLs 
are no longer isolated per user.
 
+Finally, _CryptoMapper_ offers two constructors: _CryptoMapper(IRequestMapper 
wrappedMapper, Application application)_ uses the _ICryptFactory_ configured on 
_SecuritySettings_, while _CryptoMapper(IRequestMapper wrappedMapper, 
Supplier<ICrypt> cryptProvider)_ lets you supply a specific _ICrypt_ instance 
directly.
diff --git a/wicket-user-guide/src/main/asciidoc/urls/urls_6.adoc 
b/wicket-user-guide/src/main/asciidoc/urls/urls_6.adoc
index 7f0ab3b16f..721ae8cee2 100644
--- a/wicket-user-guide/src/main/asciidoc/urls/urls_6.adoc
+++ b/wicket-user-guide/src/main/asciidoc/urls/urls_6.adoc
@@ -224,6 +224,6 @@ public void init() {
 
 As pointed out in the code above, pages and resources must be mounted after 
having set _CryptoMapper_ as root mapper, otherwise the mounted paths will not 
work.
 
-WARNING: By default _CryptoMapper_ encrypts page URLs with a cipher that might 
not be strong enough for production environment. Paragraph
-<<_security_with_wicket,"Security with Wicket">> will provide a more detailed 
description of how Wicket encrypts page URLs and we will see how to use 
stronger ciphers.
+NOTE: By default _CryptoMapper_ encrypts page URLs with authenticated 
AES-256-GCM using a unique key per user session, which is suitable for 
production. Section
+<<_urls_encryption_in_detail,"URLs encryption in detail">> describes how 
Wicket encrypts URLs and how to configure the cipher (scheme) and the key 
source.
 

Reply via email to