Skip to content

Use secure_string for more secure Password and SecretKey#328

Open
eibrahim95 wants to merge 21 commits into
cot-rs:masterfrom
eibrahim95:secure-string
Open

Use secure_string for more secure Password and SecretKey#328
eibrahim95 wants to merge 21 commits into
cot-rs:masterfrom
eibrahim95:secure-string

Conversation

@eibrahim95

Copy link
Copy Markdown
Contributor

This implements #47

  • Updated cot::common_types::Password struct to use SecureString for enhanced security.
  • Implemented PartialEq and Eq for cot::common_types::Password to be able to compare 2 Password instances
  • Added tests for equality comparison of instances.
  • Updated SecretKey struct to use SecureBytes for improved security handling.
  • Adjusted implementations of PartialEq and Debug to align with SecureBytes.
  • Implemented serialization for SecretKey since we cannot derive Serialize because SecureBytes doesn't implement it .
  • Included tests for JSON serialization of SecretKey.

- Updated  struct to use SecureString for enhanced security.
- Implemented PartialEq and Eq to be able to compare 2 Password instances
- Added tests for equality comparison of  instances.
…curity

- Updated SecretKey struct to use SecureBytes for improved security handling.
- Adjusted implementations of PartialEq and Debug to align with SecureBytes.
- Implemented serialization for SecretKey since we cannot derive Serialize since SecureBytes doesn't implement it .
- Included tests for JSON serialization of SecretKey.
@github-actions github-actions Bot added the C-lib Crate: cot (main library crate) label May 15, 2025
@codecov

