2017-02-16 19 views
0

外部から取得したAndroidアプリケーションでハッシュ値に署名しようとすると、上記の例外が発生します。android.security.KeyStoreException:RSAで署名するときに互換性のないダイジェスト

鍵ペアを生成するためのコードは次のとおりです。

public static byte[] signHash(byte[] hashToSign) { 
     try { 
      KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE); 
      keyStore.load(null); 
      KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry(MY_KEY_ALIAS, null); 
      PrivateKey privateKey = keyEntry.getPrivateKey(); 

      DigestAlgorithmIdentifierFinder hashAlgorithmFinder = new DefaultDigestAlgorithmIdentifierFinder(); 
      AlgorithmIdentifier hashingAlgorithmIdentifier = hashAlgorithmFinder.find(KeyProperties.DIGEST_SHA256); 
      DigestInfo digestInfo = new DigestInfo(hashingAlgorithmIdentifier, hashToSign); 
      byte[] hashToEncrypt = digestInfo.getEncoded(); 
      Cipher cipher = Cipher.getInstance("RSA/ECB/Pkcs1Padding"); 
      cipher.init(Cipher.ENCRYPT_MODE, privateKey); // <= the exception is thrown here 
      return cipher.doFinal(hashToEncrypt); 
     } catch (Throwable e) { 
      Log.e("KeyStoreWrapper", "Error while signing: ", e); 
     } 
     return "Could not sign the message.".getBytes(StandardCharsets.UTF_16LE); 
    } 

私が手にエラーがある:

java.security.InvalidKeyException: Keystore operation failed 
at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1004) 
at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1024) 
at android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(KeyStoreCryptoOperationUtils.java:53) 
at android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:89) 
at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:263) 
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:108) 
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:612) 
at javax.crypto.Cipher.tryCombinations(Cipher.java:532) 
at javax.crypto.Cipher.getSpi(Cipher.java:437) 
at javax.crypto.Cipher.init(Cipher.java:815) 
at javax.crypto.Cipher.init(Cipher.java:774) 
at de.new_frontiers.m2fa.security.KeyStoreWrapper.signHash(KeyStoreWrapper.java:186) 
at de.new_frontiers.m2fa.bluetooth.BluetoothHandler.handleMessage(BluetoothHandler.java:93) 
at android.os.Handler.dispatchMessage(Handler.java:102) 
at android.os.Looper.loop(Looper.java:158) 
at android.app.ActivityThread.main(ActivityThread.java:7229) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120) 
Caused by: android.security.KeyStoreException: Incompatible digest 
at android.security.KeyStore.getKeyStoreException(KeyStore.java:944) 
at android.security.KeyStore.getInvalidKeyException(KeyStore.java:1024)  
at android.security.keystore.KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(KeyStoreCryptoOperationUtils.java:53)  
at android.security.keystore.KeyStoreCryptoOperationUtils.getExceptionForCipherInit(KeyStoreCryptoOperationUtils.java:89)  
at android.security.keystore.AndroidKeyStoreCipherSpiBase.ensureKeystoreOperationInitialized(AndroidKeyStoreCipherSpiBase.java:263)  
at android.security.keystore.AndroidKeyStoreCipherSpiBase.engineInit(AndroidKeyStoreCipherSpiBase.java:108)  
at javax.crypto.Cipher.tryTransformWithProvider(Cipher.java:612)  
at javax.crypto.Cipher.tryCombinations(Cipher.java:532)  
at javax.crypto.Cipher.getSpi(Cipher.java:437)  
at javax.crypto.Cipher.init(Cipher.java:815)  
at javax.crypto.Cipher.init(Cipher.java:774)  
at com.mycompany.security.KeyStoreWrapper.signHash(KeyStoreWrapper.java:186)  

public static KeyPair generateKeyPair(Context context, String username) throws Exception { 
     KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_RSA, ANDROID_KEY_STORE); 
     Calendar start = Calendar.getInstance(); 
     Calendar end = Calendar.getInstance(); 
     end.add(Calendar.YEAR, 1); 
     AlgorithmParameterSpec parameterSpec; 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      parameterSpec = new KeyGenParameterSpec.Builder(MY_KEY_ALIAS, KeyProperties.PURPOSE_SIGN) 
        .setKeySize(KEY_SIZE) 
        .setCertificateSubject(usernameToSubject(username)) 
        .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA1) 
        .setCertificateNotBefore(start.getTime()) 
        .setCertificateNotAfter(end.getTime()) 
        .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) 
        .build(); 
     } else { 
      // Here I build the keys for older versions. This is not part of my problem 
     } 
     keyPairGenerator.initialize(parameterSpec); 
     return keyPairGenerator.generateKeyPair(); 
    } 

