aboutsummaryrefslogtreecommitdiff
path: root/security/AsymmetricFingerprintDialog
diff options
context:
space:
mode:
authorTakeshi Hagikura <thagikura@google.com>2015-10-05 15:43:12 +0900
committerTakeshi Hagikura <thagikura@google.com>2015-10-07 18:09:49 +0900
commit54c876b6980f9e67a4acc50b91ad06296f6798f6 (patch)
treefe159a1c396037f51085f7b4672505d73c1dee28 /security/AsymmetricFingerprintDialog
parent67fcd44215052bdde25a723475ee4b63a8e7d3dc (diff)
downloadandroid-54c876b6980f9e67a4acc50b91ad06296f6798f6.tar.gz
Add a client nonce in the transactions to prevent replay attacks.
Change-Id: Icf98c918223fc4b738c569f764726032329cffee
Diffstat (limited to 'security/AsymmetricFingerprintDialog')
-rw-r--r--security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java8
-rw-r--r--security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java3
-rw-r--r--security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackend.java1
-rw-r--r--security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackendImpl.java10
-rw-r--r--security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/Transaction.java30
5 files changed, 44 insertions, 8 deletions
diff --git a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java
index d40661c6..a56556f1 100644
--- a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java
+++ b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/FingerprintAuthenticationDialogFragment.java
@@ -42,6 +42,7 @@ import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
@@ -217,7 +218,7 @@ public class FingerprintAuthenticationDialogFragment extends DialogFragment
* the activity know about the result.
*/
private void verifyPassword() {
- Transaction transaction = new Transaction("user", 1);
+ Transaction transaction = new Transaction("user", 1, new SecureRandom().nextLong());
if (!mStoreBackend.verify(transaction, mPassword.getText().toString())) {
return;
}
@@ -284,7 +285,10 @@ public class FingerprintAuthenticationDialogFragment extends DialogFragment
// successful.
mPassword.setText("");
Signature signature = mCryptoObject.getSignature();
- Transaction transaction = new Transaction("user", 1);
+ // 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();
diff --git a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java
index e6031c52..5086a173 100644
--- a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java
+++ b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/MainActivity.java
@@ -55,10 +55,7 @@ import javax.inject.Inject;
*/
public class MainActivity extends Activity {
- private static final String TAG = MainActivity.class.getSimpleName();
-
private static final String DIALOG_FRAGMENT_TAG = "myFragment";
- private static final String SECRET_MESSAGE = "Very secret message";
/** Alias for our key in the Android Key Store */
public static final String KEY_NAME = "my_key";
diff --git a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackend.java b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackend.java
index dde81519..87921ae5 100644
--- a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackend.java
+++ b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackend.java
@@ -57,5 +57,4 @@ public interface StoreBackend {
* @return true if the enrollment was successful, false otherwise
*/
boolean enroll(String userId, String password, PublicKey publicKey);
-
}
diff --git a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackendImpl.java b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackendImpl.java
index 8bf48d89..b28dce49 100644
--- a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackendImpl.java
+++ b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/StoreBackendImpl.java
@@ -23,7 +23,9 @@ import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
+import java.util.Set;
/**
* A fake backend implementation of {@link StoreBackend}.
@@ -31,10 +33,17 @@ import java.util.Map;
public class StoreBackendImpl implements StoreBackend {
private final Map<String, PublicKey> mPublicKeys = new HashMap<>();
+ private final Set<Transaction> mReceivedTransactions = new HashSet<>();
@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);
@@ -65,5 +74,4 @@ public class StoreBackendImpl implements StoreBackend {
// backend.
return true;
}
-
}
diff --git a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/Transaction.java b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/Transaction.java
index 33b65ef8..789cc0e7 100644
--- a/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/Transaction.java
+++ b/security/AsymmetricFingerprintDialog/Application/src/main/java/com/example/android/asymmetricfingerprintdialog/server/Transaction.java
@@ -19,6 +19,7 @@ package com.example.android.asymmetricfingerprintdialog.server;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
+import java.util.Objects;
/**
* An entity that represents a single transaction (purchase) of an item.
@@ -31,9 +32,16 @@ public class Transaction {
/** The unique user ID who made the transaction */
private final String mUserId;
- public Transaction(String userId, long itemId) {
+ /**
+ * The random long value that will be also signed by the private key and verified in the server
+ * that the same nonce can't be reused to prevent replay attacks.
+ */
+ private final Long mClientNonce;
+
+ public Transaction(String userId, long itemId, long clientNonce) {
mItemId = itemId;
mUserId = userId;
+ mClientNonce = clientNonce;
}
public String getUserId() {
@@ -47,6 +55,7 @@ public class Transaction {
dataOutputStream = new DataOutputStream(byteArrayOutputStream);
dataOutputStream.writeLong(mItemId);
dataOutputStream.writeUTF(mUserId);
+ dataOutputStream.writeLong(mClientNonce);
return byteArrayOutputStream.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
@@ -63,4 +72,23 @@ public class Transaction {
}
}
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Transaction that = (Transaction) o;
+ return Objects.equals(mItemId, that.mItemId) && Objects.equals(mUserId, that.mUserId) &&
+ Objects.equals(mClientNonce, that.mClientNonce);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mItemId, mUserId, mClientNonce);
+ }
}