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:
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.verify_pin(pin: String) -> Result<bool, String>: Verifies if the provided PIN matches the stored PIN. ReturnsOk(true)if the PIN is correct, andOk(false)if incorrect. ReturnsErr(String)if the PIN is invalid (doesn't meet complexity requirements).change_pin(old_pin: String, new_pin: String) -> Result<bool, String>: Changes the existing PIN to a new PIN. It first verifies theold_pinand then sets thenew_pinif the verification is successful. ReturnsOk(true)on successful change,Ok(false)if the old PIN is incorrect, andErr(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
PinManagermust be thread-safe, meaning multiple threads can safely call its methods concurrently. UseMutexor 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
sha2crate for hashing. - Performance: Verification should be reasonably fast. Avoid unnecessary computations.
Notes
- Consider using the
sha2crate for hashing. Add it to yourCargo.toml:sha2 = "0.10" - Think about how to handle potential errors during hashing.
- The
Resulttype 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
PinManagershould be initialized withPinManager::new(). - The PIN is a
Stringto allow for alphanumeric PINs.