diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java b/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java
index 8a52a01e..6d3be591 100644
--- a/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java
+++ b/app/src/main/java/org/shadowice/flocke/andotp/Activities/MainActivity.java
@@ -93,11 +93,13 @@ public class MainActivity extends BaseActivity
final EditText labelInput = (EditText) inputView.findViewById(R.id.manual_label);
final EditText secretInput = (EditText) inputView.findViewById(R.id.manual_secret);
final EditText periodInput = (EditText) inputView.findViewById(R.id.manual_period);
+ final EditText digitsInput = (EditText) inputView.findViewById(R.id.manual_digits);
final Spinner algorithmInput = (Spinner) inputView.findViewById(R.id.manual_algorithm);
typeInput.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, Entry.OTPType.values()));
algorithmInput.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_expandable_list_item_1, TokenCalculator.HashAlgorithm.values()));
periodInput.setText(Integer.toString(TokenCalculator.TOTP_DEFAULT_PERIOD));
+ digitsInput.setText(Integer.toString(TokenCalculator.TOTP_DEFAULT_DIGITS));
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.dialog_title_manual_entry)
@@ -112,8 +114,9 @@ public class MainActivity extends BaseActivity
String label = labelInput.getText().toString();
String secret = secretInput.getText().toString();
int period = Integer.parseInt(periodInput.getText().toString());
+ int digits = Integer.parseInt(digitsInput.getText().toString());
- Entry e = new Entry(type, secret, period, label, algorithm);
+ Entry e = new Entry(type, secret, period, digits, label, algorithm);
e.updateOTP();
adapter.addEntry(e);
adapter.saveEntries();
diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Database/Entry.java b/app/src/main/java/org/shadowice/flocke/andotp/Database/Entry.java
index 88ddcad0..44e68243 100644
--- a/app/src/main/java/org/shadowice/flocke/andotp/Database/Entry.java
+++ b/app/src/main/java/org/shadowice/flocke/andotp/Database/Entry.java
@@ -42,11 +42,13 @@ public class Entry {
private static final String JSON_SECRET = "secret";
private static final String JSON_LABEL = "label";
private static final String JSON_PERIOD = "period";
+ private static final String JSON_DIGITS = "digits";
private static final String JSON_TYPE = "type";
private static final String JSON_ALGORITHM = "algorithm";
private OTPType type = OTPType.TOTP;
private int period = TokenCalculator.TOTP_DEFAULT_PERIOD;
+ private int digits = TokenCalculator.TOTP_DEFAULT_DIGITS;
private TokenCalculator.HashAlgorithm algorithm = TokenCalculator.DEFAULT_ALGORITHM;
private byte[] secret;
private String label;
@@ -55,10 +57,11 @@ public class Entry {
public Entry(){}
- public Entry(OTPType type, String secret, int period, String label, TokenCalculator.HashAlgorithm algorithm) {
+ public Entry(OTPType type, String secret, int period, int digits, String label, TokenCalculator.HashAlgorithm algorithm) {
this.type = type;
this.secret = new Base32().decode(secret.toUpperCase());
this.period = period;
+ this.digits = digits;
this.label = label;
this.algorithm = algorithm;
}
@@ -83,6 +86,7 @@ public class Entry {
String issuer = uri.getQueryParameter("issuer");
String period = uri.getQueryParameter("period");
+ String digits = uri.getQueryParameter("digits");
String algorithm = uri.getQueryParameter("algorithm");
if(issuer != null){
@@ -98,6 +102,12 @@ public class Entry {
this.period = TokenCalculator.TOTP_DEFAULT_PERIOD;
}
+ if (digits != null) {
+ this.digits = Integer.parseInt(digits);
+ } else {
+ this.digits = TokenCalculator.TOTP_DEFAULT_DIGITS;
+ }
+
if (algorithm != null) {
this.algorithm = TokenCalculator.HashAlgorithm.valueOf(algorithm.toUpperCase());
} else {
@@ -110,6 +120,12 @@ public class Entry {
this.label = jsonObj.getString(JSON_LABEL);
this.period = jsonObj.getInt(JSON_PERIOD);
+ try {
+ this.digits = jsonObj.getInt(JSON_DIGITS);
+ } catch(JSONException e) {
+ this.digits = TokenCalculator.TOTP_DEFAULT_DIGITS;
+ }
+
try {
this.type = OTPType.valueOf(jsonObj.getString(JSON_TYPE));
} catch(JSONException e) {
@@ -128,6 +144,7 @@ public class Entry {
jsonObj.put(JSON_SECRET, new String(new Base32().encode(getSecret())));
jsonObj.put(JSON_LABEL, getLabel());
jsonObj.put(JSON_PERIOD, getPeriod());
+ jsonObj.put(JSON_DIGITS, getDigits());
jsonObj.put(JSON_TYPE, getType().toString());
jsonObj.put(JSON_ALGORITHM, algorithm.toString());
@@ -166,6 +183,14 @@ public class Entry {
this.period = period;
}
+ public int getDigits() {
+ return digits;
+ }
+
+ public void setDigits(int digits) {
+ this.digits = digits;
+ }
+
public TokenCalculator.HashAlgorithm getAlgorithm() {
return this.algorithm;
}
@@ -187,7 +212,7 @@ public class Entry {
long counter = time / this.getPeriod();
if (counter > last_update) {
- currentOTP = TokenCalculator.TOTP(secret, period, algorithm);
+ currentOTP = TokenCalculator.TOTP(secret, period, digits, algorithm);
last_update = counter;
return true;
@@ -202,6 +227,7 @@ public class Entry {
if (o == null || getClass() != o.getClass()) return false;
Entry entry = (Entry) o;
return period == entry.period &&
+ digits == entry.digits &&
type == entry.type &&
algorithm == entry.algorithm &&
Arrays.equals(secret, entry.secret) &&
@@ -210,6 +236,6 @@ public class Entry {
@Override
public int hashCode() {
- return Objects.hash(type, period, algorithm, secret, label);
+ return Objects.hash(type, period, digits, algorithm, secret, label);
}
}
diff --git a/app/src/main/java/org/shadowice/flocke/andotp/Utilities/TokenCalculator.java b/app/src/main/java/org/shadowice/flocke/andotp/Utilities/TokenCalculator.java
index 3dfeabdb..84e58a63 100644
--- a/app/src/main/java/org/shadowice/flocke/andotp/Utilities/TokenCalculator.java
+++ b/app/src/main/java/org/shadowice/flocke/andotp/Utilities/TokenCalculator.java
@@ -33,6 +33,7 @@ import javax.crypto.spec.SecretKeySpec;
public class TokenCalculator {
public static final int TOTP_DEFAULT_PERIOD = 30;
+ public static final int TOTP_DEFAULT_DIGITS = 6;
public enum HashAlgorithm {
SHA1, SHA256, SHA512
@@ -50,8 +51,8 @@ public class TokenCalculator {
return mac.doFinal(data);
}
- public static String TOTP(byte[] secret, int period, HashAlgorithm algorithm) {
- return String.format("%06d", TOTP(secret, period, System.currentTimeMillis() / 1000, 6, algorithm));
+ public static String TOTP(byte[] secret, int period, int digits, HashAlgorithm algorithm) {
+ return String.format("%0" + digits + "d", TOTP(secret, period, System.currentTimeMillis() / 1000, digits, algorithm));
}
public static int TOTP(byte[] key, int period, long time, int digits, HashAlgorithm algorithm)
diff --git a/app/src/main/res/layout/dialog_manual_entry.xml b/app/src/main/res/layout/dialog_manual_entry.xml
index 30559adc..2c97254e 100644
--- a/app/src/main/res/layout/dialog_manual_entry.xml
+++ b/app/src/main/res/layout/dialog_manual_entry.xml
@@ -86,6 +86,27 @@
+
+
+
+
+
+
+
+
Type
Secret
Period
+ Digits
Label
Algorithm