mirror of
https://github.com/beemdevelopment/Aegis.git
synced 2025-05-04 20:30:36 +00:00
Get rid of all uses of double brace initialization
The way this feature is implemented in java is absolutely ridiculous
This commit is contained in:
parent
c3f94b37c8
commit
3f01a0a3da
15 changed files with 139 additions and 103 deletions
|
@ -38,7 +38,7 @@ dependencies {
|
||||||
implementation 'com.android.support:cardview-v7:27.1.1'
|
implementation 'com.android.support:cardview-v7:27.1.1'
|
||||||
implementation 'com.android.support:support-v4:27.1.1'
|
implementation 'com.android.support:support-v4:27.1.1'
|
||||||
implementation 'com.mattprecious.swirl:swirl:1.0.0'
|
implementation 'com.mattprecious.swirl:swirl:1.0.0'
|
||||||
implementation 'com.madgag.spongycastle:core:1.56.0.0'
|
implementation 'com.madgag.spongycastle:core:1.58.0.0'
|
||||||
implementation 'com.github.apl-devs:appintro:v4.2.2'
|
implementation 'com.github.apl-devs:appintro:v4.2.2'
|
||||||
implementation 'com.getbase:floatingactionbutton:1.10.1'
|
implementation 'com.getbase:floatingactionbutton:1.10.1'
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
|
|
|
@ -9,15 +9,20 @@ import me.impy.aegis.encoding.Hex;
|
||||||
import me.impy.aegis.encoding.HexException;
|
import me.impy.aegis.encoding.HexException;
|
||||||
|
|
||||||
public class CryptParameters implements Serializable {
|
public class CryptParameters implements Serializable {
|
||||||
public byte[] Nonce;
|
private byte[] _nonce;
|
||||||
public byte[] Tag;
|
private byte[] _tag;
|
||||||
|
|
||||||
|
public CryptParameters(byte[] nonce, byte[] tag) {
|
||||||
|
_nonce = nonce;
|
||||||
|
_tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
public JSONObject toJson() {
|
public JSONObject toJson() {
|
||||||
JSONObject obj = new JSONObject();
|
JSONObject obj = new JSONObject();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
obj.put("nonce", Hex.encode(Nonce));
|
obj.put("nonce", Hex.encode(_nonce));
|
||||||
obj.put("tag", Hex.encode(Tag));
|
obj.put("tag", Hex.encode(_tag));
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
|
@ -26,11 +31,16 @@ public class CryptParameters implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CryptParameters parseJson(JSONObject obj) throws JSONException, HexException {
|
public static CryptParameters parseJson(JSONObject obj) throws JSONException, HexException {
|
||||||
byte[] tag = Hex.decode(obj.getString("tag"));
|
|
||||||
byte[] nonce = Hex.decode(obj.getString("nonce"));
|
byte[] nonce = Hex.decode(obj.getString("nonce"));
|
||||||
return new CryptParameters() {{
|
byte[] tag = Hex.decode(obj.getString("tag"));
|
||||||
Tag = tag;
|
return new CryptParameters(nonce, tag);
|
||||||
Nonce = nonce;
|
}
|
||||||
}};
|
|
||||||
|
public byte[] getNonce() {
|
||||||
|
return _nonce;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getTag() {
|
||||||
|
return _tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,19 @@
|
||||||
package me.impy.aegis.crypto;
|
package me.impy.aegis.crypto;
|
||||||
|
|
||||||
public class CryptResult {
|
public class CryptResult {
|
||||||
public CryptParameters Parameters;
|
private byte[] _data;
|
||||||
public byte[] Data;
|
private CryptParameters _params;
|
||||||
|
|
||||||
|
public CryptResult(byte[] data, CryptParameters params) {
|
||||||
|
_data = data;
|
||||||
|
_params = params;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getData() {
|
||||||
|
return _data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CryptParameters getParams() {
|
||||||
|
return _params;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,13 +74,7 @@ public class CryptoUtils {
|
||||||
byte[] tag = Arrays.copyOfRange(result, result.length - CRYPTO_AEAD_TAG_SIZE, result.length);
|
byte[] tag = Arrays.copyOfRange(result, result.length - CRYPTO_AEAD_TAG_SIZE, result.length);
|
||||||
byte[] encrypted = Arrays.copyOfRange(result, 0, result.length - CRYPTO_AEAD_TAG_SIZE);
|
byte[] encrypted = Arrays.copyOfRange(result, 0, result.length - CRYPTO_AEAD_TAG_SIZE);
|
||||||
|
|
||||||
return new CryptResult() {{
|
return new CryptResult(encrypted, new CryptParameters(cipher.getIV(), tag));
|
||||||
Parameters = new CryptParameters() {{
|
|
||||||
Nonce = cipher.getIV();
|
|
||||||
Tag = tag;
|
|
||||||
}};
|
|
||||||
Data = encrypted;
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CryptResult decrypt(byte[] encrypted, Cipher cipher, CryptParameters params)
|
public static CryptResult decrypt(byte[] encrypted, Cipher cipher, CryptParameters params)
|
||||||
|
@ -88,15 +82,12 @@ public class CryptoUtils {
|
||||||
// append the tag to the ciphertext
|
// append the tag to the ciphertext
|
||||||
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||||
stream.write(encrypted);
|
stream.write(encrypted);
|
||||||
stream.write(params.Tag);
|
stream.write(params.getTag());
|
||||||
|
|
||||||
encrypted = stream.toByteArray();
|
encrypted = stream.toByteArray();
|
||||||
byte[] decrypted = cipher.doFinal(encrypted);
|
byte[] decrypted = cipher.doFinal(encrypted);
|
||||||
|
|
||||||
return new CryptResult() {{
|
return new CryptResult(decrypted, params);
|
||||||
Parameters = params;
|
|
||||||
Data = decrypted;
|
|
||||||
}};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SecretKey generateKey() {
|
public static SecretKey generateKey() {
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class MasterKey implements Serializable {
|
||||||
|
|
||||||
public CryptResult decrypt(byte[] bytes, CryptParameters params) throws MasterKeyException {
|
public CryptResult decrypt(byte[] bytes, CryptParameters params) throws MasterKeyException {
|
||||||
try {
|
try {
|
||||||
Cipher cipher = CryptoUtils.createDecryptCipher(_key, params.Nonce);
|
Cipher cipher = CryptoUtils.createDecryptCipher(_key, params.getNonce());
|
||||||
return CryptoUtils.decrypt(bytes, cipher, params);
|
return CryptoUtils.decrypt(bytes, cipher, params);
|
||||||
} catch (NoSuchPaddingException
|
} catch (NoSuchPaddingException
|
||||||
| NoSuchAlgorithmException
|
| NoSuchAlgorithmException
|
||||||
|
|
|
@ -83,7 +83,7 @@ public class DatabaseFile {
|
||||||
try {
|
try {
|
||||||
byte[] bytes = Base64.decode((String) _content);
|
byte[] bytes = Base64.decode((String) _content);
|
||||||
CryptResult result = key.decrypt(bytes, _cryptParameters);
|
CryptResult result = key.decrypt(bytes, _cryptParameters);
|
||||||
return new JSONObject(new String(result.Data, "UTF-8"));
|
return new JSONObject(new String(result.getData(), "UTF-8"));
|
||||||
} catch (MasterKeyException | JSONException | UnsupportedEncodingException | Base64Exception e) {
|
} catch (MasterKeyException | JSONException | UnsupportedEncodingException | Base64Exception e) {
|
||||||
throw new DatabaseFileException(e);
|
throw new DatabaseFileException(e);
|
||||||
}
|
}
|
||||||
|
@ -101,8 +101,8 @@ public class DatabaseFile {
|
||||||
byte[] dbBytes = string.getBytes("UTF-8");
|
byte[] dbBytes = string.getBytes("UTF-8");
|
||||||
|
|
||||||
CryptResult result = key.encrypt(dbBytes);
|
CryptResult result = key.encrypt(dbBytes);
|
||||||
_content = Base64.encode(result.Data);
|
_content = Base64.encode(result.getData());
|
||||||
_cryptParameters = result.Parameters;
|
_cryptParameters = result.getParams();
|
||||||
} catch (MasterKeyException | UnsupportedEncodingException | JSONException e) {
|
} catch (MasterKeyException | UnsupportedEncodingException | JSONException e) {
|
||||||
throw new DatabaseFileException(e);
|
throw new DatabaseFileException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public abstract class Slot implements Serializable {
|
||||||
public MasterKey getKey(Cipher cipher) throws SlotException, SlotIntegrityException {
|
public MasterKey getKey(Cipher cipher) throws SlotException, SlotIntegrityException {
|
||||||
try {
|
try {
|
||||||
CryptResult res = CryptoUtils.decrypt(_encryptedMasterKey, cipher, _encryptedMasterKeyParams);
|
CryptResult res = CryptoUtils.decrypt(_encryptedMasterKey, cipher, _encryptedMasterKeyParams);
|
||||||
SecretKey key = new SecretKeySpec(res.Data, CryptoUtils.CRYPTO_AEAD);
|
SecretKey key = new SecretKeySpec(res.getData(), CryptoUtils.CRYPTO_AEAD);
|
||||||
return new MasterKey(key);
|
return new MasterKey(key);
|
||||||
} catch (AEADBadTagException e) {
|
} catch (AEADBadTagException e) {
|
||||||
throw new SlotIntegrityException(e);
|
throw new SlotIntegrityException(e);
|
||||||
|
@ -56,8 +56,8 @@ public abstract class Slot implements Serializable {
|
||||||
try {
|
try {
|
||||||
byte[] masterKeyBytes = masterKey.getBytes();
|
byte[] masterKeyBytes = masterKey.getBytes();
|
||||||
CryptResult res = CryptoUtils.encrypt(masterKeyBytes, cipher);
|
CryptResult res = CryptoUtils.encrypt(masterKeyBytes, cipher);
|
||||||
_encryptedMasterKey = res.Data;
|
_encryptedMasterKey = res.getData();
|
||||||
_encryptedMasterKeyParams = res.Parameters;
|
_encryptedMasterKeyParams = res.getParams();
|
||||||
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
} catch (BadPaddingException | IllegalBlockSizeException e) {
|
||||||
throw new SlotException(e);
|
throw new SlotException(e);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ public abstract class Slot implements Serializable {
|
||||||
|
|
||||||
public Cipher createDecryptCipher(SecretKey key) throws SlotException {
|
public Cipher createDecryptCipher(SecretKey key) throws SlotException {
|
||||||
try {
|
try {
|
||||||
return CryptoUtils.createDecryptCipher(key, _encryptedMasterKeyParams.Nonce);
|
return CryptoUtils.createDecryptCipher(key, _encryptedMasterKeyParams.getNonce());
|
||||||
} catch (InvalidAlgorithmParameterException
|
} catch (InvalidAlgorithmParameterException
|
||||||
| NoSuchAlgorithmException
|
| NoSuchAlgorithmException
|
||||||
| InvalidKeyException
|
| InvalidKeyException
|
||||||
|
|
|
@ -123,7 +123,11 @@ public class FreeOtpImporter extends DatabaseImporter {
|
||||||
String name = parser.getAttributeValue(null, "name");
|
String name = parser.getAttributeValue(null, "name");
|
||||||
String value = parseText(parser);
|
String value = parseText(parser);
|
||||||
parser.require(XmlPullParser.END_TAG, null, "string");
|
parser.require(XmlPullParser.END_TAG, null, "string");
|
||||||
return new XmlEntry() {{ Name = name; Value = value; }};
|
|
||||||
|
XmlEntry entry = new XmlEntry();
|
||||||
|
entry.Name = name;
|
||||||
|
entry.Value = value;
|
||||||
|
return entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String parseText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
private static String parseText(XmlPullParser parser) throws IOException, XmlPullParserException {
|
||||||
|
|
|
@ -31,9 +31,9 @@ import me.impy.aegis.db.slots.SlotException;
|
||||||
import me.impy.aegis.helpers.FingerprintHelper;
|
import me.impy.aegis.helpers.FingerprintHelper;
|
||||||
import me.impy.aegis.helpers.FingerprintUiHelper;
|
import me.impy.aegis.helpers.FingerprintUiHelper;
|
||||||
import me.impy.aegis.helpers.EditTextHelper;
|
import me.impy.aegis.helpers.EditTextHelper;
|
||||||
import me.impy.aegis.ui.tasks.SlotCollectionTask;
|
import me.impy.aegis.ui.tasks.SlotListTask;
|
||||||
|
|
||||||
public class AuthActivity extends AegisActivity implements FingerprintUiHelper.Callback, SlotCollectionTask.Callback {
|
public class AuthActivity extends AegisActivity implements FingerprintUiHelper.Callback, SlotListTask.Callback {
|
||||||
private EditText _textPassword;
|
private EditText _textPassword;
|
||||||
|
|
||||||
private SlotList _slots;
|
private SlotList _slots;
|
||||||
|
@ -112,10 +112,8 @@ public class AuthActivity extends AegisActivity implements FingerprintUiHelper.C
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T extends Slot> void trySlots(Class<T> type, Object obj) {
|
private <T extends Slot> void trySlots(Class<T> type, Object obj) {
|
||||||
new SlotCollectionTask<>(type, this, this).execute(new SlotCollectionTask.Params(){{
|
SlotListTask.Params params = new SlotListTask.Params(_slots, obj);
|
||||||
Slots = _slots;
|
new SlotListTask<>(type, this, this).execute(params);
|
||||||
Obj = obj;
|
|
||||||
}});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setKey(MasterKey key) {
|
private void setKey(MasterKey key) {
|
||||||
|
|
|
@ -115,10 +115,8 @@ public class IntroActivity extends AppIntro implements DerivationTask.Callback {
|
||||||
|
|
||||||
if (newFragment == _endSlide && cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
if (newFragment == _endSlide && cryptType != CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
||||||
_passwordSlot = new PasswordSlot();
|
_passwordSlot = new PasswordSlot();
|
||||||
new DerivationTask(this, this).execute(new DerivationTask.Params() {{
|
DerivationTask.Params params = new DerivationTask.Params(_passwordSlot, _authenticatedSlide.getPassword());
|
||||||
Slot = _passwordSlot;
|
new DerivationTask(this, this).execute(params);
|
||||||
Password = _authenticatedSlide.getPassword();
|
|
||||||
}});
|
|
||||||
} else if (oldFragment == _authenticationSlide && newFragment != _endSlide) {
|
} else if (oldFragment == _authenticationSlide && newFragment != _endSlide) {
|
||||||
// skip to the last slide if no encryption will be used
|
// skip to the last slide if no encryption will be used
|
||||||
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
|
||||||
|
|
|
@ -60,10 +60,7 @@ public class PasswordDialogFragment extends SlotDialogFragment {
|
||||||
getListener().onSlotResult(slot, cipher);
|
getListener().onSlotResult(slot, cipher);
|
||||||
dialog.dismiss();
|
dialog.dismiss();
|
||||||
});
|
});
|
||||||
task.execute(new DerivationTask.Params() {{
|
task.execute(new DerivationTask.Params(slot, password));
|
||||||
Slot = slot;
|
|
||||||
Password = password;
|
|
||||||
}});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ public class DerivationTask extends ProgressDialogTask<DerivationTask.Params, Se
|
||||||
|
|
||||||
Params params = args[0];
|
Params params = args[0];
|
||||||
byte[] salt = CryptoUtils.generateSalt();
|
byte[] salt = CryptoUtils.generateSalt();
|
||||||
return params.Slot.deriveKey(params.Password, salt, CryptoUtils.CRYPTO_SCRYPT_N, CryptoUtils.CRYPTO_SCRYPT_r, CryptoUtils.CRYPTO_SCRYPT_p);
|
return params.getSlot().deriveKey(params.getPassword(), salt, CryptoUtils.CRYPTO_SCRYPT_N, CryptoUtils.CRYPTO_SCRYPT_r, CryptoUtils.CRYPTO_SCRYPT_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,8 +31,21 @@ public class DerivationTask extends ProgressDialogTask<DerivationTask.Params, Se
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Params {
|
public static class Params {
|
||||||
public PasswordSlot Slot;
|
private PasswordSlot _slot;
|
||||||
public char[] Password;
|
private char[] _password;
|
||||||
|
|
||||||
|
public Params(PasswordSlot slot, char[] password) {
|
||||||
|
_slot = slot;
|
||||||
|
_password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PasswordSlot getSlot() {
|
||||||
|
return _slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public char[] getPassword() {
|
||||||
|
return _password;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
|
|
|
@ -13,36 +13,37 @@ import me.impy.aegis.db.slots.SlotList;
|
||||||
import me.impy.aegis.db.slots.SlotException;
|
import me.impy.aegis.db.slots.SlotException;
|
||||||
import me.impy.aegis.db.slots.SlotIntegrityException;
|
import me.impy.aegis.db.slots.SlotIntegrityException;
|
||||||
|
|
||||||
public class SlotCollectionTask<T extends Slot> extends ProgressDialogTask<SlotCollectionTask.Params, MasterKey> {
|
public class SlotListTask<T extends Slot> extends ProgressDialogTask<SlotListTask.Params, MasterKey> {
|
||||||
private Callback _cb;
|
private Callback _cb;
|
||||||
private Class<T> _type;
|
private Class<T> _type;
|
||||||
|
|
||||||
public SlotCollectionTask(Class<T> type, Context context, Callback cb) {
|
public SlotListTask(Class<T> type, Context context, Callback cb) {
|
||||||
super(context, "Decrypting database");
|
super(context, "Decrypting database");
|
||||||
_cb = cb;
|
_cb = cb;
|
||||||
_type = type;
|
_type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected MasterKey doInBackground(SlotCollectionTask.Params... args) {
|
protected MasterKey doInBackground(SlotListTask.Params... args) {
|
||||||
setPriority();
|
setPriority();
|
||||||
|
|
||||||
Params params = args[0];
|
Params params = args[0];
|
||||||
|
SlotList slots = params.getSlots();
|
||||||
try {
|
try {
|
||||||
if (!params.Slots.has(_type)) {
|
if (!slots.has(_type)) {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
MasterKey masterKey = null;
|
MasterKey masterKey = null;
|
||||||
for (Slot slot : params.Slots.findAll(_type)) {
|
for (Slot slot : slots.findAll(_type)) {
|
||||||
try {
|
try {
|
||||||
if (slot instanceof PasswordSlot) {
|
if (slot instanceof PasswordSlot) {
|
||||||
char[] password = (char[])params.Obj;
|
char[] password = (char[])params.getObj();
|
||||||
SecretKey key = ((PasswordSlot)slot).deriveKey(password);
|
SecretKey key = ((PasswordSlot)slot).deriveKey(password);
|
||||||
Cipher cipher = slot.createDecryptCipher(key);
|
Cipher cipher = slot.createDecryptCipher(key);
|
||||||
masterKey = slot.getKey(cipher);
|
masterKey = slot.getKey(cipher);
|
||||||
} else if (slot instanceof FingerprintSlot) {
|
} else if (slot instanceof FingerprintSlot) {
|
||||||
masterKey = slot.getKey((Cipher)params.Obj);
|
masterKey = slot.getKey((Cipher)params.getObj());
|
||||||
} else {
|
} else {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
@ -71,8 +72,21 @@ public class SlotCollectionTask<T extends Slot> extends ProgressDialogTask<SlotC
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Params {
|
public static class Params {
|
||||||
public SlotList Slots;
|
private SlotList _slots;
|
||||||
public Object Obj;
|
private Object _obj;
|
||||||
|
|
||||||
|
public Params(SlotList slots, Object obj) {
|
||||||
|
_slots = slots;
|
||||||
|
_obj = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SlotList getSlots() {
|
||||||
|
return _slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getObj() {
|
||||||
|
return _obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface Callback {
|
public interface Callback {
|
|
@ -2,6 +2,9 @@ package me.impy.aegis;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.security.InvalidKeyException;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
|
|
||||||
import me.impy.aegis.crypto.otp.HOTP;
|
import me.impy.aegis.crypto.otp.HOTP;
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
@ -22,7 +25,7 @@ public class HOTPTest {
|
||||||
};
|
};
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void vectorsMatch() throws Exception {
|
public void vectorsMatch() throws InvalidKeyException, NoSuchAlgorithmException {
|
||||||
for (int i = 0; i < _vectors.length; i++) {
|
for (int i = 0; i < _vectors.length; i++) {
|
||||||
String otp = HOTP.generateOTP(_secret, i, 6, false, -1);
|
String otp = HOTP.generateOTP(_secret, i, 6, false, -1);
|
||||||
assertEquals(_vectors[i], otp);
|
assertEquals(_vectors[i], otp);
|
||||||
|
|
|
@ -7,59 +7,54 @@ import me.impy.aegis.crypto.otp.TOTP;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class TOTPTest {
|
public class TOTPTest {
|
||||||
private class testVector {
|
|
||||||
public String Time;
|
|
||||||
public String Mode;
|
|
||||||
public String OTP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://tools.ietf.org/html/rfc6238#appendix-B
|
// https://tools.ietf.org/html/rfc6238#appendix-B
|
||||||
private final testVector[] _vectors = {
|
private final String[][] _vectors = {
|
||||||
new testVector(){{ Time = "0000000000000001"; OTP = "94287082"; Mode = "HmacSHA1"; }},
|
// time, OPT, algorithm
|
||||||
new testVector(){{ Time = "0000000000000001"; OTP = "46119246"; Mode = "HmacSHA256"; }},
|
{"0000000000000001", "94287082", "HmacSHA1"},
|
||||||
new testVector(){{ Time = "0000000000000001"; OTP = "90693936"; Mode = "HmacSHA512"; }},
|
{"0000000000000001", "46119246", "HmacSHA256"},
|
||||||
new testVector(){{ Time = "00000000023523EC"; OTP = "07081804"; Mode = "HmacSHA1"; }},
|
{"0000000000000001", "90693936", "HmacSHA512"},
|
||||||
new testVector(){{ Time = "00000000023523EC"; OTP = "68084774"; Mode = "HmacSHA256"; }},
|
{"00000000023523EC", "07081804", "HmacSHA1"},
|
||||||
new testVector(){{ Time = "00000000023523EC"; OTP = "25091201"; Mode = "HmacSHA512"; }},
|
{"00000000023523EC", "68084774", "HmacSHA256"},
|
||||||
new testVector(){{ Time = "00000000023523ED"; OTP = "14050471"; Mode = "HmacSHA1"; }},
|
{"00000000023523EC", "25091201", "HmacSHA512"},
|
||||||
new testVector(){{ Time = "00000000023523ED"; OTP = "67062674"; Mode = "HmacSHA256"; }},
|
{"00000000023523ED", "14050471", "HmacSHA1"},
|
||||||
new testVector(){{ Time = "00000000023523ED"; OTP = "99943326"; Mode = "HmacSHA512"; }},
|
{"00000000023523ED", "67062674", "HmacSHA256"},
|
||||||
new testVector(){{ Time = "000000000273EF07"; OTP = "89005924"; Mode = "HmacSHA1"; }},
|
{"00000000023523ED", "99943326", "HmacSHA512"},
|
||||||
new testVector(){{ Time = "000000000273EF07"; OTP = "91819424"; Mode = "HmacSHA256"; }},
|
{"000000000273EF07", "89005924", "HmacSHA1"},
|
||||||
new testVector(){{ Time = "000000000273EF07"; OTP = "93441116"; Mode = "HmacSHA512"; }},
|
{"000000000273EF07", "91819424", "HmacSHA256"},
|
||||||
new testVector(){{ Time = "0000000003F940AA"; OTP = "69279037"; Mode = "HmacSHA1"; }},
|
{"000000000273EF07", "93441116", "HmacSHA512"},
|
||||||
new testVector(){{ Time = "0000000003F940AA"; OTP = "90698825"; Mode = "HmacSHA256"; }},
|
{"0000000003F940AA", "69279037", "HmacSHA1"},
|
||||||
new testVector(){{ Time = "0000000003F940AA"; OTP = "38618901"; Mode = "HmacSHA512"; }},
|
{"0000000003F940AA", "90698825", "HmacSHA256"},
|
||||||
new testVector(){{ Time = "0000000027BC86AA"; OTP = "65353130"; Mode = "HmacSHA1"; }},
|
{"0000000003F940AA", "38618901", "HmacSHA512"},
|
||||||
new testVector(){{ Time = "0000000027BC86AA"; OTP = "77737706"; Mode = "HmacSHA256"; }},
|
{"0000000027BC86AA", "65353130", "HmacSHA1"},
|
||||||
new testVector(){{ Time = "0000000027BC86AA"; OTP = "47863826"; Mode = "HmacSHA512"; }}
|
{"0000000027BC86AA", "77737706", "HmacSHA256"},
|
||||||
|
{"0000000027BC86AA", "47863826", "HmacSHA512"}
|
||||||
};
|
};
|
||||||
|
|
||||||
private final byte[] _seed = new byte[] {
|
private final byte[] _seed = new byte[]{
|
||||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
|
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
|
||||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
|
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
|
||||||
};
|
};
|
||||||
|
|
||||||
private final byte[] _seed32 = new byte[] {
|
private final byte[] _seed32 = new byte[]{
|
||||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||||
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||||
0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
|
0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34,
|
||||||
0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32
|
0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32
|
||||||
};
|
};
|
||||||
|
|
||||||
private final byte[] _seed64 = new byte[] {
|
private final byte[] _seed64 = new byte[]{
|
||||||
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
|
||||||
0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
|
0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
|
||||||
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
|
||||||
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34
|
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34
|
||||||
};
|
};
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void vectorsMatch() throws Exception {
|
public void vectorsMatch() {
|
||||||
for (testVector v : _vectors) {
|
for (String[] vector : _vectors) {
|
||||||
byte[] seed;
|
byte[] seed;
|
||||||
|
|
||||||
switch (v.Mode) {
|
switch (vector[2]) {
|
||||||
case "HmacSHA1":
|
case "HmacSHA1":
|
||||||
seed = _seed;
|
seed = _seed;
|
||||||
break;
|
break;
|
||||||
|
@ -74,8 +69,8 @@ public class TOTPTest {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String otp = TOTP.generateTOTP(seed, v.Time, 8, v.Mode);
|
String otp = TOTP.generateTOTP(seed, vector[0], 8, vector[2]);
|
||||||
assertEquals(v.OTP, otp);
|
assertEquals(vector[1], otp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue