1. è¨å®: é対称éµã®ãã¢ã®ä½æ
ã¾ã、次ã®ããã«é対称éµã®ãã¢ãä½æãã¾ã。
KeyPairGenerator . getInstance ( KeyProperties . KEY_ALGORITHM_EC , "AndroidKeyStore" );
keyPairGenerator . initialize (
new KeyGenParameterSpec . Builder ( KEY_NAME ,
KeyProperties . PURPOSE_SIGN )
. setDigests ( KeyProperties . DIGEST_SHA256 )
. setAlgorithmParameterSpec ( new ECGenParameterSpec ( "secp256r1" ))
. setUserAuthenticationRequired ( true )
. build ());
keyPairGenerator . generateKeyPair ();
.setUserAuthenticationRequired(true)
ã«æ³¨ç®ãã¦ãã ãã。ãã®ã¡ã½ãããå¼ã¶ãã¨ã«ãã、ç§å¯éµã使ç¨ããåã«、ç»é²ããæç´ã®èªè¨¼ãå¼·å¶ã§ããããã«ãªãã¾ã。
次ã«ä½æããç§å¯éµã¨å
¬ééµã以ä¸ã®ããã«åå¾ãã¾ã。
KeyStore keyStore = KeyStore . getInstance ( "AndroidKeyStore" );
keyStore . load ( null );
PublicKey publicKey =
keyStore . getCertificate ( MainActivity . KEY_NAME ). getPublicKey ();
KeyStore keyStore = KeyStore . getInstance ( "AndroidKeyStore" );
keyStore . load ( null );
PrivateKey key = ( PrivateKey ) keyStore . getKey ( KEY_NAME , null );
2. ç»é²: ãµã¼ãã¼ã¸ã®å
¬ééµã®ç»é²
次ã«、å
¬ééµãããã¯ã¨ã³ãã«éä¿¡ã、ãã®å¾ã®ã¦ã¼ã¶ã®è³¼å
¥ãã¦ã¼ã¶ã¼ã«ãã£ã¦æ¿èªããã¦ãããã¨(ãã®å
¬ééµã«å¯¾å¿ããç§å¯éµã«ãã£ã¦ç½²åããã¦ãããã¨)ãããã¯ã¨ã³ãã確èªããå¿
è¦ãããã¾ã。ãã®ãµã³ãã«ã§ã¯、å
¬ééµã®éä¿¡ã模æ¬çã«åç¾ããããã«ããã¯ã¨ã³ãå®è£
ã端æ«ä¸ã§åä½ãã模æ¬ã³ã¼ãã使ç¨ãã¦ãã¾ãã、å®éã«ã¯å
¬ééµããããã¯ã¼ã¯çµç±ã§éä¿¡ããå¿
è¦ãããã¾ã。
boolean enroll ( String userId , String password , PublicKey publicKey );
3. èªè¨¼: æç´ã«ããç½²åå¦ç
ååè³¼å
¥ãªã©ã§ã¦ã¼ã¶ã¼ãå¦çãèªè¨¼ã§ããããã«、æç´ã»ã³ãµã¼ã¸ã®ã¿ãããä¿ãããã³ããã表示ãã¾ã。
ç¶ãã¦、次ã®ããã«æç´ã®èªã¿è¾¼ã¿ãéå§ãã¾ã。
Signature . getInstance ( "SHA256withECDSA" );
KeyStore keyStore = KeyStore . getInstance ( "AndroidKeyStore" );
keyStore . load ( null );
PrivateKey key = ( PrivateKey ) keyStore . getKey ( KEY_NAME , null );
signature . initSign ( key );
CryptoObject cryptObject = new FingerprintManager . CryptoObject ( signature );
CancellationSignal cancellationSignal = new CancellationSignal ();
FingerprintManager fingerprintManager =
context . getSystemService ( FingerprintManager . class );
fingerprintManager . authenticate ( cryptoObject , cancellationSignal , 0 , this , null );
4. æçµå¦ç: ããã¯ã¨ã³ãã¸ã®ãã¼ã¿éä¿¡ã¨ç
§å
èªè¨¼ãæåããã、次ã®ããã«ç½²åæ¸ã¿ã®ãã¼ã¿(ãã®ãµã³ãã«ã§ã¯、è³¼å
¥å¦çã®å
容)ãããã¯ã¨ã³ãã«éä¿¡ãã¾ã。
Signature signature = cryptoObject . getSignature ();
// Include a client nonce in the transaction so that the nonce is also signed
// by the private key and the backend can verify that the same nonce can't be used
// to prevent replay attacks.
Transaction transaction = new Transaction ( "user" , 1 , new SecureRandom (). nextLong ());
try {
signature . update ( transaction . toByteArray ());
byte [] sigBytes = signature . sign ();
// Send the transaction and signedTransaction to the dummy backend
if ( mStoreBackend . verify ( transaction , sigBytes )) {
mActivity . onPurchased ( sigBytes );
dismiss ();
} else {
mActivity . onPurchaseFailed ();
dismiss ();
}
} catch ( SignatureException e ) {
throw new RuntimeException ( e );
}
æå¾ã«、ã¹ããã 2 ã§ç»é²ããå
¬ééµã使ç¨ã、ããã¯ã¨ã³ãã«ããç½²åæ¸ã¿ãã¼ã¿ã¨ç
§åãã¾ã。
@Override
public boolean verify ( Transaction transaction , byte [] transactionSignature ) {
try {
if ( mReceivedTransactions . contains ( transaction )) {
// It verifies the equality of the transaction including the client nonce
// So attackers can't do replay attacks.
return false ;
}
mReceivedTransactions . add ( transaction );
PublicKey publicKey = mPublicKeys . get ( transaction . getUserId ());
Signature verificationFunction = Signature . getInstance ( "SHA256withECDSA" );
verificationFunction . initVerify ( publicKey );
verificationFunction . update ( transaction . toByteArray ());
if ( verificationFunction . verify ( transactionSignature )) {
// Transaction is verified with the public key associated with the user
// Do some post purchase processing in the server
return true ;
}
} catch ( NoSuchAlgorithmException | InvalidKeyException | SignatureException e ) {
// In a real world, better to send some error message to the user
}
return false ;
}
ã¹ããã 1 ã§è¿°ã¹ãã¨ãã、ç§å¯éµã使ç¨ããåã«ã¦ã¼ã¶ã¼èªè¨¼ãæ¯åå¿
è¦ã§ãããã、ãã®æç¹ã§ã¦ã¼ã¶ã¼èªèº«ã®æç´ãæ£ããèªè¨¼ããã¦ããã¨ã¿ãªããã¨ãã§ãã¾ã。ããã¯ã¨ã³ãã§è³¼å
¥å¾ã®å¦çãå®è¡ã、ã¦ã¼ã¶ã¼ã«å¦çãæåãããã¨ãéç¥ãã¾ããã。
ãã®ä»ã®æ´æ°ããããµã³ãã«
ãã®ä»ã«、 Android for Work API ã«é¢é£ãã Marshmallow ã§æ´æ°ãããæ©è½ã«ã¤ãã¦ãµã³ãã«ãæ´æ°ãã¾ãã。
AppRestrictionEnforcer 㨠AppRestrictionSchema ã®ãµã³ãã«ã¯、Android 5.0 Lollipop ã® Android for Work API ã®ä¸é¨ã¨ã㦠ã¢ããªå¶éæ©è½ å°å
¥æã«ãªãªã¼ã¹ããã¾ãã。AppRestrictionEnforcer ã¯、ãããã¡ã¤ã« ãªã¼ãã¼ã¨ãã¦ä»ã®ã¢ããªã«å¶éãè¨å®ããæ¹æ³ã«ã¤ãã¦èª¬æãã¦ãã¾ã。AppRestrictionSchema ã¯、AppRestrictionEnforcer ã§å¶å¾¡ã§ããããã¤ãã®å¶éãå®ç¾©ãã¦ãã¾ã。ãã®æ´æ°ã¯、Android 6.0 ã§è¿½å å°å
¥ããã 2 ã¤ã®å¶éã¿ã¤ãã®ä½¿ç¨æ¹æ³ã«ã¤ãã¦èª¬æãã¦ãã¾ã。
æ´æ°ããããµã³ãã«ããããããã¼ã®çæ§ã®ãå½¹ã«ç«ã¦ãã°ã¨æãã¾ã。ãµã³ãã«ã«ã¤ãã¦ã®ã質åã¯、
GitHub ãã¼ã¸ 㧠Issue ãç»é²ããã、Pull Request ãéã£ã¦ããã ããããé¡ãè´ãã¾ã。
Posted by
Takeshi Hagikura - Developer Relations Team
[ãã®è¨äºã¯ Takeshi Hagikura、Yuichi Araki、ãããããã¼ ããã°ã©ã ã¨ã³ã¸ãã¢ã«ãã Android Developers Blog ã®è¨äº "New in Android Samples: Authenticating to remote servers using the Fingerprint API " ãå
ã«ç¿»è¨³・å çãããã®ã§ã。詳ããã¯å
è¨äºãã覧ãã ãã。]
以åã®ããã°æ稿 ã§çºè¡¨ãããããã«、Android 6.0 Marshmallow ãã¦ã¼ã¶ã¼åãã«ä¸è¬å
¬éããã¾ãã。ããã¾ã§ã、ãããããã¼ã使ç¨ã§ããæ°æ©è½ã主ãªå¯¾è±¡ã¨ãã¦、ãµã³ãã« ã®æ´æ°ãè¡ã£ã¦ãã¾ããã、å
æ¥ AsymmetricFingerprintDialog ã¨ããã¯ã©ã¤ã¢ã³ã / ãµã¼ãã¼ç°å¢ã§、æç´ãªã¼ãã¼(Nexus Imprint ãªã©)ãèªè¨¼ã«ä½¿ç¨ããæ¹æ³ã«ã¤ãã¦ç´¹ä»ããæ°ããªãµã³ãã«ããªãªã¼ã¹ãã¾ãã。
ãã®ãµã³ãã«ã®è©³ããä»çµã¿ã、Android M ãã¬ãã¥ã¼çºè¡¨æã«ãªãªã¼ã¹ãã FingerprintDialog ãµã³ãã«ã¨ã®éãã«ã¤ãã¦èª¬æãã¾ã。
対称éµã¨é対称éµ
Android Fingerprint API ã¯、æç´æ
å ±ã端æ«ä¸ã®ãã¼ãã¦ã§ã¢ã§ä¿è·ãããé åã«ä¿åã、ã¦ã¼ã¶ã¼ã®ãã©ã¤ãã·ã¼ãä¿è·ãã¾ã。ããã«ãã£ã¦å¤é¨ããã®æªè³ªãªæ»æãé²ã、ä¿¡é ¼æ§ã®ä½ãã¢ããªã±ã¼ã·ã§ã³ããã§ãèªã¿åããããã¨ããªãã®ã§ã¦ã¼ã¶ã¼ãå®å
¨ã«æç´èªè¨¼ãè¡ããã¨ãä¿è¨¼ã§ãã¾ã。
ã¾ãã¢ããªã±ã¼ã·ã§ã³ ãããããã¼åãã«Android ã®ä¿è·æ©è½ãæä¾ãã、æ©å¯æ§ã®é«ããã¼ã¿ããªã½ã¼ã¹ã«ã¢ã¯ã»ã¹ããåã«、ã¦ã¼ã¶ã¼ãç»é²ãããæç´ã®æã¡ä¸»ã§ãããã¨ãä¿è¨¼ã§ãã¾ã。ããã«ãã£ã¦ãªãã©ã¤ã³ ãã¼ã¿ã¨ãªã³ã©ã¤ã³éä¿¡ã®ä¸¡æ¹ã®ã»ãã¥ãªã㣠ãæå·åã¬ãã«ã§é«ãããã¨ãã§ã、ã¢ããªã±ã¼ã·ã§ã³ãæ¹ãããããã¨ãã¦ããã¼ã¿ããªã½ã¼ã¹ãä¿è·ã§ãã¾ã。
æç´ãªã¼ãæè¼ã®ç«¯æ«ã§ã¯æå·ã«ä½¿ç¨ãããéµã¯ãã¼ãã¦ã§ã¢ã§ä¿è·ãããé åã«ä¿åããã¾ã。æå·ã«ä½¿ç¨ãããéµã®ã¿ã¤ãã¯、ã¢ããªã±ã¼ã·ã§ã³ã®ç¨éã«å¿ãã¦ãããããã¼ãé¸æã§ãã¾ã。
対称éµ: ãã¹ã¯ã¼ãã®ããã«、ãã¼ã«ã« ãã¼ã¿ãæå·åã§ãã¾ã。 ãã®éµã¯、ãã¼ã¿ãã¼ã¹ããªãã©ã¤ã³ ãã¡ã¤ã«ã«å®å
¨ã«ã¢ã¯ã»ã¹ãããå ´åã«é©ãã¦ãã¾ã。
é対称éµ: å
¬ééµã¨ç§å¯éµãããªãéµã®ãã¢ã§ã。å
¬ééµã¯ã¤ã³ã¿ã¼ãããã§å®å
¨ã«éä¿¡ãã、ãªã¢ã¼ã ãµã¼ãã¼ã«ä¿åã§ãã¾ã。å
¬ééµã使ã£ã¦ç½²åèªè¨¼ãã§ããããã«、ç§å¯éµã¯å¾ãããã¼ã¿ç½²å ã«ä½¿ç¨ã§ãã¾ã。ç½²åæ¸ã¿ã®ãã¼ã¿ãæ¹ãããããã¨ã¯ã§ãã、ãã¼ã¿ä½æè
ãæ確ã«ç¹å®ã§ãã¾ã。ãã®ããã«、é対称éµã¯ãããã¯ã¼ã¯ã®ãã°ã¤ã³ããªã³ã©ã¤ã³å¦çã®èªè¨¼ã«ä½¿ç¨ã§ãã¾ã。åæ§ã«、ç§å¯éµã«ãã£ã¦ã®ã¿ãã¼ã¿ã復å·åã§ããããã«、å
¬ééµããã¼ã¿ã®æå·åã«ä½¿ç¨ãããã¨ãã§ãã¾ã。
ãã®ãµã³ãã«ã§ã¯、ãªã³ã©ã¤ã³è³¼å
¥ã®èªè¨¼æã«é対称éµã使ç¨ããæ¹æ³ã«ã¤ãã¦èª¬æãã¾ã。対称éµã®ä½¿ç¨ã«ã¤ãã¦ã¯、以åã«å
¬éããã FingerprintDialog ã®ãµã³ãã«ãåç
§ãã¦ãã ãã。
以ä¸ã¯、é対称éµã使ç¨ããå ´åã« Android ã¢ããª、ã¦ã¼ã¶ã¼、ããã¯ã¨ã³ããã©ã®ããã«é£æºããããå³ã§ç¤ºãããã®ã§ã。
1. è¨å®: é対称éµã®ãã¢ã®ä½æ
ã¾ã、次ã®ããã«é対称éµã®ãã¢ãä½æãã¾ã。
KeyPairGenerator . getInstance ( KeyProperties . KEY_ALGORITHM_EC , "AndroidKeyStore" );
keyPairGenerator . initialize (
new KeyGenParameterSpec . Builder ( KEY_NAME ,
KeyProperties . PURPOSE_SIGN )
. setDigests ( KeyProperties . DIGEST_SHA256 )
. setAlgorithmParameterSpec ( new ECGenParameterSpec ( "secp256r1" ))
. setUserAuthenticationRequired ( true )
. build ());
keyPairGenerator . generateKeyPair ();
.setUserAuthenticationRequired(true)
ã«æ³¨ç®ãã¦ãã ãã。ãã®ã¡ã½ãããå¼ã¶ãã¨ã«ãã、ç§å¯éµã使ç¨ããåã«、ç»é²ããæç´ã®èªè¨¼ãå¼·å¶ã§ããããã«ãªãã¾ã。
次ã«ä½æããç§å¯éµã¨å
¬ééµã以ä¸ã®ããã«åå¾ãã¾ã。
KeyStore keyStore = KeyStore . getInstance ( "AndroidKeyStore" );
keyStore . load ( null );
PublicKey publicKey =
keyStore . getCertificate ( MainActivity . KEY_NAME ). getPublicKey ();
KeyStore keyStore = KeyStore . getInstance ( "AndroidKeyStore" );
keyStore . load ( null );
PrivateKey key = ( PrivateKey ) keyStore . getKey ( KEY_NAME , null );
2. ç»é²: ãµã¼ãã¼ã¸ã®å
¬ééµã®ç»é²
次ã«、å
¬ééµãããã¯ã¨ã³ãã«éä¿¡ã、ãã®å¾ã®ã¦ã¼ã¶ã®è³¼å
¥ãã¦ã¼ã¶ã¼ã«ãã£ã¦æ¿èªããã¦ãããã¨(ãã®å
¬ééµã«å¯¾å¿ããç§å¯éµã«ãã£ã¦ç½²åããã¦ãããã¨)ãããã¯ã¨ã³ãã確èªããå¿
è¦ãããã¾ã。ãã®ãµã³ãã«ã§ã¯、å
¬ééµã®éä¿¡ã模æ¬çã«åç¾ããããã«ããã¯ã¨ã³ãå®è£
ã端æ«ä¸ã§åä½ãã模æ¬ã³ã¼ãã使ç¨ãã¦ãã¾ãã、å®éã«ã¯å
¬ééµããããã¯ã¼ã¯çµç±ã§éä¿¡ããå¿
è¦ãããã¾ã。
boolean enroll ( String userId , String password , PublicKey publicKey );
3. èªè¨¼: æç´ã«ããç½²åå¦ç
ååè³¼å
¥ãªã©ã§ã¦ã¼ã¶ã¼ãå¦çãèªè¨¼ã§ããããã«、æç´ã»ã³ãµã¼ã¸ã®ã¿ãããä¿ãããã³ããã表示ãã¾ã。
ç¶ãã¦、次ã®ããã«æç´ã®èªã¿è¾¼ã¿ãéå§ãã¾ã。
Signature . getInstance ( "SHA256withECDSA" );
KeyStore keyStore = KeyStore . getInstance ( "AndroidKeyStore" );
keyStore . load ( null );
PrivateKey key = ( PrivateKey ) keyStore . getKey ( KEY_NAME , null );
signature . initSign ( key );
CryptoObject cryptObject = new FingerprintManager . CryptoObject ( signature );
CancellationSignal cancellationSignal = new CancellationSignal ();
FingerprintManager fingerprintManager =
context . getSystemService ( FingerprintManager . class );
fingerprintManager . authenticate ( cryptoObject , cancellationSignal , 0 , this , null );
4. æçµå¦ç: ããã¯ã¨ã³ãã¸ã®ãã¼ã¿éä¿¡ã¨ç
§å
èªè¨¼ãæåããã、次ã®ããã«ç½²åæ¸ã¿ã®ãã¼ã¿(ãã®ãµã³ãã«ã§ã¯、è³¼å
¥å¦çã®å
容)ãããã¯ã¨ã³ãã«éä¿¡ãã¾ã。
Signature signature = cryptoObject . getSignature ();
// Include a client nonce in the transaction so that the nonce is also signed
// by the private key and the backend can verify that the same nonce can't be used
// to prevent replay attacks.
Transaction transaction = new Transaction ( "user" , 1 , new SecureRandom (). nextLong ());
try {
signature . update ( transaction . toByteArray ());
byte [] sigBytes = signature . sign ();
// Send the transaction and signedTransaction to the dummy backend
if ( mStoreBackend . verify ( transaction , sigBytes )) {
mActivity . onPurchased ( sigBytes );
dismiss ();
} else {
mActivity . onPurchaseFailed ();
dismiss ();
}
} catch ( SignatureException e ) {
throw new RuntimeException ( e );
}
æå¾ã«、ã¹ããã 2 ã§ç»é²ããå
¬ééµã使ç¨ã、ããã¯ã¨ã³ãã«ããç½²åæ¸ã¿ãã¼ã¿ã¨ç
§åãã¾ã。
@Override
public boolean verify ( Transaction transaction , byte [] transactionSignature ) {
try {
if ( mReceivedTransactions . contains ( transaction )) {
// It verifies the equality of the transaction including the client nonce
// So attackers can't do replay attacks.
return false ;
}
mReceivedTransactions . add ( transaction );
PublicKey publicKey = mPublicKeys . get ( transaction . getUserId ());
Signature verificationFunction = Signature . getInstance ( "SHA256withECDSA" );
verificationFunction . initVerify ( publicKey );
verificationFunction . update ( transaction . toByteArray ());
if ( verificationFunction . verify ( transactionSignature )) {
// Transaction is verified with the public key associated with the user
// Do some post purchase processing in the server
return true ;
}
} catch ( NoSuchAlgorithmException | InvalidKeyException | SignatureException e ) {
// In a real world, better to send some error message to the user
}
return false ;
}
ã¹ããã 1 ã§è¿°ã¹ãã¨ãã、ç§å¯éµã使ç¨ããåã«ã¦ã¼ã¶ã¼èªè¨¼ãæ¯åå¿
è¦ã§ãããã、ãã®æç¹ã§ã¦ã¼ã¶ã¼èªèº«ã®æç´ãæ£ããèªè¨¼ããã¦ããã¨ã¿ãªããã¨ãã§ãã¾ã。ããã¯ã¨ã³ãã§è³¼å
¥å¾ã®å¦çãå®è¡ã、ã¦ã¼ã¶ã¼ã«å¦çãæåãããã¨ãéç¥ãã¾ããã。
ãã®ä»ã®æ´æ°ããããµã³ãã«
ãã®ä»ã«、 Android for Work API ã«é¢é£ãã Marshmallow ã§æ´æ°ãããæ©è½ã«ã¤ãã¦ãµã³ãã«ãæ´æ°ãã¾ãã。
AppRestrictionEnforcer 㨠AppRestrictionSchema ã®ãµã³ãã«ã¯、Android 5.0 Lollipop ã® Android for Work API ã®ä¸é¨ã¨ã㦠ã¢ããªå¶éæ©è½ å°å
¥æã«ãªãªã¼ã¹ããã¾ãã。AppRestrictionEnforcer ã¯、ãããã¡ã¤ã« ãªã¼ãã¼ã¨ãã¦ä»ã®ã¢ããªã«å¶éãè¨å®ããæ¹æ³ã«ã¤ãã¦èª¬æãã¦ãã¾ã。AppRestrictionSchema ã¯、AppRestrictionEnforcer ã§å¶å¾¡ã§ããããã¤ãã®å¶éãå®ç¾©ãã¦ãã¾ã。ãã®æ´æ°ã¯、Android 6.0 ã§è¿½å å°å
¥ããã 2 ã¤ã®å¶éã¿ã¤ãã®ä½¿ç¨æ¹æ³ã«ã¤ãã¦èª¬æãã¦ãã¾ã。
æ´æ°ããããµã³ãã«ããããããã¼ã®çæ§ã®ãå½¹ã«ç«ã¦ãã°ã¨æãã¾ã。ãµã³ãã«ã«ã¤ãã¦ã®ã質åã¯、GitHub ãã¼ã¸ 㧠Issue ãç»é²ããã、Pull Request ãéã£ã¦ããã ããããé¡ãè´ãã¾ã。
Posted by Takeshi Hagikura - Developer Relations Team