Hone logo
Hone
Problems

Secure PIN Management API in Rust

This challenge tasks you with implementing a simple PIN management API in Rust. The API should allow users to set a PIN, verify a PIN, and potentially change a PIN, all while ensuring security and preventing common vulnerabilities like brute-force attacks. This is a practical exercise in handling sensitive data and implementing secure authentication logic.

Problem Description

You are to implement a PinManager struct in Rust that provides the following functionalities:

  1. set_pin(pin: String): Sets a new PIN for the user. The PIN must meet certain complexity requirements (see Constraints). If a PIN is already set, it should be overwritten.
  2. verify_pin(pin: String) -> Result<bool, String>: Verifies if the provided PIN matches the stored PIN. Returns Ok(true) if the PIN is correct, and Ok(false) if incorrect. Returns Err(String) if the PIN is invalid (doesn't meet complexity requirements).
  3. change_pin(old_pin: String, new_pin: String) -> Result<bool, String>: Changes the existing PIN to a new PIN. It first verifies the old_pin and then sets the new_pin if the verification is successful. Returns Ok(true) on successful change, Ok(false) if the old PIN is incorrect, and Err(String) if either PIN is invalid.

The PinManager should be designed to be thread-safe.

Examples

Example 1:

Input:
PinManager::new().set_pin("1234".to_string());
let manager = PinManager::new();
manager.verify_pin("1234".to_string())
Output: Ok(true)
Explanation: The PIN "1234" was set, and the verification correctly identifies it.

Example 2:

Input:
let manager = PinManager::new();
manager.set_pin("abc1234".to_string());
manager.change_pin("abc1234".to_string(), "4321abc".to_string())
Output: Ok(true)
Explanation: The PIN is successfully changed from "abc1234" to "4321abc".

Example 3: (Edge Case - Invalid PIN)

Input:
let manager = PinManager::new();
manager.set_pin("123".to_string());
manager.verify_pin("1234".to_string())
Output: Err("PIN must be at least 4 characters long.")
Explanation: The provided PIN "1234" is invalid because the PIN was set to "123" which is too short.

Constraints

  • PIN Length: The PIN must be at least 4 characters long.
  • PIN Complexity: The PIN must contain at least one digit.
  • Error Handling: Invalid PINs (too short, no digits) should return a descriptive Err(String) message.
  • Thread Safety: The PinManager must be thread-safe, meaning multiple threads can safely call its methods concurrently. Use Mutex or similar synchronization primitives to protect the internal state.
  • No Storage: The PIN should not be stored in plain text. For simplicity, you can hash the PIN using a simple hashing algorithm (e.g., SHA-256) before storing it. You'll need to store the hash, not the PIN itself. Use the sha2 crate for hashing.
  • Performance: Verification should be reasonably fast. Avoid unnecessary computations.

Notes

  • Consider using the sha2 crate for hashing. Add it to your Cargo.toml: sha2 = "0.10"
  • Think about how to handle potential errors during hashing.
  • The Result type is crucial for error handling. Use it consistently to indicate success or failure.
  • Focus on clear, concise, and well-documented code.
  • Test your implementation thoroughly with various valid and invalid PINs, as well as concurrent access scenarios.
  • The PinManager should be initialized with PinManager::new().
  • The PIN is a String to allow for alphanumeric PINs.
Loading editor...
rust