Skip to content

Add a secure cache to Windows Hello to make it usable (amount of prompts) #105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from

Conversation

purejava
Copy link
Contributor

@purejava purejava commented Apr 4, 2025

I am glad to request this change to finalize the Windows Hello integration.

Based on an idea from @infeo

"to implement caching only in the integrations-win, as natively as possible. General: Windows Hello only produces a single key and all entries are encrypted with this key. The key is left in memory the first time it is used using CryptProtectMemory. If the user has to log in again, the key must also be reloaded."

I implemented this as natively as possible. Knowing, that caching secure data is a tradeoff to security, this makes Windows Hello usable, as it reduces the prompts to a required minimum, e.g. on changing the password for a vault.

Basically, the Windows Hello prompt comes up once for every vault used. The sensitive information is keep in memory, but nevertheless protected by CryptProtectMemory.

So, after all, this is a gain in security and fits well to the new Touch ID feature on Mac.

This PR depends on a small change in Cryptomator, that the Hello keychain path property needs to be added to the Environment. I'll open a separate PR for this.

Edit: depends on cryptomator/cryptomator#3808
Edit 2: The Windows Hello prompt does not come up for every vault used, this was changed by 6bda0f9.

Copy link

coderabbitai bot commented Apr 4, 2025

"""

Walkthrough

The changes update two areas of the codebase. In the Java module descriptor (module-info.java), the service provision for the KeychainAccessProvider is expanded to include both WindowsProtectedKeychainAccess and WindowsHelloKeychainAccess, modifying the module’s service declaration to support multiple providers.

In the native code (WindowsHello_Native.cpp), a thread-safe caching mechanism is introduced for Windows Hello signature data keyed by keyId. This uses a global mutex and an unordered map to store encrypted signature data. Two new helper functions, ProtectMemory and UnprotectMemory, utilize Windows API calls (CryptProtectMemory and CryptUnprotectMemory) to encrypt and decrypt cached data in-process. The deriveEncryptionKey function is updated to first attempt to use cached signature data before generating a new signature, with improved error handling and secure memory clearing. The function signature is also changed to take the keyId parameter by const reference.

In the Java class WindowsHello, a fixed challenge byte array is introduced and used internally in the encrypt and decrypt methods instead of the previously passed dynamic challenge parameter, changing the internal logic without modifying public method signatures.

Possibly related PRs

  • Add Windows Hello support #83: Introduces Windows Hello support including the WindowsHelloKeychainAccess implementation and native integration, closely related by adding Windows Hello keychain access functionality and modifying service provider declarations.

Suggested reviewers

  • infeo
    """

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 30th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (2)

28-28: Concurrent caching strategy is sound but consider cache eviction.
Defining a global cache (keyCache) guarded by cacheMutex is correct to avoid data races. However, you may want to periodically invalidate or limit the cache size to prevent indefinite growth or stale entries persisting in memory.

Also applies to: 30-47, 49-53, 55-55


200-234: Signing the challenge and populating the cache is correct.
The logic for creating or opening the Windows Hello credential, signing the challenge, and then protecting/storing it in the cache is appropriate. Consider clarifying behavior for user-canceled prompts (line 215) if enhanced UX is desired.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ade0318 and c5f31ac.

📒 Files selected for processing (2)
  • src/main/java/module-info.java (1 hunks)
  • src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (1)
Learnt from: purejava
PR: cryptomator/integrations-win#83
File: src/main/native/org_cryptomator_windows_keychain_WinHello_Native.cpp:0-0
Timestamp: 2025-04-03T12:51:14.634Z
Learning: In `src/main/native/org_cryptomator_windows_keychain_WinHello_Native.cpp`, additional error handling and input validation in the `deriveEncryptionKey` function may not be necessary unless specific issues are identified.
🔇 Additional comments (8)
src/main/java/module-info.java (1)

23-23: Provision of multiple keychain providers looks good.
Adding WindowsHelloKeychainAccess alongside WindowsProtectedKeychainAccess appears consistent with the PR’s objective to provide both functionalities for keychain access.

