-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Implement ECC APIs on Android using Android-built-in Crypto APIs #48348
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
Conversation
…ly implemented CryptoNative_EcKeyCreateByExplicitParameters.
…handling still todo.
|
Tagging subscribers to this area: @bartonjs, @vcsjones, @krwq, @GrabYourPitchforks Issue DetailsImplement the ECC key management, import/export, and ECDSA APIs using the Java-based Crypto APIs available on Android. cc: @bartonjs
|
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_evp_cipher.c
Outdated
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.h
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.h
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecdsa.h
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecdsa.c
Outdated
Show resolved
Hide resolved
| jstring algorithmName = JSTRING("SHA1withECDSA"); | ||
| jobject signatureObject = (*env)->CallStaticObjectMethod(env, g_SignatureClass, g_SignatureGetInstance, algorithmName); | ||
| (*env)->DeleteLocalRef(algorithmName); | ||
| if (CheckJNIExceptions()) return NULL; |
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.
Are we not printing the exception here? Does this indicate a sort of catastrophic failure?
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.
The CheckJNIExceptions() method prints out the exceptions to the Android logs.
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.
Okay. So NULL is okay here then, but we immediately return in all places where NULL is returned but don't record in that scenario. It seems to me that this code should be as boiler plate as possible and this function handles errors but does the caller so I am just trying to understand how reconciles ownership of when to report and when not to. Also, I think we can pass in env right?
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.
I like having the CheckJNIExceptions() call as close to the throwing Java method call as possible for clarity. Since this method calls the Java Signature.getInstance method, it checks if it threw an exception.
The callers of this method don't need to check if it threw an exception since we already checked that.
I think a good way to encapsulate the model for JNI exception checking in the PAL is, "a JNI exception will never be left pending across a PAL function return." Or at least that's my mental model of it.
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.
I think what I'm getting at is this function seems like 3 lines in 2 places and can be removed entirely. Just my opinion. Up to you.
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.
Yeah that's true. I'll think about removing it. We might want something similar for RSA signing, so I might generalize it for that.
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.c
Outdated
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.h
Show resolved
Hide resolved
| jobject* qy, int32_t* cbQy, | ||
| jobject* d, int32_t* cbD) | ||
| { | ||
| assert(qx != NULL); |
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 is the logic to assert here as opposed to return an error code? In other functions it seems we do a hard check instead of simply asserting? Perhaps this is an internal function? I would recommend we be consistent here.
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.
We guard in the error case for d but not here?
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.
I guess the asserts are copied from OpenSSL's CryptoNative_GetECKeyParameters
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.
The shims are considered 100% as internal functions. We're inconsistent of asserting vs error checking (largely, IIRC, error checking was first, when we had the possibility of torn state of the native shim package and the caller package... now that we have shared frameworks some of the newer things assert)
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.
The shims are considered 100% as internal functions.
now that we have shared frameworks some of the newer things assert
W00t. If these functions are internal only I would prefer to limit this sort of validation to asserts only. My assumption is we will always call these functions correctly and find incorrect internal usage with testing.
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.
I've noticed that a lot of places in the crypto tests push the validation down to the shim/native library, so we can't use asserts for those ones since they'll take down the process.
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 all comes back to the current "time-saving" effort of reusing the OpenSSL-based implementations. The tests (generally) don't care where things fail, just that CryptographicException-derived exceptions happen. If you make ECDsaAndroid and it does more work in managed code you can do more asserting and less runtime error checking.
If there are tests that care about specifics for the exceptions I believe those should only care about using the concrete public ECDsaOpenSsl type, which should NOT work on Android since it can't speak pointers in an actually interoperable way (and the pointer interop is the only reason the type is public).
| const EC_KEY* key, | ||
| int32_t includePrivate, | ||
| ECCurveType* curveType, | ||
| jobject* qx, int32_t* cbQx, |
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.
Might it make sense to create a blittable in/out value type for these large pointer sets? I assume all these functions are for internal usage and not external consumption.
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.
My answer to this, and everything else in the shim API, is "do whatever makes sense for this interop". Just make a new ECDsaAndroid/ECDiffieHellmanAndroid as internal types in System.Security.Cryptography.Algorithms and own the interop for them entirely. There's no reason to stay aligned with the OpenSSL shim API... especially since I've already started the process of rewriting that one 😄.
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c
Outdated
Show resolved
Hide resolved
|
My two cents (unrelated to this PR)
|
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c
Outdated
Show resolved
Hide resolved
I don't think that is an option here - at least I was under the impression we were required to use pure C.
I think we can consider that pattern if we are keeping with C. However, if we are going with C++ that sort of macro magic should be avoided as it can't be debugged and modern C++ has mechanisms to avoid those patterns. |
AFAIK, System.Native.* libs were initially C++ in corefx but then were rewritten to C to be: 1) Mono-friendly (Mono used to be C-only and couldn't consume/build C++ files) 2) to save some space (not much) by dropping stdlib. |
Yep. That is what I was alluding to. Does Mono now permit C++ in their scenarios? |
Well, this lib is a standalone dynamic lib so it doesn't matter at all - cmake will just build a |
I am fine with that if it is okay. We will have to make sure the target platforms provide the C++ runtime and ensure no exceptions cross the binary boundary but other than those two considerations I am all for it. |
|
There were some other reasons for the C++ > C conversion. Maybe @am11 will remember them? It may not matter in this case if it's specific to Android platform. |
|
@filipnavara @am11 @VSadov Was the decision based on the Single File + self-contained work? |
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecdsa.c
Outdated
Show resolved
Hide resolved
...ries/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.EcKey.cs
Outdated
Show resolved
Hide resolved
src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.Dsa.cs
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c
Outdated
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_ecc_import_export.c
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.c
Outdated
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.c
Outdated
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.c
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_jni.h
Outdated
Show resolved
Hide resolved
....Security.Cryptography.Algorithms/src/System/Security/Cryptography/ECAndroid.ImportExport.cs
Outdated
Show resolved
Hide resolved
...ty.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanAndroid.Derive.cs
Show resolved
Hide resolved
...ty.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanAndroid.Derive.cs
Outdated
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.c
Show resolved
Hide resolved
src/libraries/Native/Unix/System.Security.Cryptography.Native.Android/pal_eckey.c
Show resolved
Hide resolved
...ty.Cryptography.Algorithms/src/System/Security/Cryptography/ECDiffieHellmanAndroid.Derive.cs
Outdated
Show resolved
Hide resolved
bartonjs
left a comment
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.
Two outstanding bits of housekeeping:
- Use BitsToBytes instead of repeating the formula in managed code
- After verifying how leading zeros work, either assert or handle the case where bytesWritten in ECDH isn't the expected value.
...n/tests/System/Security/Cryptography/AlgorithmImplementations/ECDsa/ECDsaTests.netcoreapp.cs
Outdated
Show resolved
Hide resolved
|
Hello @jkoritzinsky! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
|
Merging in as this PR has no effect on iOS or the standard Android build with OpenSSL. |
Implement the ECC key management, import/export, ECDSA, and ECDH APIs using the Java-based Crypto APIs available on Android.
cc: @bartonjs