Reduce the amount of wear on the flash.
No need to assume failure as an attacker won't know the outcome thanks
to tamper proof hardware.
Bug: 34872600
Test: libese-app-weaver-test
Change-Id: Ibb93258e5806301659794f21fb107356b07beb77
diff --git a/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java b/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java
index 35842d3..e744f02 100644
--- a/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java
+++ b/apps/weaver/card/src/com/android/weaver/core/CoreSlots.java
@@ -38,8 +38,10 @@
mSlots[i] = new Slot();
}
- final short intBytes = 4;
- Slot.sRemainingBackoff = JCSystem.makeTransientByteArray(intBytes, JCSystem.CLEAR_ON_RESET);
+ // Make the same size as the value so the whole buffer can be copied in read() so there is
+ // no time difference between success and failure.
+ Slot.sRemainingBackoff = JCSystem.makeTransientByteArray(
+ Consts.SLOT_VALUE_BYTES, JCSystem.CLEAR_ON_RESET);
}
@Override
@@ -128,7 +130,10 @@
*/
public byte read(byte[] keyBuffer, short keyOffset, byte[] outBuffer, short outOffset) {
// Check timeout has expired or hasn't been started
+ // TODO: bring back the timer
//mBackoffTimer.getRemainingTime(sRemainingBackoff, (short) 0);
+ Util.setShort(sRemainingBackoff, (short) 0, (short) 0);
+ Util.setShort(sRemainingBackoff, (short) 2, (short) 0);
if (sRemainingBackoff[0] != 0 || sRemainingBackoff[1] != 0 ||
sRemainingBackoff[2] != 0 || sRemainingBackoff[3] != 0) {
Util.arrayCopyNonAtomic(
@@ -136,34 +141,37 @@
return Consts.READ_BACK_OFF;
}
- // Assume this to be a failed attempt until proven otherwise. This means losing power
- // midway cannot be abused for extra attempts.
- JCSystem.beginTransaction();
- if (mFailureCount != 0x7fff) {
- mFailureCount += 1;
+ // Check the key matches in constant time and copy out the value if it does
+ byte difference = 0;
+ for (short i = 0; i < Consts.SLOT_KEY_BYTES; ++i) {
+ difference |= keyBuffer[(short) (keyOffset + i)] ^ mKey[i];
}
- throttle(sRemainingBackoff, (short) 0, mFailureCount);
- //mBackoffTimer.startTimer(
- // sRemainingBackoff, (short) 0, DSTimer.DST_POWEROFFMODE_FALLBACK);
- JCSystem.commitTransaction();
+ final byte result = (difference == 0) ? Consts.READ_SUCCESS : Consts.READ_WRONG_KEY;
- // Check the key matches and copy out the value if it does
- if (Util.arrayCompare(
- keyBuffer, keyOffset, mKey, (short) 0, Consts.SLOT_KEY_BYTES) != 0) {
- Util.arrayCopyNonAtomic(
- sRemainingBackoff, (short) 0, outBuffer, outOffset, (byte) 4);
- return Consts.READ_WRONG_KEY;
+ // Keep track of the number of failures
+ if (result == Consts.READ_WRONG_KEY) {
+ if (mFailureCount != 0x7fff) {
+ mFailureCount += 1;
+ }
+ } else {
+ // This read was successful so reset the failures
+ if (mFailureCount != 0) { // attempt to maintain constant time
+ mFailureCount = 0;
+ }
}
- // This attempt was successful so reset the failures
- JCSystem.beginTransaction();
- mFailureCount = 0;
- //mBackoffTimer.stopTimer();
- JCSystem.commitTransaction();
+ // Start the timer on a failure
+ if (throttle(sRemainingBackoff, (short) 0, mFailureCount)) {
+ //mBackoffTimer.startTimer(
+ // sRemainingBackoff, (short) 0, DSTimer.DST_POWEROFFMODE_FALLBACK);
+ } else {
+ //mBackoffTimer.stopTimer();
+ }
- Util.arrayCopyNonAtomic(
- mValue, (short) 0, outBuffer, outOffset, Consts.SLOT_VALUE_BYTES);
- return Consts.READ_SUCCESS;
+ final byte[] data = (result == Consts.READ_SUCCESS) ? mValue : sRemainingBackoff;
+ Util.arrayCopyNonAtomic(data, (short) 0, outBuffer, outOffset, Consts.SLOT_VALUE_BYTES);
+
+ return result;
}
/**
@@ -187,8 +195,10 @@
* [140, inf) -> 1 day
*
* The 32-bit millisecond timeout is written to the array.
+ *
+ * @return Whether there is any throttle time.
*/
- private static void throttle(byte[] bArray, short bOff, short failureCount) {
+ private static boolean throttle(byte[] bArray, short bOff, short failureCount) {
short highWord = 0;
short lowWord = 0;
@@ -219,6 +229,8 @@
// Write the value to the buffer
Util.setShort(bArray, bOff, highWord);
Util.setShort(bArray, (short) (bOff + 2), lowWord);
+
+ return highWord != 0 || lowWord != 0;
}
}
}