Coder Social home page Coder Social logo

redmadrobot / pinkman Goto Github PK

View Code? Open in Web Editor NEW
85.0 5.0 11.0 461 KB

PINkman is a library to help implementing an authentication by a PIN code in a secure manner. The library derives hash from the user's PIN using Argon2 function and stores it in an encrypted file. The file is encrypted with the AES-256 algorithm in the GCM mode and keys are stored in the AndroidKeystore.

License: MIT License

Kotlin 100.00%
android-security kotlin kotlin-android kotlin-library authentication android-library argon2 user-pin

pinkman's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

pinkman's Issues

Call Pinkman on computation thread

Operations createPin, changePin, isValidPin, etc may take some time.
I think these operations shouldn't be run on the main thread. A developer can manage which thread to use himself but it would be great to have Rx wrapper around Pinkman or something like.

Avoid resource naming conflicts

Better to add a namespace prefix to library resources. In this case, it will be something like pinkman_darkGray.
A developer can define the resource with the same name in his app and get pin view changed unexpectedly. Prefix avoids such cases.

<color name="red">#f44336</color>
<color name="darkGrey">#A9A9A9</color>

The same here. Better to add a prefix. For example <style name="Pinkman.DefaultKeyboard" parent="">

<style name="DefaultKeyboard">

The same for the drawables.
circle_red -> pinkman_circle_red
circle_grey -> pinkman_circle_grey

Crash on android 12

Fatal Exception: java.security.ProviderException: Keystore key generation failed
       at android.security.keystore2.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:413)
       at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
       at androidx.security.crypto.MasterKeys.generateKey(MasterKeys.java:130)
       at androidx.security.crypto.MasterKeys.getOrCreate(MasterKeys.java:88)
       at com.redmadrobot.pinkman.Pinkman$encryptedStorage$2.invoke(Pinkman.kt:52)
       at com.redmadrobot.pinkman.Pinkman$encryptedStorage$2.invoke(Pinkman.kt:22)
       at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
       at com.redmadrobot.pinkman.Pinkman.getEncryptedStorage(:2)
       at com.redmadrobot.pinkman.Pinkman.createPin(Pinkman.kt:67)
       at com.redmadrobot.pinkman.Pinkman.createPin$default(Pinkman.kt:58)
       at *****.invokeSuspend(*****)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
       at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
       at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
       at kotlinx.coroutines.android.HandlerContext$scheduleResumeAfterDelay$$inlined$Runnable$1.run(Runnable.kt:19)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:201)
       at android.os.Looper.loop(Looper.java:288)
       at android.app.ActivityThread.main(ActivityThread.java:7842)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
Caused by android.security.KeyStoreException: System error
       at android.security.KeyStore2.getKeyStoreException(KeyStore2.java:334)
       at android.security.KeyStoreSecurityLevel.handleExceptions(KeyStoreSecurityLevel.java:57)
       at android.security.KeyStoreSecurityLevel.generateKey(KeyStoreSecurityLevel.java:145)
       at android.security.keystore2.AndroidKeyStoreKeyGeneratorSpi.engineGenerateKey(AndroidKeyStoreKeyGeneratorSpi.java:400)
       at javax.crypto.KeyGenerator.generateKey(KeyGenerator.java:612)
       at androidx.security.crypto.MasterKeys.generateKey(MasterKeys.java:130)
       at androidx.security.crypto.MasterKeys.getOrCreate(MasterKeys.java:88)
       at com.redmadrobot.pinkman.Pinkman$encryptedStorage$2.invoke(Pinkman.kt:52)
       at com.redmadrobot.pinkman.Pinkman$encryptedStorage$2.invoke(Pinkman.kt:22)
       at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
       at com.redmadrobot.pinkman.Pinkman.getEncryptedStorage(:2)
       at com.redmadrobot.pinkman.Pinkman.createPin(Pinkman.kt:67)
       at com.redmadrobot.pinkman.Pinkman.createPin$default(Pinkman.kt:58)
       at *****.invokeSuspend(*****)
       at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
       at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:234)
       at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:166)
       at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:397)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:431)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:420)
       at kotlinx.coroutines.CancellableContinuationImpl.resumeUndispatched(CancellableContinuationImpl.kt:518)
       at kotlinx.coroutines.android.HandlerContext$scheduleResumeAfterDelay$$inlined$Runnable$1.run(Runnable.kt:19)
       at android.os.Handler.handleCallback(Handler.java:938)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:201)
       at android.os.Looper.loop(Looper.java:288)
       at android.app.ActivityThread.main(ActivityThread.java:7842)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

Reproducing stable on android 12 (sdk 32), tested on real device and emulator. Right now workarounded it like this:

diff --git a/pinkman/src/main/java/com/redmadrobot/pinkman/Pinkman.kt b/pinkman/src/main/java/com/redmadrobot/pinkman/Pinkman.kt
index 4c12aaa..ebc5d17 100644
--- a/pinkman/src/main/java/com/redmadrobot/pinkman/Pinkman.kt
+++ b/pinkman/src/main/java/com/redmadrobot/pinkman/Pinkman.kt
@@ -34,7 +34,7 @@ class Pinkman(
             .setEncryptionPaddings(ENCRYPTION_PADDING_NONE)
             .setKeySize(KEY_SIZE)
             .apply {
-                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
+                if (Build.VERSION.SDK_INT in Build.VERSION_CODES.P..Build.VERSION_CODES.S) {
                     setUnlockedDeviceRequired(true)
 
                     val hasStrongBox = applicationContext

PinkMan doesn't work if you remove lock screen

#24 - it is only half-fix @Zestxx

I suggest you always put setUnlockedDeviceRequired(false) instead of setUnlockedDeviceRequired(isDeviceSecure)

Why:

Steps for android 12

  1. set android lock screen
  2. install pinkman demo app (i used fork of this repo)
  3. create pin in pinkman
  4. remove android lock screen
  5. launch pinkman demo app

Expected result - all works
Actual result - crash

It happens, because you generate key on locked device, This key becomes irrevocably lost, if user removes android lock screen.
Generated key also may become irrevocably lost, if user for example change android lock screen type from PIN to Graphical key. Or may be, if user just changes PIN's digits.

Paranoid mode

Add an ability to set a blacklist of PIN codes to avoid potentially insecure combinations like "0000", "1234", etc.

Add module with biometrics

It would be great to be able to enable biometric authentication "with one line of code".
I have not thought about the API yet.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.