codecov Bot commented May 15, 2025

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.44444% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
cot/src/config.rs 89.47% 2 Missing ⚠️
Flag Coverage Δ
rust 90.25% <94.44%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
cot/src/common_types.rs 84.67% <100.00%> (+0.58%) ⬆️
cot/src/config.rs 94.58% <89.47%> (+0.05%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@eibrahim95

Copy link
Copy Markdown
Contributor Author

Looks like miri doesn't support mlock, thinking about mocking it for miri only what do you think @m4tx @seqre ?

@seqre seqre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

@m4tx can you look at my comments, I'd like a second pair of eyes.

Comment thread cot/src/common_types.rs Outdated
Comment thread cot/src/config.rs Outdated
@eibrahim95

Copy link
Copy Markdown
Contributor Author

@seqre What do you think about the miri thing, because that is a blocker for this PR?

@m4tx

m4tx commented May 27, 2025

Copy link
Copy Markdown
Member

Looks like miri doesn't support mlock, thinking about mocking it for miri only what do you think @m4tx @seqre ?

Hey, thanks for your patience! Can you share more details on mocking a syscall for Miri? I didn't know it was possible.

Otherwise, I think the only option is to ignore all the failing tests. Which would be kind of a sad thing to do, given how many there are.

- Refactored Password and SecretKey structs to provide Miri-compatible versions, using String and Box<[u8]> respectively.
- Adjusted methods for creating and accessing passwords and secret keys to ensure compatibility with Miri's limitations.
@eibrahim95

Copy link
Copy Markdown
Contributor Author

Hey, thanks for your patience! Can you share more details on mocking a syscall for Miri? I didn't know it was possible.

I realize I didn't fully think through the mock idea - it's beyond my current skill level anyway.

Otherwise, I think the only option is to ignore all the failing tests. Which would be kind of a sad thing to do, given how many there are.

I kept a normal implementation for miri, all should be good now, please have a look.

@seqre

seqre commented May 31, 2025

Copy link
Copy Markdown
Member

I'm not sure if creating a special implementation just for Miri is the best approach. It forces us to maintain twice as much code. However, getting rid of it would force us to ignore a lot of only partially related tests from Miri testing, which is also not a good end result. I think that for now, we can leave that implementation be, and we can always reassess the situation in the future if it becomes a hassle. Would you agree @m4tx?

@eibrahim95, on a side note, please add Unlicense to cargo-deny's allowed list of licenses to make the CI check pass

@eibrahim95 eibrahim95 requested review from m4tx and seqre May 31, 2025 12:26

@seqre seqre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

One last request from me and it should be good in my eyes!

Comment thread cot/src/common_types.rs Outdated
@eibrahim95 eibrahim95 requested a review from seqre June 1, 2025 11:54

@seqre seqre left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

Comment thread cot/src/common_types.rs Outdated
Comment thread Cargo.toml Outdated
@eibrahim95

Copy link
Copy Markdown
Contributor Author

Hey Guys, I'm seeing some activity here, although i totally forgot what we we were doing here :D but let me know if i can help.

Thanks

@seqre

seqre commented Mar 20, 2026

Copy link
Copy Markdown
Member

Hey @eibrahim95, it's nice to hear from you again! We're going back to all old PRs and trying to get them working and merge them. So far, I've only updated this PR to the newest changes on the master branch. In the background, I'm working on updating secure_string for our use case. Once that's done, we can use it to finish this PR and merge it!

@seqre seqre linked an issue Mar 23, 2026 that may be closed by this pull request
@github-actions github-actions Bot added the A-deps Area: Dependencies label May 22, 2026
@seqre

seqre commented May 22, 2026

Copy link
Copy Markdown
Member

Hey @eibrahim95, we finished working on https://github.com/cot-rs/securer-string, so I took the liberty of updating the PR's code to use it.

@eibrahim95, @m4tx, and @Kijewski I'd appreciate if you guys could take a peek and see if it's in good shape now!

@Kijewski

Kijewski commented May 22, 2026

Copy link
Copy Markdown
Contributor

That's nitpicking from me, feel free to ignore. :)

In https://github.com/cot-rs/securer-string/blob/1995c9dc687bd6fc24da8a1e0ba4ae5e51381e75/src/serde.rs#L38, I would not print the underlying error, because some deserializing library might print the password string or parts of it. It could be something simple as "string contains an unescaped apostrophe", which would weaken the user's security at least a tiny bit. Same with the other instances of {error}.

In https://github.com/cot-rs/securer-string/blob/1995c9dc687bd6fc24da8a1e0ba4ae5e51381e75/src/secure_utils.rs#L6, no error is reported to the caller, which is mostly okay I guess, but if the mlock failed, the munlock call must be skipped.

This does not look right to me: https://github.com/cot-rs/securer-string/blob/1995c9dc687bd6fc24da8a1e0ba4ae5e51381e75/src/secure_types/array.rs#L34-L35. The compiler is free to move content after the mlock call happened. Maybe drop the SecureArray type entirely?

The #[must_use] annotation is missing in https://github.com/cot-rs/securer-string/blob/1995c9dc687bd6fc24da8a1e0ba4ae5e51381e75/src/secure_types/string.rs#L22. The other methods are annotated.

If the password length is less than page sized (which is somewhat ensured, as macOS uses 16k pages if I'm not mistaken), and two passwords get allocated in the same page, then dropping one password will munlock the other password. Fixing this problem would be difficult, I think. Either allocate pages manually for every password or have some sort of arena that stores all passwords. I hate the latter option, though, because that arena would be treasure chest for any evil-doer .

@seqre

seqre commented May 25, 2026

Copy link
Copy Markdown
Member

Thanks @Kijewski, I appreciate your review a lot! I've made a PR with the first 4 fixes and left the last point as an issue in the repo to handle at some other time as it's a bit harder to tackle right away.

@m4tx m4tx left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

A couple minor things still, but with the securer-string almost in place, we should be able to merge this very soon!

Comment thread cot/src/common_types.rs
}
}

impl Debug for Password {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we still need/want this if SecureString hides the content in the debug impl anyway? Same for other types (such as SecretKey).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'd say yes, because then instead of Password(..) you'll get Password(SecureString { .. }) if you just do plain #[derive(Debug)].

Comment thread cot/src/config.rs
Comment thread .gitignore Outdated
Comment thread cot/src/common_types.rs Outdated
/// where the security tradeoff is understood, e.g., when you're creating a
/// user registration form with the "retype your password" field, where both
/// passwords come from the same source anyway.
/// 2. An alternative is to compare 2 instances of the [`Password`] type

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Now this sounds like option 2 and 1 are essentially the same. It feels like we should explain in more detail the differences between the two - e.g. the first calculates hashes of passwords and compares that, making it computationally expensive and very difficult to make any timing attacks, vs. just comparing the passwords with constant-time comparison which can still leak the length of the password. I don't know how to put this in words in a short way.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I've updated it, is it okay now?

@seqre seqre requested a review from m4tx June 22, 2026 22:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-deps Area: Dependencies C-lib Crate: cot (main library crate)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Consider using secure_string crate (or similar) for Password

5 participants