src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (7)

9-9: Includes for cryptographic operations and hashing are appropriate.
These newly added headers (<wincrypt.h>, <unordered_map>, <mutex>, and <functional>) are necessary to implement the secure caching and memory protection functionalities.

Also applies to: 10-11, 19-19


58-58: Memory protection functions are correctly implemented.
Using CryptProtectMemory and CryptUnprotectMemory to protect sensitive data is a reputable approach. Ensure these functions remain compatible with your targeted Windows versions.

Also applies to: 59-65, 67-73


178-178: Passing keyId by reference is a performance and clarity improvement.
Changing bool deriveEncryptionKey(const std::wstring keyId, ...) to bool deriveEncryptionKey(const std::wstring& keyId, ...) avoids unnecessary copies.


184-185: Securely retrieving and unprotecting data from cache is well-handled.
The lock-based retrieval ensures thread-safe access, and the explicit unprotection step prevents storing plaintext in memory. This flow aligns with secure caching requirements.

Also applies to: 187-198


236-238: Converting signature data into an IBuffer is implemented correctly.
This step is straightforward and consistent with your subsequent HKDF usage.


241-242: Zeroing out sensitive data helps prevent lingering in memory.
Overwriting signatureData after deriving the key is a good security practice, reducing the window of exposure.


244-244: Final return statement concludes the flow gracefully.
No issues noted; the function clearly returns success at this point.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (2)

165-169: Consider adding cache invalidation mechanism.

While the current implementation works well for caching Windows Hello signatures, there's no mechanism to invalidate or expire cached entries. Consider adding time-based expiration or a way to clear the cache when certain security events occur.

 static std::mutex cacheMutex;
-static std::unordered_map<std::wstring, std::vector<uint8_t>> keyCache;
+// Cache entry with timestamp for potential expiration
+struct CacheEntry {
+    std::vector<uint8_t> data;
+    std::chrono::system_clock::time_point timestamp;
+};
+static std::unordered_map<std::wstring, CacheEntry> keyCache;
+
+// Helper to clear cache (can be exposed via JNI if needed)
+void clearCache() {
+    std::lock_guard<std::mutex> lock(cacheMutex);
+    keyCache.clear();
+}

And then in the cache lookup code:

 auto it = keyCache.find(keyId);
 if (it != keyCache.end()) {
-    signatureData = it->second;
+    // Optional: Check if entry has expired (e.g., after 30 minutes)
+    auto now = std::chrono::system_clock::now();
+    if (now - it->second.timestamp > std::chrono::minutes(30)) {
+        keyCache.erase(it);
+    } else {
+        signatureData = it->second.data;
+        if (!UnprotectMemory(signatureData)) {
+            throw std::runtime_error("Failed to unprotect memory.");
+        }
+        foundInCache = true;
+    }
-    if (!UnprotectMemory(signatureData)) {
-        throw std::runtime_error("Failed to unprotect memory.");
-    }
-    foundInCache = true;
 }

And when storing:

 {
     std::lock_guard<std::mutex> lock(cacheMutex);
-    keyCache[keyId] = protectedCopy;
+    keyCache[keyId] = {protectedCopy, std::chrono::system_clock::now()};
 }

173-174: Consider adding a JNI method to pre-cache keys.

Since the core functionality already supports caching, consider exposing a JNI method that allows pre-caching keys during application startup or at strategic points in the user workflow to further reduce prompts.

This would allow the Java layer to proactively trigger the Windows Hello prompt at the most appropriate time for the user, further improving usability while maintaining security.

