2016-08-22 10 views
10

मेरे पास एंड्रॉइड कीस्टोर में एक एन्क्रिप्टेड पासवर्ड संग्रहीत है।उपयोगकर्ता नाम नहीं प्रमाणीकृत FingerprintManager.authenticate के दौरान अपवाद()

मैं फिंगरप्रिंट एपीआई का उपयोग कर उपयोगकर्ता को प्रमाणीकृत करके उस पासवर्ड को डिक्रिप्ट करना चाहता हूं।

जहां तक ​​मैं समझता हूं, मुझे FingerprintManager.authenticate(CryptoObject cryptoObject) विधि को फिंगरप्रिंट परिणाम सुनने के लिए कॉल करना होगा। CryptoObject पैरामीटर ऐसा बनाया जाता है:

public static Cipher getDecryptionCipher(Context context) throws KeyStoreException { 
    try { 
     Cipher cipher = Cipher.getInstance(TRANSFORMATION); 
     SecretKey secretKey = getKeyFromKeyStore(); 
     final IvParameterSpec ivParameterSpec = getIvParameterSpec(context); 

     cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec); 
     return cipher; 

    } catch (NoSuchAlgorithmException | NoSuchPaddingException | IOException | UnrecoverableKeyException | CertificateException | InvalidAlgorithmParameterException | InvalidKeyException e) { 
     e.printStackTrace(); 

    } 

    return null; 
} 

Cipher cipher = FingerprintCryptoHelper.getDecryptionCipher(getContext()); 
FingerprintManager.CryptoObject cryptoObject = new FingerprintManager.CryptoObject(cipher); 
fingerprintManager.authenticate(cryptoObject, ...); 

विधि getDecryptionCipher()cipher.init() कॉल जब तक सही ढंग से काम करता है। इस कॉल पर मुझे UserNotAuthenticatedException मिलता है, क्योंकि उपयोगकर्ता इस गुप्तकी के लिए प्रमाणित नहीं है। जो किसी भी तरह से समझ में आता है। लेकिन यह एक पाश, असंभव को पूरा करने के लिए है:

  • उपयोगकर्ता को प्रमाणित करने के लिए, मैं उसकी/उसके फिंगरप्रिंट का उपयोग करने के
  • उसकी/उसके फिंगरप्रिंट के लिए सुनने के लिए चाहते हैं, तो मैं init करने की जरूरत है सिफर, जो बदले में एक प्रमाणीकृत उपयोगकर्ता की आवश्यकता है

क्या गलत है ??

संपादित करें:

मैं एमुलेटर (Nexus 4, एपीआई 23) के साथ काम करते हैं।

यहां कोड है जिसका उपयोग मैं कुंजी बनाने के लिए करता हूं।

private SecretKey createKey() { 
    try { 
     KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, ANDROID_KEY_STORE); 
     keyGenerator.init(new KeyGenParameterSpec.Builder(
       KEY_NAME, 
       KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT 
     ) 
       .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 
       .setUserAuthenticationRequired(true) 
       .setUserAuthenticationValidityDurationSeconds(AUTHENTICATION_DURATION_SECONDS) 
       .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) 
       .build()); 
     return keyGenerator.generateKey(); 
    } catch (NoSuchAlgorithmException | NoSuchProviderException | InvalidAlgorithmParameterException e) { 
     throw new RuntimeException("Failed to create a symmetric key", e); 
    } 
} 
+0

कौन-सा उपकरण आप इस पर परीक्षण कर रहे हैं? आपने कुंजी कैसे उत्पन्न की? – Michael

+0

और आपने एमुलेटर में कम से कम एक फिंगरप्रिंट नामांकित किया है? – Michael

+0

@ माइकल यह कुछ सैमसंग और एक एचटीसी वन मिनी पर नेक्सस उपकरणों से लेकर विभिन्न उपकरणों पर परीक्षण किया गया है। और हाँ, मैंने इसे एम्यूलेटर पर भी परीक्षण किया। – muetzenflo