後、私に私が外部から取得ハッシュに署名android documentationで私は参照してください:

署名と検証操作では、beginのadditional_params引数の にダイジェストを指定する必要があります。指定されたダイジェストがキーに関連付けられたダイジェストに含まれていない である場合、操作はKM_ERROR_INCOMPATIBLE_DIGESTで に失敗する必要があります。

私はKeyProperties.DIGEST_SHA256で鍵ペアを作成し、DigestInfoを同じアルゴリズムに設定します。だから、なぜ私はエラー "互換性のないダイジェスト"を取得するのか分からない。誰かがこれについていくつかの光を当てることができますか?

なぜ、私がSignature.sign()を使用しないのか不思議に思っている人のために、これは署名のために平文が必要になり、ハッシュ、DigestInfoを作成してそれを秘密鍵で暗号化します。私はすでに外部からハッシュを取得しており、これは変更できないものです。

答えて

0

pedrofbs答え、私は最終的に物事が権利を取得するのに役立ちました。私はすでにキーの目的を、彼の答えに記載されている値に変更しました:KeyProperties.PURPOSE_SIGN|KeyProperties.PURPOSE_ENCRYPT|Key‌​Properties.PURPOSE_D‌​ECRYPTしかし、.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1)に電話するのを忘れました。だから、これを見つけ出すために、pedrofsに感謝します!

残念ながら、まだ動作しませんでした。キーの設定を変えてみると、私はパスワード、ピンなどでテストするためのデバイスを保護していないことに気付きました。だから、.setUserAuthenticationRequired(false)をKeyGenParameterSpecに追加することはそのトリックを行いました。私はこれが安全ではなく、変更されなければならないことを知っていますが、現時点では私はただの概念証明しかしていません。 :-)この問題の際にケースの他の誰かつまずくで

:ここでは、鍵生成のための全体の作業コードです:| KeyProperties.PURPOSE_ENCRYPT |

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { 
      parameterSpec = new KeyGenParameterSpec.Builder(LOGON_KEY_ALIAS, KeyProperties.PURPOSE_SIGN|KeyProperties.PURPOSE_ENCRYPT|KeyProperties.PURPOSE_DECRYPT) 
        .setKeySize(KEY_SIZE) 
        .setUserAuthenticationRequired(false) 
        .setCertificateSubject(usernameToSubject(username)) 
        .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA1)//, KeyProperties.DIGEST_NONE, KeyProperties.DIGEST_SHA224, KeyProperties.DIGEST_SHA384, KeyProperties.DIGEST_SHA512, KeyProperties.DIGEST_MD5) 
        .setCertificateNotBefore(start.getTime()) 
        .setCertificateNotAfter(end.getTime()) 
        .setSignaturePaddings(KeyProperties.SIGNATURE_PADDING_RSA_PKCS1) 
        .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) 
        .build(); 
     } 
2

RSA/ECB/PKCS1Paddingを使用した秘密鍵による暗号化はAndroid 18のAndroidKeyStoreで利用できるため、受信したハッシュで有効なデジタル署名を実行できるはずです。

私は、キーの使用方法を暗号化ではなく署名に設定していると思います。これを試してみてください:

parameterSpec = new KeyGenParameterSpec.Builder(MY_KEY_ALIAS, KeyProperties.PURPOSE_ENCRYPT | | KeyProperties.PURPOSE_DECRYPT) 
       .setKeySize(KEY_SIZE) 
       .setCertificateSubject(usernameToSubject(username)) 
       .setDigests(KeyProperties.DIGEST_SHA256, KeyProperties.DIGEST_SHA1) 
       .setCertificateNotBefore(start.getTime()) 
       .setCertificateNotAfter(end.getTime()) 
       .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1) 
       .build(); 

hashToSignが本当にSHA-256であることも確認し(32バイト)

+0

私は 'KeyProperties.PURPOSE_SIGNするKeyGenParameterSpecの目的を変更しましたKeyProperties。PURPOSE_DECRYPT'とEncrpytionPaddingsを追加しましたが、それでも動作しません。暗号は、暗号化するハッシュ(32バイト)について何も知らない場合、cipher.init()で例外がスローされます。 – Frank

関連する問題