-
Notifications
You must be signed in to change notification settings - Fork 9
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
Multiplatform - Native #162
Conversation
ea7f8e8
to
6b7090c
Compare
6b7090c
to
fd6021f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the effort that went into creating this PR. The changes are clear, and it is nice to have various native targets. I appreciate the care that went into generating secure random data in platform-specific ways.
I've looked at this from the general Kotlin/Gradle code review, clarity, maintainability, etc. perspective, and there are some questions inline. Another member of our team will be looking at this from a security perspective, and will chime in over the next week or so.
From my perspective, the main thing that we need to figure out is how we can reduce any third party dependency (e.g. Okio). It's great that we don't introduce dependencies in the Android targets, and I hope we can build on that.
I added a followup issue for CI jobs for other platforms, as I see that as complementary but out of scope for this initial PR. Relatedly, we may want to explicitly disable native release publishing until we get the CI jobs properly set up (we'll leave the publishing on for snapshots). That would mean adding
ORG_GRADLE_PROJECT_NATIVE_ENABLED: false
here.
bU[s.size + j] = (i shr (24 - 8 * j)).toByte() | ||
} | ||
|
||
val uXor = bU.toByteString().hmacSha512(key).toByteArray() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What options do we have for hmacSha512
that doesn't rely on Okio?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
import okio.ByteString.Companion.toByteString | ||
|
||
internal actual fun ByteArray.toSha256(): ByteArray = this.toByteString().sha256().toByteArray() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What options to we have to implement sha256
without Okio (or other third party dependencies)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
internal var cachedList = WordList() | ||
|
||
@Suppress("VARIABLE_IN_SINGLETON_WITHOUT_THREAD_LOCAL") | ||
var cachedList = WordList() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we make this a val
, which might help avoid the need for a @Suppress
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that would break the actual purpose of it being a var
:
var cachedList = WordList()
fun getCachedWords(languageCode: String): List<String> {
if (cachedList.languageCode != languageCode) {
cachedList = WordList(languageCode)
}
return cachedList.words
}
... I think I removed internal
by accident. I'll fix that. However it could also be made private
. It's not used anywhere else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
also the suppress isn't technically needed. But without it, it will print a bunch of info
level logs while building saying:
With old Native GC, variable in singleton without @ThreadLocal can't be changed after initialization
Which is just annoying considering kotlin uses the new GC by default now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks—reviewing just on GitHub hides some of the important context!
bip39-lib/src/nonJvmMain/kotlin/cash/z/ecc/android/crypto/PBEKeySpecCommon.kt
Outdated
Show resolved
Hide resolved
bip39-lib/src/nonJvmMain/kotlin/cash/z/ecc/android/crypto/PBEKeySpecCommon.kt
Outdated
Show resolved
Hide resolved
bip39-lib/src/nonJvmMain/kotlin/cash/z/ecc/android/crypto/Pbkdf2Sha512.kt
Outdated
Show resolved
Hide resolved
these are okios implementations. I guess they could be copied. I don't necessarily agree with the no dependencies rule you have, as java's standard library is pretty massive (essentially they already bundle things that would be a dependency in like any other language). Plus rolling your own crypto is something I avoid; I guess if you have the team to maintain it that works. But at that point honestly I would make a new library or module and import it into this project. That way other people can at least benefit from the code if you plan on maintaining it. If every project made everything self contained it would lead to tons of code duplication. I do get you want to keep it as concise as possible though. |
actual class SecureRandom { | ||
actual fun nextBytes(bytes: ByteArray) { | ||
val result = bytes.usePinned { | ||
@Suppress("UNCHECKED_CAST") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What errors occur if this @Suppress is removed? Are there consequences to making the value nullable instead of suppressing the unchecked cast?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
> Task :bip39-lib:compileKotlinMingwX64 FAILED
e: warnings found and -Werror specified
w: file:///Users/lucaspinazzola/Projects/kotlin-bip39/bip39-lib/src/mingwMain/kotlin/cash/z/ecc/android/random/SecureRandom.kt:17:33 Unchecked cast: CPointer<ByteVar /* = ByteVarOf<Byte> */> to CPointer<UByteVar /* = UByteVarOf<UByte> */>
Execution failed for task ':bip39-lib:compileKotlinMingwX64'.
> Compilation finished with errors
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's supposed to be a UByte not a Byte for mingw. The suppress isn't for null-ablity
update to gradle 8.0.1 and updates locks using procedure in `dependency.md`
results failing native tests
Turns out the native tests weren't running at all. Fixed that by adding and applying the kotest plugin. And that led me to find out there was an issue with the require statement in the native nextBytes implementation. Had to change the check: Also, I updated gradle to 8.0.1 |
I think I've fixed everything that needs to be fixed. Up to you guys on how you want to handle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for these enhancements. I have a few minor comments inline, and I'm about to trigger the CI build.
} | ||
return ByteArray(dkLenBytes).apply { | ||
baos.read(this) | ||
val dkLenBytes = dkLen / 8 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for rolling back use of Okio here. This minimizes the surface area of using third parties, and will make it easier to swap out Okio with something else in the future since its now just the hashing functions.
internal var cachedList = WordList() | ||
|
||
@Suppress("VARIABLE_IN_SINGLETON_WITHOUT_THREAD_LOCAL") | ||
var cachedList = WordList() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks—reviewing just on GitHub hides some of the important context!
found another option for the hashing: |
@luca992 Thanks for your patience. We are still having internal security auditing discussions, and we hope to wrap those up soon. As a preview, this where I think we will land:
No action items yet, just keeping you in the loop as we're making decisions internally. |
@luca992 Although it took a while, I got internal approval for the plan discussed above #162 (comment) Once we resolve the conflicts, then I can merge this PR 🎉 |
@ccjernigan I updated kotlin and all dependencies. If you don't want that lmk and I'll revert it |
We don't mind updating dependencies, although I would recommend a separate PR for the dependencies. When I merge this PR, it will be squashed into a single commit. For dependencies, Kotlin 1.8.21 is good to go, and we've updated our other repos as well. (We're sticking with Gradle 7.6 until we resolve an issue with the Rust integration in another project though). We still have merge conflicts with this PR—I think the WordList changes from the main branch need to be brought in which incorporates a significant performance improvement. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the effort that went into this PR, as well as your patience during our review process. This brings some great enhancements for the project and the ecosystem.
I created a new PR that incorporated these changes while resolving the remaining conflict. These changes have been merged. See #188 |
Np. Now I'll make that last pr for JS 👌 |
Added my native implementation targeting all tier 1-3 native targets.
Personally I don't agree with having a
NATIVE_TARGETS_ENABLED
toggle. But up to you.Not sure why detekt fails for
Pbkdf2Sha512
in thenonJvmMain
due toPbkdf2Sha512.F
:But succeeds in
commonMain
. I renamed both toPbkdf2Sha512.f
for consistencyEdit:
linuxArm64
target wasn't added due to okio not supporting it.