उत्तर

1

यह पता चला कि समस्या KeyGenParameterSpec जो प्रमाणीकरण के बिना सार्वजनिक कुंजी का उपयोग (जो वास्तव में क्या सार्वजनिक कुंजी की आवश्यकता नहीं होती है) को रोकता है साथ एक ज्ञात समस्या से संबंधित था।

इससे संबंधित एक प्रश्न/उत्तर यहां पाया जा सकता: Android Fingerprint API Encryption and Decryption

वैकल्पिक हल मूल रूप से बनाया कुंजी से एक PublicKey बना सकते हैं और सिफर init को यह अप्रतिबंधित PublicKey उपयोग करने के लिए है। तो मेरा अंतिम सिफर एईएस/सीबीसी/PKCS7Padding उपयोग करता है और इस विधि से आरंभ नहीं हो जाता:

public boolean initCipher(int opMode) { 
    try { 
     Key key = mKeyStore.getKey(KEY_NAME, null); 

     if (opMode == Cipher.ENCRYPT_MODE) { 
      final byte[] encoded = key.getEncoded(); 
      final String algorithm = key.getAlgorithm(); 
      final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded); 
      PublicKey unrestricted = KeyFactory.getInstance(algorithm).generatePublic(keySpec); 

      mCipher.init(opMode, unrestricted); 

     } else { 
      final IvParameterSpec ivParameterSpec = getIvParameterSpec(); 
      mCipher.init(opMode, key, ivParameterSpec); 

     } 

     return true; 

    } catch (KeyPermanentlyInvalidatedException exception) { 
     return false; 

    } catch (NoSuchAlgorithmException | InvalidKeyException 
      | InvalidKeySpecException | InvalidAlgorithmParameterException | UnrecoverableKeyException | KeyStoreException exception) { 
     throw new RuntimeException("Failed to initialize Cipher or Key: ", exception); 
    } 
} 

@NonNull 
public IvParameterSpec getIvParameterSpec() { 
    // the IV is stored in the Preferences after encoding. 
    String base64EncryptionIv = PreferenceHelper.getEncryptionIv(mContext); 
    byte[] encryptionIv = Base64.decode(base64EncryptionIv, Base64.DEFAULT); 
    return new IvParameterSpec(encryptionIv); 
} 
+1

यह असली काम कर रहा है? आप एईएस का उपयोग करते हैं और यह एक सार्वजनिक कुंजी के बिना एक सममित एल्गोरिदम है। एईएस कुंजी से सार्वजनिक कुंजी उत्पन्न करना कैसे संभव है? – UKoehler

+0

यह निश्चित रूप से काम करता है, लेकिन मैं वास्तव में क्यों समझा नहीं सकता। जैसा कि आपने उल्लेख किया था, वही विचार मेरे पास थे, लेकिन यह एकमात्र तरीका है जिसे मैंने "इरादे से" शब्द में प्राप्त किया। कृपया इस दृष्टिकोण को बेहतर बनाने के लिए स्वतंत्र महसूस करें! – muetzenflo

+0

मुझे नहीं लगता कि यह संभवतः एईएस कुंजी के साथ कैसे काम कर सकता है। सबसे पहले, एक अच्छा मौका है कि टीईई के बाहर ऐसी महत्वपूर्ण सामग्री का खुलासा होने से बचने के लिए 'getEncoded'' SecretKey'/'PrivateKey' के लिए 'शून्य' वापस कर देगा। यहां तक ​​कि यदि यहां मामला नहीं है, तो 'KeyFactory.getInstance' एईएस के लिए असफल होना चाहिए क्योंकि यह केवल डीएच, डीएसए, ईसी, आरएसए, और एक्स.50 9 का समर्थन करता है। मुझे लगता है कि आप वास्तव में यहां कुछ अन्य कुंजी का उपयोग कर रहे हैं। – Michael

संबंधित मुद्दे