// Example JNI method to pre-cache a key
jboolean JNICALL Java_org_cryptomator_windows_keychain_WindowsHello_00024Native_preCacheKey
(JNIEnv* env, jobject obj, jbyteArray keyId, jbyteArray challenge) {
    queueSecurityPromptFocus();
    try {
        std::vector<uint8_t> challengeVec = jbyteArrayToVector(env, challenge);
        
        winrt::init_apartment(winrt::apartment_type::single_threaded);
        
        auto toReleaseKeyId = (LPCWSTR)env->GetByteArrayElements(keyId, NULL);
        const std::wstring keyIdentifier(toReleaseKeyId);
        
        IBuffer key;
        bool result = deriveEncryptionKey(keyIdentifier, challengeVec, key);
        
        env->ReleaseByteArrayElements(keyId, (jbyte*)toReleaseKeyId, JNI_ABORT);
        return result ? JNI_TRUE : JNI_FALSE;
    }
    catch (...) {
        return JNI_FALSE;
    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c5f31ac and f18f6a9.

📒 Files selected for processing (1)
  • src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (3 hunks)
🧰 Additional context used
🧠 Learnings (1)
src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (2)
Learnt from: purejava
PR: cryptomator/integrations-win#83
File: src/main/native/org_cryptomator_windows_keychain_WinHello_Native.cpp:0-0
Timestamp: 2024-11-16T17:26:11.536Z
Learning: In `src/main/native/org_cryptomator_windows_keychain_WinHello_Native.cpp`, additional error handling and input validation in the `deriveEncryptionKey` function may not be necessary unless specific issues are identified.
Learnt from: purejava
PR: cryptomator/integrations-win#83
File: src/main/native/org_cryptomator_windows_keychain_WinHello_Native.cpp:0-0
Timestamp: 2024-11-18T20:38:43.547Z
Learning: In `deriveEncryptionKey` in `src/main/native/org_cryptomator_windows_keychain_WinHello_Native.cpp`, additional null checks on `result.Credential()` are unnecessary because the Windows API guarantees it is non-null or throws an exception otherwise.
🔇 Additional comments (9)
src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (9)

9-11: Appropriate includes added for new functionality.

The additions of wincrypt.h, unordered_map, and mutex are appropriate for implementing the secure caching mechanism with thread safety.


27-28: Thread-safe cache implementation.

Good implementation of a thread-safe cache using a mutex for synchronization and an unordered map for storage. The key design is appropriate - using the Windows Hello keyId as the map key and storing the protected signature data as the value.


31-38: Memory protection implementation looks good.

The ProtectMemory function properly uses CryptProtectMemory with the correct protection level (CRYPTPROTECTMEMORY_SAME_PROCESS). The function includes appropriate error handling and empty data validation.


40-46: Memory unprotection implementation looks good.

The UnprotectMemory function correctly implements the inverse operation using CryptUnprotectMemory with consistent protection level and error handling.


151-151: Function signature improvement.

Good change to pass the keyId parameter by const reference, which avoids unnecessary copying of the string.


157-171: Thread-safe cache retrieval implementation.

Well-structured implementation that:

  1. Uses a lock guard for thread safety
  2. Attempts to find the cached key
  3. Properly unprotects the memory if found
  4. Throws an exception with a clear error message if memory unprotection fails

This approach effectively reduces the number of Windows Hello prompts by reusing cached credentials.


173-206: Well-implemented cache population logic.

This code segment appropriately:

  1. Falls back to Windows Hello credential retrieval when not found in cache
  2. Handles different status codes from Windows Hello API
  3. Creates a protected copy of sensitive data
  4. Uses a lock guard for thread-safe cache updates
  5. Cleans up sensitive data by zeroing the buffer after use

The approach aligns well with the PR objective of reducing Windows Hello prompts while maintaining security.


208-215: Good security practice for handling sensitive data.

The code properly:

  1. Creates a signature buffer from the retrieved data
  2. Derives the encryption key using HKDF
  3. Clears the sensitive signature data by zeroing the buffer after use

This follows the principle of minimizing the lifetime of sensitive data in memory.


194-198: Memory protection exception handling.

Good practice to throw an exception when memory protection fails. This is a critical security operation and failing silently would be inappropriate. The exception with a descriptive message helps with troubleshooting.

Comment on lines 32 to 37
bool ProtectMemory(std::vector<uint8_t>& data) {
if (data.empty()) return false;
if (!CryptProtectMemory(data.data(), static_cast<DWORD>(data.size()), CRYPTPROTECTMEMORY_SAME_PROCESS)) {
return false;
}
return true;
Copy link

@coderabbitai coderabbitai bot May 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Verify memory alignment for CryptProtectMemory.

CryptProtectMemory requires that the data length is a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16 bytes). While the current implementation works with the signature data, ensure that all data passed to this function meets this requirement.


🏁 Script executed:

#!/bin/bash
# Verify if the signature data length is always a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE

# Search for signature data extraction
rg "signatureData = " -A 3 -B 3

Length of output: 1618


Ensure Block Alignment for CryptProtectMemory Input

CryptProtectMemory mandates that the length of the buffer be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE (16). Currently, ProtectMemory is invoked directly on the raw data vector, which may not satisfy this requirement and can cause failures or silent padding issues.

Please update the code to pad or validate the data size before calling CryptProtectMemory. For example:

bool ProtectMemory(std::vector<uint8_t>& data) {
    if (data.empty()) return false;
    // enforce 16-byte alignment
    const size_t block = CRYPTPROTECTMEMORY_BLOCK_SIZE;
    size_t pad = (block - (data.size() % block)) % block;
    if (pad) {
        data.insert(data.end(), pad, 0);
    }
    if (!CryptProtectMemory(data.data(), static_cast<DWORD>(data.size()), CRYPTPROTECTMEMORY_SAME_PROCESS)) {
        return false;
    }
    return true;
}

• File: src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp
Function: ProtectMemory (around lines 32–37)
• Call sites: ensure any buffer passed in (e.g., signatureData) is block-aligned or padded.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@purejava Since the we hand over the signature, which has not a documented defined length, the input data should be validated to be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE bytes. If this is not the case, throw an runtime_error with a more specific error message.

This is for the case Microsoft changes the signature size to a not multiple of 16

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Member

@infeo infeo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested this on a laptop with WindowsHello (fingerprint). Looks good, also tested it in combination with Cryptomator.

When i looked at the code, i think i found some issues about not zero'd arrays, but this is not part of this PR.

Comment on lines 32 to 37
bool ProtectMemory(std::vector<uint8_t>& data) {
if (data.empty()) return false;
if (!CryptProtectMemory(data.data(), static_cast<DWORD>(data.size()), CRYPTPROTECTMEMORY_SAME_PROCESS)) {
return false;
}
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@purejava Since the we hand over the signature, which has not a documented defined length, the input data should be validated to be a multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE bytes. If this is not the case, throw an runtime_error with a more specific error message.

This is for the case Microsoft changes the signature size to a not multiple of 16

Comment on lines 173 to 205
if (!foundInCache) {
auto result = KeyCredentialManager::RequestCreateAsync(keyId, KeyCredentialCreationOption::FailIfExists).get();

if (result.Status() == KeyCredentialStatus::CredentialAlreadyExists) {
result = KeyCredentialManager::OpenAsync(keyId).get();
}
return false;
else if (result.Status() != KeyCredentialStatus::Success) {
std::cerr << "Failed to retrieve Windows Hello credential." << std::endl;
return false;
}

const auto signature = result.Credential().RequestSignAsync(challengeBuffer).get();

if (signature.Status() != KeyCredentialStatus::Success) {
if (signature.Status() != KeyCredentialStatus::UserCanceled) {
std::cerr << "Failed to sign challenge using Windows Hello." << std::endl;
}
return false;
}

signatureData = iBufferToVector(signature.Result());
std::vector<uint8_t> protectedCopy = signatureData;

if (!ProtectMemory(protectedCopy)) {
throw std::runtime_error("Failed to protect memory.");
}

// Store in cache
{
std::lock_guard<std::mutex> lock(cacheMutex);
keyCache[keyId] = protectedCopy;
}
std::fill(protectedCopy.begin(), protectedCopy.end(), 0);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to its own method

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@infeo I implemented the changes:

  • CRYPTPROTECTMEMORY_BLOCK_SIZE
  • Move this to its own method

I could not spot any places, where zeroing vectors has been forgotten.

On testing, I noticed a missing piece on the cache implementation: when a signature is cached and a second vault created afterwards (with the cached signature), HMAC verification failed for the second vault, when you end the app, start it again and try to unlock the second vault first. This was due to a newly created challenge for the second vault.

This is fixed now too by using a fixed challenge in the WindowsHello class, as discussed for this last part of the cache implementation.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
src/main/java/org/cryptomator/windows/keychain/WindowsHello.java (3)

9-14: Document security considerations for using a fixed challenge

Using a fixed challenge rather than a dynamic one is a deliberate design choice to enable caching Windows Hello authentication results. While this improves usability by reducing authentication prompts, it's worth documenting this security trade-off directly in the code.

Consider adding a comment explaining the purpose and security implications of using a fixed challenge:

 private final byte[] fixedChallenge = new byte[] {
+	// Using a fixed challenge enables caching of Windows Hello authentication results,
+	// reducing the number of prompts. The actual encryption key is still protected 
+	// in memory using CryptProtectMemory in the native implementation.
 	'1', '2', '3', '4',
 	'5', '6', '7', '8',
 	'9', '0', 'A', 'B',
 	'C', 'D', 'E', 'F'
 };

21-22: Document that the challenge parameter is ignored

The method now uses the fixed challenge instead of the parameter, but the method signature remains unchanged for compatibility. This behavior should be documented to avoid confusion.

Consider adding a comment or updating the method signature:

 @Override
+// The challenge parameter is ignored and fixedChallenge is used instead to enable caching
 public byte[] encrypt(byte[] cleartext, byte[] challenge) {
 	return Native.INSTANCE.setEncryptionKey(keyId, cleartext, fixedChallenge);
 }

26-27: Document that the challenge parameter is ignored

The decrypt method also now uses the fixed challenge instead of the parameter. As with the encrypt method, this behavior should be documented.

Consider adding a comment similar to the one suggested for encrypt:

 @Override
+// The challenge parameter is ignored and fixedChallenge is used instead to enable caching
 public byte[] decrypt(byte[] ciphertext, byte[] challenge) {
 	return Native.INSTANCE.getEncryptionKey(keyId, ciphertext, fixedChallenge);
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f18f6a9 and 2b119e8.

📒 Files selected for processing (2)
  • src/main/java/org/cryptomator/windows/keychain/WindowsHello.java (1 hunks)
  • src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/main/native/org_cryptomator_windows_keychain_WindowsHello_Native.cpp
🧰 Additional context used
🧠 Learnings (1)
src/main/java/org/cryptomator/windows/keychain/WindowsHello.java (1)
Learnt from: infeo
PR: cryptomator/integrations-win#83
File: src/main/java/org/cryptomator/windows/keychain/WinHello.java:29-41
Timestamp: 2024-11-11T15:58:12.072Z
Learning: In `src/main/java/org/cryptomator/windows/keychain/WinHello.java`, the `Native` class is private and only accessible within its enclosing class. Therefore, making `INSTANCE` private and adding a getter method is unnecessary.
🧬 Code Graph Analysis (1)
src/main/java/org/cryptomator/windows/keychain/WindowsHello.java (2)
src/main/java/org/cryptomator/windows/common/WinStrings.java (1)
  • WinStrings (6-14)
src/main/java/org/cryptomator/windows/keychain/WinDataProtection.java (1)
  • Native (23-33)
🔇 Additional comments (1)
src/main/java/org/cryptomator/windows/keychain/WindowsHello.java (1)

6-48: Implementation aligns well with PR objectives for secure caching

The changes to use a fixed challenge instead of dynamic ones effectively support the goal of caching Windows Hello authentication results to reduce the number of prompts. This improves usability while maintaining security through secure memory protection.

For future maintenance, consider documenting the purpose of the implementation pattern and potentially refactoring the method signatures to remove unused parameters if backward compatibility becomes less of a concern.

@infeo infeo added this to the next milestone May 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants