Clean things up a bit

This commit is contained in:
Alexander Bakker 2017-08-26 21:15:53 +02:00
parent 37e303626f
commit c0bdd261b5
24 changed files with 528 additions and 573 deletions

View file

@ -12,18 +12,18 @@ import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.TextView; import android.widget.TextView;
import me.impy.aegis.crypto.KeyInfo;
import me.impy.aegis.crypto.otp.OTP; import me.impy.aegis.crypto.otp.OTP;
public class AddProfileActivity extends AppCompatActivity { public class AddProfileActivity extends AppCompatActivity {
KeyProfile keyProfile; KeyProfile _keyProfile;
EditText profileName;
TextView tvAlgorithm;
TextView tvIssuer;
TextView tvPeriod;
TextView tvOtp;
EditText _profileName;
TextView _textAlgorithm;
TextView _textIssuer;
TextView _textPeriod;
TextView _textOtp;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -31,16 +31,16 @@ public class AddProfileActivity extends AppCompatActivity {
setPreferredTheme(); setPreferredTheme();
setContentView(R.layout.activity_add_profile); setContentView(R.layout.activity_add_profile);
profileName = (EditText) findViewById(R.id.addProfileName); _profileName = (EditText) findViewById(R.id.addProfileName);
tvAlgorithm = (TextView) findViewById(R.id.tvAlgorithm); _textAlgorithm = (TextView) findViewById(R.id.tvAlgorithm);
tvIssuer = (TextView) findViewById(R.id.tvIssuer); _textIssuer = (TextView) findViewById(R.id.tvIssuer);
tvPeriod = (TextView) findViewById(R.id.tvPeriod); _textPeriod = (TextView) findViewById(R.id.tvPeriod);
tvOtp = (TextView) findViewById(R.id.tvOtp); _textOtp = (TextView) findViewById(R.id.tvOtp);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false); getSupportActionBar().setDisplayShowTitleEnabled(false);
keyProfile = (KeyProfile)getIntent().getSerializableExtra("KeyProfile"); _keyProfile = (KeyProfile) getIntent().getSerializableExtra("KeyProfile");
initializeForm(); initializeForm();
@ -50,33 +50,33 @@ public class AddProfileActivity extends AppCompatActivity {
public void onClick(View view) { public void onClick(View view) {
Intent resultIntent = new Intent(); Intent resultIntent = new Intent();
keyProfile.Name = profileName.getText().toString(); _keyProfile.getEntry().setName(_profileName.getText().toString());
resultIntent.putExtra("KeyProfile", keyProfile); resultIntent.putExtra("KeyProfile", _keyProfile);
setResult(Activity.RESULT_OK, resultIntent); setResult(Activity.RESULT_OK, resultIntent);
finish(); finish();
} }
}); });
//profileName.setText(keyProfile.Info.getAccountName()); //_profileName.setText(_keyProfile.Info.getAccountName());
} }
private void initializeForm() private void initializeForm() {
{ KeyInfo info = _keyProfile.getEntry().getInfo();
profileName.setText(keyProfile.Info.getAccountName()); _profileName.setText(info.getAccountName());
tvAlgorithm.setText(keyProfile.Info.getAlgorithm()); _textAlgorithm.setText(info.getAlgorithm());
tvIssuer.setText(keyProfile.Info.getIssuer()); _textIssuer.setText(info.getIssuer());
tvPeriod.setText(keyProfile.Info.getPeriod() + " seconds"); _textPeriod.setText(info.getPeriod() + " seconds");
String otp; String otp;
try { try {
otp = OTP.generateOTP(keyProfile.Info); otp = OTP.generateOTP(info);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return; return;
} }
keyProfile.Code = otp; _keyProfile.setCode(otp);
tvOtp.setText(otp.substring(0, 3) + " " + otp.substring(3)); _textOtp.setText(otp.substring(0, 3) + " " + otp.substring(3));
} }
@Override @Override
@ -90,16 +90,12 @@ public class AddProfileActivity extends AppCompatActivity {
} }
} }
private void setPreferredTheme() {
private void setPreferredTheme()
{
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if(sharedPreferences.getBoolean("pref_night_mode", false)) if (sharedPreferences.getBoolean("pref_night_mode", false)) {
{ setTheme(R.style.AppTheme_Dark_TransparentActionBar);
setTheme(R.style.AppTheme_Dark_TransparentActionBar); } else {
} else setTheme(R.style.AppTheme_Default_TransparentActionBar);
{
setTheme(R.style.AppTheme_Default_TransparentActionBar);
} }
} }
} }

View file

@ -39,39 +39,36 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
public static final int RESULT_OK = 0; public static final int RESULT_OK = 0;
public static final int RESULT_EXCEPTION = 1; public static final int RESULT_EXCEPTION = 1;
private EditText textPassword; private EditText _textPassword;
private SlotCollection slots; private SlotCollection _slots;
private LinearLayout boxFingerprint; private FingerprintUiHelper _fingerHelper;
private SwirlView imgFingerprint; private Cipher _fingerCipher;
private TextView textFingerprint;
private FingerprintUiHelper fingerHelper;
private Cipher fingerCipher;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auth); setContentView(R.layout.activity_auth);
textPassword = (EditText) findViewById(R.id.text_password); _textPassword = (EditText) findViewById(R.id.text_password);
boxFingerprint = (LinearLayout) findViewById(R.id.box_fingerprint); LinearLayout boxFingerprint = (LinearLayout) findViewById(R.id.box_fingerprint);
imgFingerprint = (SwirlView) findViewById(R.id.img_fingerprint); SwirlView imgFingerprint = (SwirlView) findViewById(R.id.img_fingerprint);
textFingerprint = (TextView) findViewById(R.id.text_fingerprint); TextView textFingerprint = (TextView) findViewById(R.id.text_fingerprint);
Intent intent = getIntent(); Intent intent = getIntent();
slots = (SlotCollection) intent.getSerializableExtra("slots"); _slots = (SlotCollection) intent.getSerializableExtra("slots");
// only show the fingerprint controls if the api version is new enough, permission is granted, a scanner is found and a fingerprint slot is found // only show the fingerprint controls if the api version is new enough, permission is granted, a scanner is found and a fingerprint slot is found
Context context = getApplicationContext(); Context context = getApplicationContext();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
FingerprintManager manager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); FingerprintManager manager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED && manager.isHardwareDetected()) { if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED && manager.isHardwareDetected()) {
if (slots.has(FingerprintSlot.class)) { if (_slots.has(FingerprintSlot.class)) {
try { try {
KeyStoreHandle handle = new KeyStoreHandle(); KeyStoreHandle handle = new KeyStoreHandle();
if (handle.keyExists()) { if (handle.keyExists()) {
SecretKey key = handle.getKey(); SecretKey key = handle.getKey();
fingerCipher = Slot.createCipher(key, Cipher.DECRYPT_MODE); _fingerCipher = Slot.createCipher(key, Cipher.DECRYPT_MODE);
fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this); _fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this);
boxFingerprint.setVisibility(View.VISIBLE); boxFingerprint.setVisibility(View.VISIBLE);
} }
} catch (Exception e) { } catch (Exception e) {
@ -104,25 +101,25 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
} }
private MasterKey decryptPasswordSlot(PasswordSlot slot) throws Exception { private MasterKey decryptPasswordSlot(PasswordSlot slot) throws Exception {
char[] password = AuthHelper.getPassword(textPassword, true); char[] password = AuthHelper.getPassword(_textPassword, true);
SecretKey key = slot.deriveKey(password); SecretKey key = slot.deriveKey(password);
CryptoUtils.zero(password); CryptoUtils.zero(password);
Cipher cipher = Slot.createCipher(key, Cipher.DECRYPT_MODE); Cipher cipher = Slot.createCipher(key, Cipher.DECRYPT_MODE);
return slots.decrypt(slot, cipher); return _slots.decrypt(slot, cipher);
} }
private MasterKey decryptFingerSlot(FingerprintSlot slot) throws Exception { private MasterKey decryptFingerSlot(FingerprintSlot slot) throws Exception {
return slots.decrypt(slot, fingerCipher); return _slots.decrypt(slot, _fingerCipher);
} }
private <T extends Slot> void trySlots(Class<T> type) { private <T extends Slot> void trySlots(Class<T> type) {
try { try {
if (!slots.has(type)) { if (!_slots.has(type)) {
throw new RuntimeException(); throw new RuntimeException();
} }
MasterKey masterKey = null; MasterKey masterKey = null;
for (Slot slot : slots.findAll(type)) { for (Slot slot : _slots.findAll(type)) {
try { try {
if (slot instanceof PasswordSlot) { if (slot instanceof PasswordSlot) {
masterKey = decryptPasswordSlot((PasswordSlot) slot); masterKey = decryptPasswordSlot((PasswordSlot) slot);
@ -132,8 +129,7 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
throw new RuntimeException(); throw new RuntimeException();
} }
break; break;
} catch (SlotIntegrityException e) { } catch (SlotIntegrityException e) { }
}
} }
if (masterKey == null) { if (masterKey == null) {
@ -165,8 +161,8 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
public void onResume() { public void onResume() {
super.onResume(); super.onResume();
if (fingerHelper != null) { if (_fingerHelper != null) {
fingerHelper.startListening(new FingerprintManager.CryptoObject(fingerCipher)); _fingerHelper.startListening(new FingerprintManager.CryptoObject(_fingerCipher));
} }
} }
@ -174,8 +170,8 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
if (fingerHelper != null) { if (_fingerHelper != null) {
fingerHelper.stopListening(); _fingerHelper.stopListening();
} }
} }

View file

@ -31,96 +31,91 @@ import me.impy.aegis.finger.FingerprintUiHelper;
import me.impy.aegis.helpers.AuthHelper; import me.impy.aegis.helpers.AuthHelper;
public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiHelper.Callback, ISlidePolicy, ISlideSelectionListener { public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiHelper.Callback, ISlidePolicy, ISlideSelectionListener {
private int cryptType; private int _cryptType;
private EditText textPassword; private EditText _textPassword;
private EditText textPasswordConfirm; private EditText _textPasswordConfirm;
private int bgColor; private int _bgColor;
private LinearLayout boxFingerprint; private LinearLayout _boxFingerprint;
private SwirlView imgFingerprint; private SwirlView _imgFingerprint;
private TextView textFingerprint; private TextView _textFingerprint;
private FingerprintUiHelper fingerHelper; private FingerprintUiHelper _fingerHelper;
private KeyStoreHandle storeHandle; private KeyStoreHandle _storeHandle;
private Cipher fingerCipher; private Cipher _fingerCipher;
private boolean fingerAuthenticated; private boolean _fingerAuthenticated;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_authenticated_slide, container, false); final View view = inflater.inflate(R.layout.fragment_authenticated_slide, container, false);
textPassword = (EditText) view.findViewById(R.id.text_password); _textPassword = (EditText) view.findViewById(R.id.text_password);
textPasswordConfirm = (EditText) view.findViewById(R.id.text_password_confirm); _textPasswordConfirm = (EditText) view.findViewById(R.id.text_password_confirm);
boxFingerprint = (LinearLayout) view.findViewById(R.id.box_fingerprint); _boxFingerprint = (LinearLayout) view.findViewById(R.id.box_fingerprint);
imgFingerprint = (SwirlView) view.findViewById(R.id.img_fingerprint); _imgFingerprint = (SwirlView) view.findViewById(R.id.img_fingerprint);
textFingerprint = (TextView) view.findViewById(R.id.text_fingerprint); _textFingerprint = (TextView) view.findViewById(R.id.text_fingerprint);
view.findViewById(R.id.main).setBackgroundColor(bgColor); view.findViewById(R.id.main).setBackgroundColor(_bgColor);
return view; return view;
} }
/*@Override
public int buttonsColor() {
return R.color.colorAccent;
}*/
public int getCryptType() { public int getCryptType() {
return cryptType; return _cryptType;
} }
public Cipher getCipher(Slot slot) throws Exception { public Cipher getCipher(Slot slot) throws Exception {
if (slot instanceof PasswordSlot) { if (slot instanceof PasswordSlot) {
char[] password = AuthHelper.getPassword(textPassword, true); char[] password = AuthHelper.getPassword(_textPassword, true);
byte[] salt = CryptoUtils.generateSalt(); byte[] salt = CryptoUtils.generateSalt();
SecretKey key = ((PasswordSlot)slot).deriveKey(password, salt, CryptoUtils.CRYPTO_SCRYPT_N, CryptoUtils.CRYPTO_SCRYPT_r, CryptoUtils.CRYPTO_SCRYPT_p); SecretKey key = ((PasswordSlot)slot).deriveKey(password, salt, CryptoUtils.CRYPTO_SCRYPT_N, CryptoUtils.CRYPTO_SCRYPT_r, CryptoUtils.CRYPTO_SCRYPT_p);
CryptoUtils.zero(password); CryptoUtils.zero(password);
return Slot.createCipher(key, Cipher.ENCRYPT_MODE); return Slot.createCipher(key, Cipher.ENCRYPT_MODE);
} else if (slot instanceof FingerprintSlot) { } else if (slot instanceof FingerprintSlot) {
return fingerCipher; return _fingerCipher;
} else { } else {
throw new RuntimeException(); throw new RuntimeException();
} }
} }
public void setBgColor(int color) { public void setBgColor(int color) {
bgColor = color; _bgColor = color;
} }
@Override @Override
public void onSlideSelected() { public void onSlideSelected() {
Intent intent = getActivity().getIntent(); Intent intent = getActivity().getIntent();
cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID); _cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID);
switch(cryptType) { switch(_cryptType) {
case CustomAuthenticationSlide.CRYPT_TYPE_NONE: case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
case CustomAuthenticationSlide.CRYPT_TYPE_PASS: case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
break; break;
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER: case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
boxFingerprint.setVisibility(View.VISIBLE); _boxFingerprint.setVisibility(View.VISIBLE);
SecretKey key; SecretKey key;
try { try {
if (storeHandle == null) { if (_storeHandle == null) {
storeHandle = new KeyStoreHandle(); _storeHandle = new KeyStoreHandle();
} }
// TODO: consider regenerating the key if it exists // TODO: consider regenerating the key if it exists
if (!storeHandle.keyExists()) { if (!_storeHandle.keyExists()) {
key = storeHandle.generateKey(true); key = _storeHandle.generateKey(true);
} else { } else {
key = storeHandle.getKey(); key = _storeHandle.getKey();
} }
} catch (Exception e) { } catch (Exception e) {
throw new UndeclaredThrowableException(e); throw new UndeclaredThrowableException(e);
} }
if (fingerHelper == null) { if (_fingerHelper == null) {
FingerprintManager fingerManager = (FingerprintManager) getContext().getSystemService(Context.FINGERPRINT_SERVICE); FingerprintManager fingerManager = (FingerprintManager) getContext().getSystemService(Context.FINGERPRINT_SERVICE);
fingerHelper = new FingerprintUiHelper(fingerManager, imgFingerprint, textFingerprint, this); _fingerHelper = new FingerprintUiHelper(fingerManager, _imgFingerprint, _textFingerprint, this);
} }
try { try {
fingerCipher = Slot.createCipher(key, Cipher.ENCRYPT_MODE); _fingerCipher = Slot.createCipher(key, Cipher.ENCRYPT_MODE);
} catch (Exception e) { } catch (Exception e) {
throw new UndeclaredThrowableException(e); throw new UndeclaredThrowableException(e);
} }
fingerHelper.startListening(new FingerprintManager.CryptoObject(fingerCipher)); _fingerHelper.startListening(new FingerprintManager.CryptoObject(_fingerCipher));
break; break;
default: default:
throw new RuntimeException(); throw new RuntimeException();
@ -129,25 +124,25 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
@Override @Override
public void onSlideDeselected() { public void onSlideDeselected() {
if (fingerHelper != null) { if (_fingerHelper != null) {
fingerAuthenticated = false; _fingerAuthenticated = false;
boxFingerprint.setVisibility(View.INVISIBLE); _boxFingerprint.setVisibility(View.INVISIBLE);
fingerHelper.stopListening(); _fingerHelper.stopListening();
} }
} }
@Override @Override
public boolean isPolicyRespected() { public boolean isPolicyRespected() {
switch(cryptType) { switch(_cryptType) {
case CustomAuthenticationSlide.CRYPT_TYPE_NONE: case CustomAuthenticationSlide.CRYPT_TYPE_NONE:
return true; return true;
case CustomAuthenticationSlide.CRYPT_TYPE_FINGER: case CustomAuthenticationSlide.CRYPT_TYPE_FINGER:
if (!fingerAuthenticated) { if (!_fingerAuthenticated) {
return false; return false;
} }
// intentional fallthrough // intentional fallthrough
case CustomAuthenticationSlide.CRYPT_TYPE_PASS: case CustomAuthenticationSlide.CRYPT_TYPE_PASS:
return AuthHelper.arePasswordsEqual(textPassword, textPasswordConfirm); return AuthHelper.arePasswordsEqual(_textPassword, _textPasswordConfirm);
default: default:
throw new RuntimeException(); throw new RuntimeException();
} }
@ -156,9 +151,9 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
@Override @Override
public void onUserIllegallyRequestedNextPage() { public void onUserIllegallyRequestedNextPage() {
String message; String message;
if (!AuthHelper.arePasswordsEqual(textPassword, textPasswordConfirm)) { if (!AuthHelper.arePasswordsEqual(_textPassword, _textPasswordConfirm)) {
message = "Passwords should be equal and non-empty"; message = "Passwords should be equal and non-empty";
} else if (!fingerAuthenticated) { } else if (!_fingerAuthenticated) {
message = "Register your fingerprint"; message = "Register your fingerprint";
} else { } else {
return; return;
@ -173,7 +168,7 @@ public class CustomAuthenticatedSlide extends Fragment implements FingerprintUiH
@Override @Override
public void onAuthenticated() { public void onAuthenticated() {
fingerAuthenticated = true; _fingerAuthenticated = true;
} }
@Override @Override

View file

@ -25,16 +25,16 @@ public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy
public static final int CRYPT_TYPE_PASS = 2; public static final int CRYPT_TYPE_PASS = 2;
public static final int CRYPT_TYPE_FINGER = 3; public static final int CRYPT_TYPE_FINGER = 3;
private RadioGroup buttonGroup; private RadioGroup _buttonGroup;
private int bgColor; private int _bgColor;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final View view = inflater.inflate(R.layout.fragment_authentication_slide, container, false); final View view = inflater.inflate(R.layout.fragment_authentication_slide, container, false);
final Context context = getContext(); final Context context = getContext();
buttonGroup = (RadioGroup) view.findViewById(R.id.rg_authenticationMethod); _buttonGroup = (RadioGroup) view.findViewById(R.id.rg_authenticationMethod);
buttonGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { _buttonGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override @Override
public void onCheckedChanged(RadioGroup group, int checkedId) { public void onCheckedChanged(RadioGroup group, int checkedId) {
if (checkedId == -1) { if (checkedId == -1) {
@ -71,17 +71,17 @@ public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy
} }
} }
view.findViewById(R.id.main).setBackgroundColor(bgColor); view.findViewById(R.id.main).setBackgroundColor(_bgColor);
return view; return view;
} }
public void setBgColor(int color) { public void setBgColor(int color) {
bgColor = color; _bgColor = color;
} }
@Override @Override
public boolean isPolicyRespected() { public boolean isPolicyRespected() {
return buttonGroup.getCheckedRadioButtonId() != -1; return _buttonGroup.getCheckedRadioButtonId() != -1;
} }
@Override @Override
@ -89,9 +89,4 @@ public class CustomAuthenticationSlide extends Fragment implements ISlidePolicy
Snackbar snackbar = Snackbar.make(getView(), "Please select an authentication method", Snackbar.LENGTH_LONG); Snackbar snackbar = Snackbar.make(getView(), "Please select an authentication method", Snackbar.LENGTH_LONG);
snackbar.show(); snackbar.show();
} }
/*@Override
public int buttonsColor() {
return R.color.colorAccent;
}*/
} }

View file

@ -9,24 +9,15 @@ import android.view.ViewGroup;
import android.widget.LinearLayout; import android.widget.LinearLayout;
public class EditProfileBottomSheetdialog extends BottomSheetDialogFragment { public class EditProfileBottomSheetdialog extends BottomSheetDialogFragment {
LinearLayout copyLayout; LinearLayout _copyLayout;
public static EditProfileBottomSheetdialog getInstance() { public static EditProfileBottomSheetdialog getInstance() {
return new EditProfileBottomSheetdialog(); return new EditProfileBottomSheetdialog();
} }
/* @Override
public void setupDialog(Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.bottom_sheet_edit_profile, null);
dialog.setContentView(contentView);
copyLayout = (LinearLayout)contentView.findViewById(R.id.copy_button);
}*/
public LinearLayout GetCopyLayout() public LinearLayout GetCopyLayout()
{ {
return copyLayout; return _copyLayout;
} }
@Nullable @Nullable

View file

@ -25,9 +25,9 @@ public class IntroActivity extends AppIntro {
public static final int RESULT_OK = 0; public static final int RESULT_OK = 0;
public static final int RESULT_EXCEPTION = 1; public static final int RESULT_EXCEPTION = 1;
private CustomAuthenticatedSlide authenticatedSlide; private CustomAuthenticatedSlide _authenticatedSlide;
private CustomAuthenticationSlide authenticationSlide; private CustomAuthenticationSlide _authenticationSlide;
private Fragment endSlide; private Fragment _endSlide;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@ -51,20 +51,20 @@ public class IntroActivity extends AppIntro {
addSlide(AppIntroFragment.newInstance(permSliderPage)); addSlide(AppIntroFragment.newInstance(permSliderPage));
askForPermissions(new String[]{Manifest.permission.CAMERA}, 2); askForPermissions(new String[]{Manifest.permission.CAMERA}, 2);
authenticationSlide = new CustomAuthenticationSlide(); _authenticationSlide = new CustomAuthenticationSlide();
authenticationSlide.setBgColor(getResources().getColor(R.color.colorHeaderSuccess)); _authenticationSlide.setBgColor(getResources().getColor(R.color.colorHeaderSuccess));
addSlide(authenticationSlide); addSlide(_authenticationSlide);
authenticatedSlide = new CustomAuthenticatedSlide(); _authenticatedSlide = new CustomAuthenticatedSlide();
authenticatedSlide.setBgColor(getResources().getColor(R.color.colorPrimary)); _authenticatedSlide.setBgColor(getResources().getColor(R.color.colorPrimary));
addSlide(authenticatedSlide); addSlide(_authenticatedSlide);
SliderPage endSliderPage = new SliderPage(); SliderPage endSliderPage = new SliderPage();
endSliderPage.setTitle("All done!"); endSliderPage.setTitle("All done!");
endSliderPage.setDescription("Aegis has been set up and is ready to go."); endSliderPage.setDescription("Aegis has been set up and is ready to go.");
endSliderPage.setImageDrawable(R.drawable.intro_shield); endSliderPage.setImageDrawable(R.drawable.intro_shield);
endSliderPage.setBgColor(getResources().getColor(R.color.colorPrimary)); endSliderPage.setBgColor(getResources().getColor(R.color.colorPrimary));
endSlide = AppIntroFragment.newInstance(endSliderPage); _endSlide = AppIntroFragment.newInstance(endSliderPage);
addSlide(endSlide); addSlide(_endSlide);
} }
private void setException(Exception e) { private void setException(Exception e) {
@ -77,7 +77,7 @@ public class IntroActivity extends AppIntro {
@Override @Override
public void onSlideChanged(Fragment oldFragment, Fragment newFragment) { public void onSlideChanged(Fragment oldFragment, Fragment newFragment) {
// skip to the last slide if no encryption will be used // skip to the last slide if no encryption will be used
if (oldFragment == authenticationSlide && newFragment != endSlide) { if (oldFragment == _authenticationSlide && newFragment != _endSlide) {
Intent intent = getIntent(); Intent intent = getIntent();
int cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID); int cryptType = intent.getIntExtra("cryptType", CustomAuthenticationSlide.CRYPT_TYPE_INVALID);
if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) { if (cryptType == CustomAuthenticationSlide.CRYPT_TYPE_NONE) {
@ -95,7 +95,7 @@ public class IntroActivity extends AppIntro {
Database database = new Database(); Database database = new Database();
DatabaseFile databaseFile = new DatabaseFile(); DatabaseFile databaseFile = new DatabaseFile();
int cryptType = authenticatedSlide.getCryptType(); int cryptType = _authenticatedSlide.getCryptType();
// generate the master key // generate the master key
MasterKey masterKey = null; MasterKey masterKey = null;
@ -114,7 +114,7 @@ public class IntroActivity extends AppIntro {
// encrypt the master key with a key derived from the user's password // encrypt the master key with a key derived from the user's password
// and add it to the list of slots // and add it to the list of slots
PasswordSlot slot = new PasswordSlot(); PasswordSlot slot = new PasswordSlot();
Cipher cipher = authenticatedSlide.getCipher(slot); Cipher cipher = _authenticatedSlide.getCipher(slot);
slots.encrypt(slot, masterKey, cipher); slots.encrypt(slot, masterKey, cipher);
slots.add(slot); slots.add(slot);
} catch (Exception e) { } catch (Exception e) {
@ -128,7 +128,7 @@ public class IntroActivity extends AppIntro {
// encrypt the master key with the fingerprint key // encrypt the master key with the fingerprint key
// and add it to the list of slots // and add it to the list of slots
FingerprintSlot slot = new FingerprintSlot(); FingerprintSlot slot = new FingerprintSlot();
Cipher cipher = authenticatedSlide.getCipher(slot); Cipher cipher = _authenticatedSlide.getCipher(slot);
slots.encrypt(slot, masterKey, cipher); slots.encrypt(slot, masterKey, cipher);
slots.add(slot); slots.add(slot);
} catch (Exception e) { } catch (Exception e) {

View file

@ -2,22 +2,24 @@ package me.impy.aegis;
import java.io.Serializable; import java.io.Serializable;
import me.impy.aegis.crypto.KeyInfo; import me.impy.aegis.db.DatabaseEntry;
public class KeyProfile implements Serializable { public class KeyProfile implements Serializable {
public String Name; private String _code;
public String Icon; private DatabaseEntry _entry;
public String Code;
public String Issuer;
public KeyInfo Info;
public int Order;
public int ID;
public int compareTo(KeyProfile another) { public KeyProfile(DatabaseEntry entry) {
if (this.Order>another.Order){ _entry = entry;
return -1; }
}else{
return 1; public DatabaseEntry getEntry() {
} return _entry;
}
public String getCode() {
return _code;
}
public void setCode(String code) {
_code = code;
} }
} }

View file

@ -26,34 +26,34 @@ import me.impy.aegis.crypto.otp.OTP;
import me.impy.aegis.helpers.ItemTouchHelperAdapter; import me.impy.aegis.helpers.ItemTouchHelperAdapter;
public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileAdapter.KeyProfileHolder> implements ItemTouchHelperAdapter { public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileAdapter.KeyProfileHolder> implements ItemTouchHelperAdapter {
private final List<KeyProfileHolder> lstHolders; private final List<KeyProfileHolder> _holders;
private ArrayList<KeyProfile> mKeyProfiles; private ArrayList<KeyProfile> _keyProfiles;
private Handler uiHandler; private Handler _uiHandler;
private static ItemClickListener itemClickListener; private static ItemClickListener _itemClickListener;
private static LongItemClickListener longItemClickListener; private static LongItemClickListener _longItemClickListener;
public KeyProfileAdapter(ArrayList<KeyProfile> keyProfiles) { public KeyProfileAdapter(ArrayList<KeyProfile> keyProfiles) {
mKeyProfiles = keyProfiles; _keyProfiles = keyProfiles;
lstHolders = new ArrayList<>(); _holders = new ArrayList<>();
uiHandler = new Handler(); _uiHandler = new Handler();
} }
@Override @Override
public void onItemDismiss(int position) { public void onItemDismiss(int position) {
return;
} }
private void remove(int position) { private void remove(int position) {
mKeyProfiles.remove(position); _keyProfiles.remove(position);
notifyItemRemoved(position); notifyItemRemoved(position);
} }
@Override @Override
public void onItemMove(int firstPosition, int secondPosition) { public void onItemMove(int firstPosition, int secondPosition) {
Collections.swap(mKeyProfiles, firstPosition, secondPosition); Collections.swap(_keyProfiles, firstPosition, secondPosition);
notifyItemMoved(firstPosition, secondPosition); notifyItemMoved(firstPosition, secondPosition);
mKeyProfiles.get(firstPosition).Order = secondPosition; _keyProfiles.get(firstPosition).getEntry().setOrder(secondPosition);
adjustOrder(secondPosition); adjustOrder(secondPosition);
} }
@ -61,12 +61,12 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileAdapter.Ke
Comparator<KeyProfile> comparator = new Comparator<KeyProfile>() { Comparator<KeyProfile> comparator = new Comparator<KeyProfile>() {
@Override @Override
public int compare(KeyProfile keyProfile, KeyProfile t1) { public int compare(KeyProfile keyProfile, KeyProfile t1) {
return keyProfile.Order - t1.Order; return keyProfile.getEntry().getOrder() - t1.getEntry().getOrder();
} }
}; };
for (int i = startPosition; i < mKeyProfiles.size(); i++) { for (int i = startPosition; i < _keyProfiles.size(); i++) {
mKeyProfiles.get(i).Order = i + 1; _keyProfiles.get(i).getEntry().setOrder(i + 1);
} }
} }
@ -79,130 +79,127 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileAdapter.Ke
@Override @Override
public void onBindViewHolder(final KeyProfileHolder holder, int position) { public void onBindViewHolder(final KeyProfileHolder holder, int position) {
holder.setData(mKeyProfiles.get(position)); holder.setData(_keyProfiles.get(position));
holder.updateCode(); holder.updateCode();
lstHolders.add(holder); _holders.add(holder);
Runnable runnable = new Runnable() { Runnable runnable = new Runnable() {
@Override @Override
public void run() { public void run() {
// check if this key profile still exists // check if this key profile still exists
if (lstHolders.contains(holder)) { if (_holders.contains(holder)) {
holder.updateCode(); holder.updateCode();
} }
uiHandler.postDelayed(this, holder.keyProfile.Info.getPeriod() * 1000); _uiHandler.postDelayed(this, holder._keyProfile.getEntry().getInfo().getPeriod() * 1000);
} }
}; };
uiHandler.postDelayed(runnable, holder.keyProfile.Info.getMillisTillNextRotation()); _uiHandler.postDelayed(runnable, holder._keyProfile.getEntry().getInfo().getMillisTillNextRotation());
} }
@Override @Override
public int getItemCount() { public int getItemCount() {
return mKeyProfiles.size(); return _keyProfiles.size();
} }
public static class KeyProfileHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener { public static class KeyProfileHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView profileName; TextView _profileName;
TextView profileCode; TextView _profileCode;
TextView profileIssuer; TextView _profileIssuer;
ImageView profileDrawable; ImageView _profileDrawable;
KeyProfile keyProfile; KeyProfile _keyProfile;
ProgressBar progressBar; ProgressBar _progressBar;
View _itemView; View _itemView;
KeyProfileHolder(final View itemView) { KeyProfileHolder(final View itemView) {
super(itemView); super(itemView);
_itemView = itemView; _itemView = itemView;
profileName = (TextView) itemView.findViewById(R.id.profile_name); _profileName = (TextView) itemView.findViewById(R.id.profile_name);
profileCode = (TextView) itemView.findViewById(R.id.profile_code); _profileCode = (TextView) itemView.findViewById(R.id.profile_code);
profileIssuer = (TextView) itemView.findViewById(R.id.profile_issuer); _profileIssuer = (TextView) itemView.findViewById(R.id.profile_issuer);
profileDrawable = (ImageView) itemView.findViewById(R.id.ivTextDrawable); _profileDrawable = (ImageView) itemView.findViewById(R.id.ivTextDrawable);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar); _progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar);
itemView.setOnClickListener(this); itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this); itemView.setOnLongClickListener(this);
} }
public void setData(KeyProfile profile) { public void setData(KeyProfile profile) {
this.keyProfile = profile; _keyProfile = profile;
profileName.setText(profile.Name); _profileName.setText(profile.getEntry().getName());
profileCode.setText(profile.Code); _profileCode.setText(profile.getCode());
// So that we can have text in the designer without showing it to our user // So that we can have text in the designer without showing it to our user
profileIssuer.setText(""); _profileIssuer.setText("");
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(_itemView.getContext()); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(_itemView.getContext());
if(sharedPreferences.getBoolean("pref_issuer", false)) if(sharedPreferences.getBoolean("pref_issuer", false))
{ {
profileIssuer.setText(" - " + profile.Info.getIssuer()); _profileIssuer.setText(" - " + profile.getEntry().getInfo().getIssuer());
} }
profileDrawable.setImageDrawable(generateTextDrawable(profile)); _profileDrawable.setImageDrawable(generateTextDrawable(profile));
} }
public void updateCode() { public void updateCode() {
progressBar.setProgress(1000); _progressBar.setProgress(1000);
if (this.keyProfile == null) { if (_keyProfile == null) {
return; return;
} }
String otp = ""; String otp = "";
try { try {
otp = OTP.generateOTP(this.keyProfile.Info); otp = OTP.generateOTP(_keyProfile.getEntry().getInfo());
} catch (Exception e) { } catch (Exception e) {
throw new UndeclaredThrowableException(e); throw new UndeclaredThrowableException(e);
} }
this.keyProfile.Code = otp; _keyProfile.setCode(otp);
profileCode.setText(otp.substring(0, 3) + " " + otp.substring(3)); _profileCode.setText(otp.substring(0, 3) + " " + otp.substring(3));
long millisTillRotation = keyProfile.Info.getMillisTillNextRotation(); long millisTillRotation = _keyProfile.getEntry().getInfo().getMillisTillNextRotation();
long period = keyProfile.Info.getPeriod() * 1000; long period = _keyProfile.getEntry().getInfo().getPeriod() * 1000;
int currentProgress = 1000 - (int) ((((double) period - millisTillRotation) / period) * 1000); int currentProgress = 1000 - (int) ((((double) period - millisTillRotation) / period) * 1000);
ObjectAnimator animation = ObjectAnimator.ofInt(progressBar, "progress", currentProgress, 0); ObjectAnimator animation = ObjectAnimator.ofInt(_progressBar, "progress", currentProgress, 0);
animation.setDuration(millisTillRotation); animation.setDuration(millisTillRotation);
animation.setInterpolator(new LinearInterpolator()); animation.setInterpolator(new LinearInterpolator());
animation.start(); animation.start();
} }
private TextDrawable generateTextDrawable(KeyProfile profile) { private TextDrawable generateTextDrawable(KeyProfile profile) {
if (profileName == null) if (_profileName == null)
return null; return null;
ColorGenerator generator = ColorGenerator.MATERIAL; ColorGenerator generator = ColorGenerator.MATERIAL;
int profileKeyColor = generator.getColor(profile.Name); int profileKeyColor = generator.getColor(profile.getEntry().getName());
TextDrawable newDrawable = TextDrawable.builder().buildRound(profile.Name.substring(0, 1).toUpperCase(), profileKeyColor); return TextDrawable.builder().buildRound(profile.getEntry().getName().substring(0, 1).toUpperCase(), profileKeyColor);
return newDrawable;
} }
@Override @Override
public void onClick(View view) { public void onClick(View view) {
itemClickListener.onItemClick(getAdapterPosition(), view); _itemClickListener.onItemClick(getAdapterPosition(), view);
} }
@Override @Override
public boolean onLongClick(View view) { public boolean onLongClick(View view) {
longItemClickListener.onLongItemClick(getAdapterPosition(), view); _longItemClickListener.onLongItemClick(getAdapterPosition(), view);
return true; return true;
} }
} }
public void setOnItemClickListener(ItemClickListener clickListener) { public void setOnItemClickListener(ItemClickListener clickListener) {
KeyProfileAdapter.itemClickListener = clickListener; KeyProfileAdapter._itemClickListener = clickListener;
} }
public void setOnLongItemClickListener(LongItemClickListener clickListener) { public void setOnLongItemClickListener(LongItemClickListener clickListener) {
KeyProfileAdapter.longItemClickListener = clickListener; KeyProfileAdapter._longItemClickListener = clickListener;
} }
public interface ItemClickListener public interface ItemClickListener {
{
void onItemClick(int position, View v); void onItemClick(int position, View v);
} }
public interface LongItemClickListener public interface LongItemClickListener {
{
void onLongItemClick(int position, View v); void onLongItemClick(int position, View v);
} }
} }

View file

@ -26,19 +26,17 @@ import android.view.View;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.Toast; import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.reflect.UndeclaredThrowableException; import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function;
import me.impy.aegis.crypto.MasterKey; import me.impy.aegis.crypto.MasterKey;
import me.impy.aegis.crypto.otp.OTP; import me.impy.aegis.crypto.otp.OTP;
import me.impy.aegis.db.DatabaseEntry;
import me.impy.aegis.db.DatabaseManager; import me.impy.aegis.db.DatabaseManager;
import me.impy.aegis.ext.FreeOTPImporter; import me.impy.aegis.ext.FreeOTPImporter;
import me.impy.aegis.helpers.SimpleItemTouchHelperCallback; import me.impy.aegis.helpers.SimpleItemTouchHelperCallback;
@ -50,18 +48,19 @@ public class MainActivity extends AppCompatActivity {
private static final int CODE_DECRYPT = 3; private static final int CODE_DECRYPT = 3;
private static final int CODE_IMPORT = 4; private static final int CODE_IMPORT = 4;
RecyclerView rvKeyProfiles; private KeyProfileAdapter _keyProfileAdapter;
KeyProfileAdapter mKeyProfileAdapter; private ArrayList<KeyProfile> _keyProfiles = new ArrayList<>();
ArrayList<KeyProfile> mKeyProfiles = new ArrayList<>(); private DatabaseManager _db;
private DatabaseManager db;
boolean nightMode = false; private boolean _nightMode = false;
int clickedItemPosition = -1; private int _clickedItemPosition = -1;
private Menu _menu;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
db = new DatabaseManager(getApplicationContext()); _db = new DatabaseManager(getApplicationContext());
SharedPreferences prefs = this.getSharedPreferences("me.impy.aegis", Context.MODE_PRIVATE); SharedPreferences prefs = this.getSharedPreferences("me.impy.aegis", Context.MODE_PRIVATE);
if (!prefs.getBoolean("passedIntro", false)) { if (!prefs.getBoolean("passedIntro", false)) {
@ -69,14 +68,14 @@ public class MainActivity extends AppCompatActivity {
startActivityForResult(intro, CODE_DO_INTRO); startActivityForResult(intro, CODE_DO_INTRO);
} else { } else {
try { try {
db.load(); _db.load();
} catch (Exception e) { } catch (Exception e) {
// TODO: feedback // TODO: feedback
throw new UndeclaredThrowableException(e); throw new UndeclaredThrowableException(e);
} }
if (!db.isDecrypted()) { if (!_db.isDecrypted()) {
Intent intent = new Intent(this, AuthActivity.class); Intent intent = new Intent(this, AuthActivity.class);
intent.putExtra("slots", db.getFile().getSlots()); intent.putExtra("slots", _db.getFile().getSlots());
startActivityForResult(intent, CODE_DECRYPT); startActivityForResult(intent, CODE_DECRYPT);
} else { } else {
loadKeyProfiles(); loadKeyProfiles();
@ -85,7 +84,7 @@ public class MainActivity extends AppCompatActivity {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPreferences.getBoolean("pref_night_mode", false)) { if (sharedPreferences.getBoolean("pref_night_mode", false)) {
nightMode = true; _nightMode = true;
setTheme(R.style.AppTheme_Dark_NoActionBar); setTheme(R.style.AppTheme_Dark_NoActionBar);
} else { } else {
setPreferredTheme(); setPreferredTheme();
@ -102,31 +101,31 @@ public class MainActivity extends AppCompatActivity {
startActivityForResult(scannerActivity, CODE_GET_KEYINFO); startActivityForResult(scannerActivity, CODE_GET_KEYINFO);
}); });
rvKeyProfiles = (RecyclerView) findViewById(R.id.rvKeyProfiles); RecyclerView rvKeyProfiles = (RecyclerView) findViewById(R.id.rvKeyProfiles);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this); LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
rvKeyProfiles.setLayoutManager(mLayoutManager); rvKeyProfiles.setLayoutManager(mLayoutManager);
mKeyProfileAdapter = new KeyProfileAdapter(mKeyProfiles); _keyProfileAdapter = new KeyProfileAdapter(_keyProfiles);
mKeyProfileAdapter.setOnItemClickListener((position, v) -> { _keyProfileAdapter.setOnItemClickListener((position, v) -> {
clickedItemPosition = position; _clickedItemPosition = position;
InitializeBottomSheet().show(); InitializeBottomSheet().show();
}); });
mKeyProfileAdapter.setOnLongItemClickListener((position, v) -> { _keyProfileAdapter.setOnLongItemClickListener((position, v) -> {
}); });
ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(mKeyProfileAdapter); ItemTouchHelper.Callback callback = new SimpleItemTouchHelperCallback(_keyProfileAdapter);
ItemTouchHelper touchHelper = new ItemTouchHelper(callback); ItemTouchHelper touchHelper = new ItemTouchHelper(callback);
touchHelper.attachToRecyclerView(rvKeyProfiles); touchHelper.attachToRecyclerView(rvKeyProfiles);
rvKeyProfiles.setAdapter(mKeyProfileAdapter); rvKeyProfiles.setAdapter(_keyProfileAdapter);
Comparator<KeyProfile> comparator = new Comparator<KeyProfile>() { Comparator<KeyProfile> comparator = new Comparator<KeyProfile>() {
@Override @Override
public int compare(KeyProfile keyProfile, KeyProfile t1) { public int compare(KeyProfile keyProfile, KeyProfile t1) {
return keyProfile.Order - t1.Order; return keyProfile.getEntry().getOrder() - t1.getEntry().getOrder();
} }
}; };
Collections.sort(mKeyProfiles, comparator); Collections.sort(_keyProfiles, comparator);
} }
@Override @Override
@ -151,6 +150,10 @@ public class MainActivity extends AppCompatActivity {
} }
private void onImportResult(int resultCode, Intent data) { private void onImportResult(int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
InputStream stream = null; InputStream stream = null;
try { try {
try { try {
@ -162,8 +165,8 @@ public class MainActivity extends AppCompatActivity {
FreeOTPImporter importer = new FreeOTPImporter(stream); FreeOTPImporter importer = new FreeOTPImporter(stream);
try { try {
for (KeyProfile profile : importer.convert()) { for (DatabaseEntry profile : importer.convert()) {
addKey(profile); addKey(new KeyProfile(profile));
} }
} catch (Exception e) { } catch (Exception e) {
Toast.makeText(this, "An error occurred while trying to parse the file", Toast.LENGTH_SHORT).show(); Toast.makeText(this, "An error occurred while trying to parse the file", Toast.LENGTH_SHORT).show();
@ -171,8 +174,10 @@ public class MainActivity extends AppCompatActivity {
} }
} finally { } finally {
if (stream != null) { if (stream != null) {
try { stream.close(); } try {
catch (Exception e) { } stream.close();
} catch (Exception e) {
}
} }
} }
@ -203,27 +208,29 @@ public class MainActivity extends AppCompatActivity {
} }
private void addKey(KeyProfile profile) { private void addKey(KeyProfile profile) {
DatabaseEntry entry = profile.getEntry();
String otp; String otp;
try { try {
otp = OTP.generateOTP(profile.Info); otp = OTP.generateOTP(entry.getInfo());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
return; return;
} }
profile.Name = profile.Info.getAccountName(); entry.setName(entry.getInfo().getAccountName());
profile.Order = mKeyProfiles.size() + 1; entry.setOrder(_keyProfiles.size() + 1);
profile.Code = otp; profile.setCode(otp);
try { try {
db.addKey(profile); _db.addKey(entry);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
// TODO: feedback // TODO: feedback
return; return;
} }
mKeyProfiles.add(profile); _keyProfiles.add(profile);
mKeyProfileAdapter.notifyDataSetChanged(); _keyProfileAdapter.notifyDataSetChanged();
} }
private void onDoIntroResult(int resultCode, Intent data) { private void onDoIntroResult(int resultCode, Intent data) {
@ -235,9 +242,9 @@ public class MainActivity extends AppCompatActivity {
MasterKey key = (MasterKey) data.getSerializableExtra("key"); MasterKey key = (MasterKey) data.getSerializableExtra("key");
try { try {
db.load(); _db.load();
if (!db.isDecrypted()) { if (!_db.isDecrypted()) {
db.setMasterKey(key); _db.setMasterKey(key);
} }
} catch (Exception e) { } catch (Exception e) {
// TODO: feedback // TODO: feedback
@ -250,7 +257,7 @@ public class MainActivity extends AppCompatActivity {
private void onDecryptResult(int resultCode, Intent data) { private void onDecryptResult(int resultCode, Intent data) {
MasterKey key = (MasterKey) data.getSerializableExtra("key"); MasterKey key = (MasterKey) data.getSerializableExtra("key");
try { try {
db.setMasterKey(key); _db.setMasterKey(key);
} catch (Exception e) { } catch (Exception e) {
// TODO: feedback // TODO: feedback
throw new UndeclaredThrowableException(e); throw new UndeclaredThrowableException(e);
@ -262,21 +269,12 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
protected void onResume() { protected void onResume() {
super.onResume(); super.onResume();
mKeyProfileAdapter.notifyDataSetChanged(); _keyProfileAdapter.notifyDataSetChanged();
setPreferredTheme(); setPreferredTheme();
} }
@Override @Override
protected void onPause() { protected void onPause() {
// update order of keys
for (int i = 0; i < mKeyProfiles.size(); i++) {
try {
db.updateKey(mKeyProfiles.get(i));
} catch (Exception e) {
e.printStackTrace();
}
}
saveDatabase(); saveDatabase();
super.onPause(); super.onPause();
} }
@ -298,7 +296,7 @@ public class MainActivity extends AppCompatActivity {
copyLayout.setOnClickListener(view -> { copyLayout.setOnClickListener(view -> {
bottomDialog.dismiss(); bottomDialog.dismiss();
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE); ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("text/plain", mKeyProfiles.get(clickedItemPosition).Code); ClipData clip = ClipData.newPlainText("text/plain", _keyProfiles.get(_clickedItemPosition).getCode());
clipboard.setPrimaryClip(clip); clipboard.setPrimaryClip(clip);
Toast.makeText(this.getApplicationContext(), "Code successfully copied to the clipboard", Toast.LENGTH_SHORT).show(); Toast.makeText(this.getApplicationContext(), "Code successfully copied to the clipboard", Toast.LENGTH_SHORT).show();
@ -307,7 +305,7 @@ public class MainActivity extends AppCompatActivity {
deleteLayout.setOnClickListener(view -> { deleteLayout.setOnClickListener(view -> {
bottomDialog.dismiss(); bottomDialog.dismiss();
KeyProfile keyProfile = mKeyProfiles.get(clickedItemPosition); KeyProfile keyProfile = _keyProfiles.get(_clickedItemPosition);
deleteProfile(keyProfile); deleteProfile(keyProfile);
}); });
@ -326,14 +324,14 @@ public class MainActivity extends AppCompatActivity {
.setMessage("Are you sure you want to delete this profile?") .setMessage("Are you sure you want to delete this profile?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> { .setPositiveButton(android.R.string.yes, (dialog, which) -> {
try { try {
db.removeKey(profile); _db.removeKey(profile.getEntry());
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
//TODO: feedback //TODO: feedback
return; return;
} }
mKeyProfiles.remove(clickedItemPosition); _keyProfiles.remove(_clickedItemPosition);
mKeyProfileAdapter.notifyItemRemoved(clickedItemPosition); _keyProfileAdapter.notifyItemRemoved(_clickedItemPosition);
}) })
.setNegativeButton(android.R.string.no, (dialog, which) -> { .setNegativeButton(android.R.string.no, (dialog, which) -> {
}) })
@ -342,7 +340,9 @@ public class MainActivity extends AppCompatActivity {
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
_menu = menu;
getMenuInflater().inflate(R.menu.menu_main, menu); getMenuInflater().inflate(R.menu.menu_main, menu);
updateLockIcon();
return true; return true;
} }
@ -367,15 +367,11 @@ public class MainActivity extends AppCompatActivity {
} }
} }
private void initializeAppShortcuts() private void initializeAppShortcuts() {
{
String mode = getIntent().getStringExtra("Action"); String mode = getIntent().getStringExtra("Action");
if(mode != null) if (mode != null) {
{
Log.println(Log.DEBUG, "MODE: ", mode); Log.println(Log.DEBUG, "MODE: ", mode);
if(Objects.equals(mode, "Scan")) if (Objects.equals(mode, "Scan")) {
{
Log.println(Log.DEBUG, "OKK ", "OKKK");
Intent scannerActivity = new Intent(getApplicationContext(), ScannerActivity.class); Intent scannerActivity = new Intent(getApplicationContext(), ScannerActivity.class);
startActivityForResult(scannerActivity, CODE_GET_KEYINFO); startActivityForResult(scannerActivity, CODE_GET_KEYINFO);
} }
@ -384,7 +380,7 @@ public class MainActivity extends AppCompatActivity {
ShortcutManager shortcutManager = null; ShortcutManager shortcutManager = null;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) { if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
shortcutManager = getSystemService(ShortcutManager.class); shortcutManager = getSystemService(ShortcutManager.class);
if(shortcutManager != null) { if (shortcutManager != null) {
//TODO: Remove this line //TODO: Remove this line
shortcutManager.removeAllDynamicShortcuts(); shortcutManager.removeAllDynamicShortcuts();
if (shortcutManager.getDynamicShortcuts().size() == 0) { if (shortcutManager.getDynamicShortcuts().size() == 0) {
@ -394,48 +390,47 @@ public class MainActivity extends AppCompatActivity {
intent1.putExtra("Action", "Scan"); intent1.putExtra("Action", "Scan");
intent1.setAction(Intent.ACTION_MAIN); intent1.setAction(Intent.ACTION_MAIN);
ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1") ShortcutInfo shortcut = new ShortcutInfo.Builder(this, "id1")
.setShortLabel("New profile") .setShortLabel("New profile")
.setLongLabel("Add new profile") .setLongLabel("Add new profile")
.setIcon(Icon.createWithResource(this.getApplicationContext(), R.drawable.intro_scanner)) .setIcon(Icon.createWithResource(this.getApplicationContext(), R.drawable.intro_scanner))
.setIntent(intent1) .setIntent(intent1)
.build(); .build();
shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut)); shortcutManager.setDynamicShortcuts(Arrays.asList(shortcut));
} }
} }
} }
} }
private void setPreferredTheme() private void setPreferredTheme() {
{
boolean restart = false; boolean restart = false;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if(sharedPreferences.getBoolean("pref_night_mode", false)) { if (sharedPreferences.getBoolean("pref_night_mode", false)) {
if(!nightMode) { if (!_nightMode) {
setTheme(R.style.AppTheme_Dark_NoActionBar); setTheme(R.style.AppTheme_Dark_NoActionBar);
restart = true; restart = true;
} }
} else { } else {
if(nightMode) { if (_nightMode) {
setTheme(R.style.AppTheme_Default_NoActionBar); setTheme(R.style.AppTheme_Default_NoActionBar);
restart = true; restart = true;
} }
} }
if(restart){ if (restart) {
finish(); finish();
startActivity(new Intent(this, this.getClass())); startActivity(new Intent(this, this.getClass()));
} }
} }
private void saveDatabase() { private void saveDatabase() {
if (!db.isDecrypted()) { if (!_db.isDecrypted()) {
return; return;
} }
try { try {
db.save(); _db.save();
} catch (Exception e) { } catch (Exception e) {
//TODO: feedback //TODO: feedback
throw new UndeclaredThrowableException(e); throw new UndeclaredThrowableException(e);
@ -443,11 +438,23 @@ public class MainActivity extends AppCompatActivity {
} }
private void loadKeyProfiles() { private void loadKeyProfiles() {
updateLockIcon();
try { try {
mKeyProfiles.addAll(db.getKeys()); for (DatabaseEntry entry : _db.getKeys()) {
mKeyProfileAdapter.notifyDataSetChanged(); _keyProfiles.add(new KeyProfile(entry));
}
_keyProfileAdapter.notifyDataSetChanged();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
private void updateLockIcon() {
// hide the lock icon if the database is not encrypted
if (_menu != null && _db.isDecrypted()) {
MenuItem item = _menu.findItem(R.id.action_lock);
item.setVisible(_db.getFile().isEncrypted());
}
}
} }

View file

@ -1,14 +1,11 @@
package me.impy.aegis; package me.impy.aegis;
import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment; import android.preference.PreferenceFragment;
import android.preference.PreferenceManager; import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate;
import android.widget.Toast; import android.widget.Toast;
public class PreferencesActivity extends AppCompatActivity { public class PreferencesActivity extends AppCompatActivity {
@ -16,24 +13,23 @@ public class PreferencesActivity extends AppCompatActivity {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
SharedPreferences mySharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); SharedPreferences mySharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if(mySharedPreferences.getBoolean("pref_night_mode", false)) if (mySharedPreferences.getBoolean("pref_night_mode", false)) {
{
setTheme(R.style.AppTheme_Dark); setTheme(R.style.AppTheme_Dark);
} else } else {
{
setTheme(R.style.AppTheme_Default); setTheme(R.style.AppTheme_Default);
} }
getFragmentManager().beginTransaction().replace(android.R.id.content, new PreferencesFragment()).commit();
getFragmentManager().beginTransaction().replace(android.R.id.content, new PreferencesFragment()).commit();
} }
public static class PreferencesFragment extends PreferenceFragment { public static class PreferencesFragment extends PreferenceFragment {
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences); addPreferencesFromResource(R.xml.preferences);
final Preference nightModePreference = findPreference("pref_night_mode"); final Preference nightModePreference = findPreference("pref_night_mode");

View file

@ -12,32 +12,34 @@ import android.widget.Toast;
import com.google.zxing.BarcodeFormat; import com.google.zxing.BarcodeFormat;
import com.google.zxing.Result; import com.google.zxing.Result;
import java.util.ArrayList; import java.util.Collections;
import java.util.List;
import me.dm7.barcodescanner.core.IViewFinder; import me.dm7.barcodescanner.core.IViewFinder;
import me.dm7.barcodescanner.zxing.ZXingScannerView; import me.dm7.barcodescanner.zxing.ZXingScannerView;
import me.impy.aegis.crypto.KeyInfo; import me.impy.aegis.crypto.KeyInfo;
import me.impy.aegis.db.DatabaseEntry;
import me.impy.aegis.helpers.SquareFinderView; import me.impy.aegis.helpers.SquareFinderView;
public class ScannerActivity extends Activity implements ZXingScannerView.ResultHandler { public class ScannerActivity extends Activity implements ZXingScannerView.ResultHandler {
private ZXingScannerView mScannerView; private static final int CODE_ASK_PERMS = 0;
private ZXingScannerView _scannerView;
@Override @Override
public void onCreate(Bundle state) { public void onCreate(Bundle state) {
super.onCreate(state); super.onCreate(state);
mScannerView = new ZXingScannerView(this) { _scannerView = new ZXingScannerView(this) {
@Override @Override
protected IViewFinder createViewFinderView(Context context) { protected IViewFinder createViewFinderView(Context context) {
return new SquareFinderView(context); return new SquareFinderView(context);
} }
}; };
setContentView(mScannerView); // Set the scanner view as the content view setContentView(_scannerView);
mScannerView.setFormats(getSupportedFormats()); _scannerView.setFormats(Collections.singletonList(BarcodeFormat.QR_CODE));
ActivityCompat.requestPermissions(ScannerActivity.this, new String[]{Manifest.permission.CAMERA}, 1); ActivityCompat.requestPermissions(ScannerActivity.this, new String[]{Manifest.permission.CAMERA}, CODE_ASK_PERMS);
} }
@Override @Override
@ -48,54 +50,39 @@ public class ScannerActivity extends Activity implements ZXingScannerView.Result
@Override @Override
public void onPause() { public void onPause() {
super.onPause(); super.onPause();
mScannerView.stopCamera(); // Stop camera on pause _scannerView.stopCamera();
} }
@Override @Override
public void handleResult(Result rawResult) { public void handleResult(Result rawResult) {
// Do something with the result here
Toast.makeText(this, rawResult.getText(), Toast.LENGTH_SHORT).show();
try { try {
//TODO: Handle non TOTP / HOTP qr codes.
KeyInfo info = KeyInfo.fromURL(rawResult.getText()); KeyInfo info = KeyInfo.fromURL(rawResult.getText());
KeyProfile keyProfile = new KeyProfile(); KeyProfile profile = new KeyProfile(new DatabaseEntry(info));
keyProfile.Info = info;
Intent resultIntent = new Intent(); Intent resultIntent = new Intent();
resultIntent.putExtra("KeyProfile", keyProfile); resultIntent.putExtra("KeyProfile", profile);
setResult(Activity.RESULT_OK, resultIntent); setResult(Activity.RESULT_OK, resultIntent);
finish(); finish();
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); Toast.makeText(this, "An error occurred while trying to parse the QR code contents", Toast.LENGTH_SHORT).show();
} }
// If you would like to resume scanning, call this method below: _scannerView.resumeCameraPreview(this);
mScannerView.resumeCameraPreview(this);
} }
@Override @Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) { public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) { switch (requestCode) {
case 1: { case CODE_ASK_PERMS: {
// If request is cancelled, the result arrays are empty.
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
_scannerView.setResultHandler(this);
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results. _scannerView.startCamera();
mScannerView.startCamera(); // Start camera on resume
} else { } else {
Toast.makeText(ScannerActivity.this, "Permission denied to get access to the camera", Toast.LENGTH_SHORT).show(); Toast.makeText(ScannerActivity.this, "Permission denied to get access to the camera", Toast.LENGTH_SHORT).show();
} }
return; break;
} }
} }
} }
private List<BarcodeFormat> getSupportedFormats() {
ArrayList<BarcodeFormat> supportedFormats = new ArrayList<>();
supportedFormats.add(BarcodeFormat.QR_CODE);
return supportedFormats;
}
} }

View file

@ -37,7 +37,7 @@ public class CryptoUtils {
public static final byte CRYPTO_NONCE_SIZE = 12; public static final byte CRYPTO_NONCE_SIZE = 12;
public static final byte CRYPTO_SALT_SIZE = 32; public static final byte CRYPTO_SALT_SIZE = 32;
public static final int CRYPTO_SCRYPT_N = 2 << 14; public static final int CRYPTO_SCRYPT_N = 1 << 15;
public static final int CRYPTO_SCRYPT_r = 8; public static final int CRYPTO_SCRYPT_r = 8;
public static final int CRYPTO_SCRYPT_p = 1; public static final int CRYPTO_SCRYPT_p = 1;

View file

@ -7,39 +7,39 @@ import java.io.Serializable;
import me.impy.aegis.encoding.Base32; import me.impy.aegis.encoding.Base32;
public class KeyInfo implements Serializable { public class KeyInfo implements Serializable {
private String type; private String _type;
private byte[] secret; private byte[] _secret;
private String accountName; private String _accountName;
private String issuer; private String _issuer;
private long counter; private long _counter;
private String algorithm = "SHA1"; private String _algorithm = "SHA1";
private int digits = 6; private int _digits = 6;
private int period = 30; private int _period = 30;
public String getURL() throws Exception { public String getURL() throws Exception {
Uri.Builder builder = new Uri.Builder(); Uri.Builder builder = new Uri.Builder();
builder.scheme("otpauth"); builder.scheme("otpauth");
builder.authority(type); builder.authority(_type);
builder.appendQueryParameter("period", Integer.toString(period)); builder.appendQueryParameter("period", Integer.toString(_period));
builder.appendQueryParameter("algorithm", algorithm); builder.appendQueryParameter("algorithm", _algorithm);
builder.appendQueryParameter("secret", Base32.encodeOriginal(secret)); builder.appendQueryParameter("secret", Base32.encodeOriginal(_secret));
if (type.equals("hotp")) { if (_type.equals("hotp")) {
builder.appendQueryParameter("counter", Long.toString(counter)); builder.appendQueryParameter("counter", Long.toString(_counter));
} }
if (!issuer.equals("")) { if (!_issuer.equals("")) {
builder.path(String.format("%s:%s", issuer, accountName)); builder.path(String.format("%s:%s", _issuer, _accountName));
builder.appendQueryParameter("issuer", issuer); builder.appendQueryParameter("issuer", _issuer);
} else { } else {
builder.path(accountName); builder.path(_accountName);
} }
return builder.build().toString(); return builder.build().toString();
} }
public long getMillisTillNextRotation() { public long getMillisTillNextRotation() {
long p = period * 1000; long p = _period * 1000;
return p - (System.currentTimeMillis() % p); return p - (System.currentTimeMillis() % p);
} }
@ -52,8 +52,8 @@ public class KeyInfo implements Serializable {
KeyInfo info = new KeyInfo(); KeyInfo info = new KeyInfo();
// only 'totp' and 'hotp' are supported // only 'totp' and 'hotp' are supported
info.type = url.getHost(); info._type = url.getHost();
if (info.type.equals("totp") && info.type.equals("hotp")) { if (info._type.equals("totp") && info._type.equals("hotp")) {
throw new Exception("unsupported type"); throw new Exception("unsupported type");
} }
@ -62,7 +62,7 @@ public class KeyInfo implements Serializable {
if (secret == null) { if (secret == null) {
throw new Exception("'secret' is not set"); throw new Exception("'secret' is not set");
} }
info.secret = Base32.decode(secret); info._secret = Base32.decode(secret);
// provider info used to disambiguate accounts // provider info used to disambiguate accounts
String path = url.getPath(); String path = url.getPath();
@ -74,39 +74,39 @@ public class KeyInfo implements Serializable {
String[] strings = label.split(":"); String[] strings = label.split(":");
if (strings.length == 2) { if (strings.length == 2) {
info.issuer = strings[0]; info._issuer = strings[0];
info.accountName = strings[1]; info._accountName = strings[1];
} else { } else {
// at this point, just dump the whole thing into the accountName // at this point, just dump the whole thing into the accountName
info.accountName = label; info._accountName = label;
} }
} else { } else {
// label only contains the account name // label only contains the account name
// grab the issuer's info from the 'issuer' parameter if it's present // grab the issuer's info from the 'issuer' parameter if it's present
String issuer = url.getQueryParameter("issuer"); String issuer = url.getQueryParameter("issuer");
info.issuer = issuer != null ? issuer : ""; info._issuer = issuer != null ? issuer : "";
info.accountName = label; info._accountName = label;
} }
// just use the defaults if these parameters aren't set // just use the defaults if these parameters aren't set
String algorithm = url.getQueryParameter("algorithm"); String algorithm = url.getQueryParameter("algorithm");
if (algorithm != null) { if (algorithm != null) {
info.algorithm = algorithm; info._algorithm = algorithm;
} }
String period = url.getQueryParameter("period"); String period = url.getQueryParameter("period");
if (period != null) { if (period != null) {
info.period = Integer.parseInt(period); info._period = Integer.parseInt(period);
} }
String digits = url.getQueryParameter("digits"); String digits = url.getQueryParameter("digits");
if (digits != null) { if (digits != null) {
info.digits = Integer.parseInt(digits); info._digits = Integer.parseInt(digits);
} }
// 'counter' is required if the type is 'hotp' // 'counter' is required if the type is 'hotp'
String counter = url.getQueryParameter("counter"); String counter = url.getQueryParameter("counter");
if (counter != null) { if (counter != null) {
info.counter = Long.parseLong(counter); info._counter = Long.parseLong(counter);
} else if (info.type.equals("hotp")) { } else if (info._type.equals("hotp")) {
throw new Exception("'counter' was not set which is required for 'hotp'"); throw new Exception("'counter' was not set which is required for 'hotp'");
} }
@ -114,55 +114,55 @@ public class KeyInfo implements Serializable {
} }
public String getType() { public String getType() {
return type; return _type;
} }
public byte[] getSecret() { public byte[] getSecret() {
return secret; return _secret;
} }
public String getAccountName() { public String getAccountName() {
return accountName; return _accountName;
} }
public String getIssuer() { public String getIssuer() {
return issuer; return _issuer;
} }
public String getAlgorithm() { public String getAlgorithm() {
return "Hmac" + algorithm; return "Hmac" + _algorithm;
} }
public int getDigits() { public int getDigits() {
return digits; return _digits;
} }
public long getCounter() { public long getCounter() {
return counter; return _counter;
} }
public int getPeriod() { public int getPeriod() {
return period; return _period;
} }
public void setType(String type) { public void setType(String type) {
this.type = type.toLowerCase(); _type = type.toLowerCase();
} }
public void setSecret(byte[] secret) { public void setSecret(byte[] secret) {
this.secret = secret; _secret = secret;
} }
public void setAccountName(String accountName) { public void setAccountName(String accountName) {
this.accountName = accountName; _accountName = accountName;
} }
public void setIssuer(String issuer) { public void setIssuer(String issuer) {
this.issuer = issuer; _issuer = issuer;
} }
public void setAlgorithm(String algorithm) { public void setAlgorithm(String algorithm) {
if (algorithm.startsWith("Hmac")) { if (algorithm.startsWith("Hmac")) {
algorithm = algorithm.substring(4); algorithm = algorithm.substring(4);
} }
this.algorithm = algorithm.toUpperCase(); _algorithm = algorithm.toUpperCase();
} }
public void setDigits(int digits) { public void setDigits(int digits) {
this.digits = digits; _digits = digits;
} }
public void setCounter(long count) { public void setCounter(long count) {
counter = count; _counter = count;
} }
public void setPeriod(int period) { public void setPeriod(int period) {
this.period = period; _period = period;
} }
} }

View file

@ -15,17 +15,17 @@ import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey; import javax.crypto.SecretKey;
public class KeyStoreHandle { public class KeyStoreHandle {
private final KeyStore keyStore; private final KeyStore _keyStore;
private static final String KEY_NAME = "AegisKey"; private static final String KEY_NAME = "AegisKey";
private static final String STORE_NAME = "AndroidKeyStore"; private static final String STORE_NAME = "AndroidKeyStore";
public KeyStoreHandle() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException { public KeyStoreHandle() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
keyStore = KeyStore.getInstance(STORE_NAME); _keyStore = KeyStore.getInstance(STORE_NAME);
keyStore.load(null); _keyStore.load(null);
} }
public boolean keyExists() throws KeyStoreException { public boolean keyExists() throws KeyStoreException {
return keyStore.containsAlias(KEY_NAME); return _keyStore.containsAlias(KEY_NAME);
} }
public SecretKey generateKey(boolean authRequired) throws Exception { public SecretKey generateKey(boolean authRequired) throws Exception {
@ -47,6 +47,6 @@ public class KeyStoreHandle {
} }
public SecretKey getKey() throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException { public SecretKey getKey() throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {
return (SecretKey) keyStore.getKey(KEY_NAME, null); return (SecretKey) _keyStore.getKey(KEY_NAME, null);
} }
} }

View file

@ -82,6 +82,10 @@ public class SlotCollection implements Iterable<Slot>, Serializable {
return _slots.size(); return _slots.size();
} }
public boolean isEmpty() {
return _slots.size() == 0;
}
public <T extends Slot> T find(Class<T> type) { public <T extends Slot> T find(Class<T> type) {
for (Slot slot : this) { for (Slot slot : this) {
if (slot.getClass() == type) { if (slot.getClass() == type) {

View file

@ -1,28 +1,23 @@
package me.impy.aegis.db; package me.impy.aegis.db;
import org.json.JSONArray; import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import me.impy.aegis.KeyProfile;
import me.impy.aegis.crypto.KeyInfo;
public class Database { public class Database {
private static final int version = 1; private static final int VERSION = 1;
private List<DatabaseEntry> entries = new ArrayList<>(); private List<DatabaseEntry> _entries = new ArrayList<>();
public byte[] serialize() throws JSONException, UnsupportedEncodingException { public byte[] serialize() throws Exception {
JSONArray array = new JSONArray(); JSONArray array = new JSONArray();
for (DatabaseEntry e : entries) { for (DatabaseEntry e : _entries) {
array.put(e.serialize()); array.put(e.serialize());
} }
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("version", version); obj.put("version", VERSION);
obj.put("entries", array); obj.put("entries", array);
return obj.toString().getBytes("UTF-8"); return obj.toString().getBytes("UTF-8");
@ -31,64 +26,30 @@ public class Database {
public void deserialize(byte[] data) throws Exception { public void deserialize(byte[] data) throws Exception {
JSONObject obj = new JSONObject(new String(data, "UTF-8")); JSONObject obj = new JSONObject(new String(data, "UTF-8"));
// TODO: support different version deserialization providers // TODO: support different VERSION deserialization providers
int ver = obj.getInt("version"); int ver = obj.getInt("version");
if (ver != version) { if (ver != VERSION) {
throw new Exception("Unsupported version"); throw new Exception("Unsupported version");
} }
JSONArray array = obj.getJSONArray("entries"); JSONArray array = obj.getJSONArray("entries");
for (int i = 0; i < array.length(); i++) { for (int i = 0; i < array.length(); i++) {
DatabaseEntry e = new DatabaseEntry(); DatabaseEntry e = new DatabaseEntry(null);
e.deserialize(array.getJSONObject(i)); e.deserialize(array.getJSONObject(i));
entries.add(e); _entries.add(e);
} }
} }
public void addKey(KeyProfile profile) throws Exception { public void addKey(DatabaseEntry entry) throws Exception {
DatabaseEntry e = new DatabaseEntry(); entry.setID(_entries.size() + 1);
e.Name = profile.Name; _entries.add(entry);
e.URL = profile.Info.getURL();
e.Order = profile.Order;
e.ID = entries.size() + 1;
profile.ID = e.ID;
entries.add(e);
} }
public void updateKey(KeyProfile profile) throws Exception { public void removeKey(DatabaseEntry entry) throws Exception {
DatabaseEntry e = findEntry(profile); _entries.remove(entry);
e.Name = profile.Name;
e.URL = profile.Info.getURL();
e.Order = profile.Order;
} }
public void removeKey(KeyProfile profile) throws Exception { public List<DatabaseEntry> getKeys() throws Exception {
DatabaseEntry e = findEntry(profile); return _entries;
entries.remove(e);
}
public List<KeyProfile> getKeys() throws Exception {
List<KeyProfile> list = new ArrayList<>();
for (DatabaseEntry e : entries) {
KeyProfile profile = new KeyProfile();
profile.Name = e.Name;
profile.Info = KeyInfo.fromURL(e.URL);
profile.Order = e.Order;
profile.ID = e.ID;
list.add(profile);
}
return list;
}
private DatabaseEntry findEntry(KeyProfile profile) throws Exception {
for (DatabaseEntry e : entries) {
if (e.ID == profile.ID) {
return e;
}
}
throw new Exception("Key doesn't exist");
} }
} }

View file

@ -1,27 +1,67 @@
package me.impy.aegis.db; package me.impy.aegis.db;
import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
public class DatabaseEntry { import java.io.Serializable;
public int ID;
public String Name;
public String URL;
public int Order;
public JSONObject serialize() throws JSONException { import me.impy.aegis.crypto.KeyInfo;
public class DatabaseEntry implements Serializable {
public int _id;
public String _name;
public String _icon;
public KeyInfo _info;
public int _order;
public DatabaseEntry(KeyInfo info) {
_info = info;
}
public JSONObject serialize() throws Exception {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("id", ID); obj.put("id", _id);
obj.put("name", Name); obj.put("name", _name);
obj.put("url", URL); obj.put("url", _info.getURL());
obj.put("order", Order); obj.put("order", _order);
return obj; return obj;
} }
public void deserialize(JSONObject obj) throws JSONException { public void deserialize(JSONObject obj) throws Exception {
ID = obj.getInt("id"); _id = obj.getInt("id");
Name = obj.getString("name"); _name = obj.getString("name");
URL = obj.getString("url"); _info = KeyInfo.fromURL(obj.getString("url"));
Order = obj.getInt("order"); _order = obj.getInt("order");
}
public int getID() {
return _id;
}
public String getName() {
return _name;
}
public String getIcon() {
return _icon;
}
public KeyInfo getInfo() {
return _info;
}
public int getOrder() {
return _order;
}
public void setID(int id) {
_id = id;
}
public void setName(String name) {
_name = name;
}
public void setIcon(String icon) {
_icon = icon;
}
public void setInfo(KeyInfo info) {
_info = info;
}
public void setOrder(int order) {
_order = order;
} }
} }

View file

@ -16,50 +16,50 @@ import me.impy.aegis.crypto.CryptoUtils;
import me.impy.aegis.util.LittleByteBuffer; import me.impy.aegis.util.LittleByteBuffer;
public class DatabaseFile { public class DatabaseFile {
private static final byte bSectionEncryptionParameters = 0x00; private static final byte SECTION_ENCRYPTION_PARAMETERS = 0x00;
private static final byte bSectionSlots = 0x01; private static final byte SECTION_SLOTS = 0x01;
private static final byte bSectionEnd = (byte) 0xFF; private static final byte SECTION_END = (byte) 0xFF;
private static final byte bVersion = 1; private static final byte VERSION = 1;
private static final String dbFilename = "aegis.db"; private static final String FILENAME = "aegis.db";
private final byte[] bHeader; private final byte[] HEADER;
private byte[] content; private byte[] _content;
private CryptParameters cryptParameters; private CryptParameters _cryptParameters;
private SlotCollection slots; private SlotCollection _slots;
public DatabaseFile() { public DatabaseFile() {
try { try {
bHeader = "AEGIS".getBytes("US_ASCII"); HEADER = "AEGIS".getBytes("US_ASCII");
} catch (Exception e) { } catch (Exception e) {
throw new UndeclaredThrowableException(e); throw new UndeclaredThrowableException(e);
} }
slots = new SlotCollection(); _slots = new SlotCollection();
} }
public byte[] serialize() throws IOException { public byte[] serialize() throws IOException {
CryptParameters cryptParams = getCryptParameters();
byte[] content = getContent(); byte[] content = getContent();
CryptParameters cryptParams = getCryptParameters();
// this is dumb, java doesn't provide an endianness-aware data stream // this is dumb, java doesn't provide an endianness-aware data stream
ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
DataOutputStream stream = new DataOutputStream(byteStream); DataOutputStream stream = new DataOutputStream(byteStream);
stream.write(bHeader); stream.write(HEADER);
stream.write(bVersion); stream.write(VERSION);
if (cryptParams != null) { if (cryptParams != null) {
LittleByteBuffer paramBuffer = LittleByteBuffer.allocate(CryptoUtils.CRYPTO_NONCE_SIZE + CryptoUtils.CRYPTO_TAG_SIZE); LittleByteBuffer paramBuffer = LittleByteBuffer.allocate(CryptoUtils.CRYPTO_NONCE_SIZE + CryptoUtils.CRYPTO_TAG_SIZE);
paramBuffer.put(cryptParams.Nonce); paramBuffer.put(cryptParams.Nonce);
paramBuffer.put(cryptParams.Tag); paramBuffer.put(cryptParams.Tag);
writeSection(stream, bSectionEncryptionParameters, paramBuffer.array()); writeSection(stream, SECTION_ENCRYPTION_PARAMETERS, paramBuffer.array());
} }
if (slots != null) { if (!_slots.isEmpty()) {
byte[] bytes = SlotCollection.serialize(slots); byte[] bytes = SlotCollection.serialize(_slots);
writeSection(stream, bSectionSlots, bytes); writeSection(stream, SECTION_SLOTS, bytes);
} }
writeSection(stream, bSectionEnd, null); writeSection(stream, SECTION_END, null);
stream.write(content); stream.write(content);
return byteStream.toByteArray(); return byteStream.toByteArray();
} }
@ -67,25 +67,25 @@ public class DatabaseFile {
public void deserialize(byte[] data) throws Exception { public void deserialize(byte[] data) throws Exception {
LittleByteBuffer buffer = LittleByteBuffer.wrap(data); LittleByteBuffer buffer = LittleByteBuffer.wrap(data);
byte[] header = new byte[bHeader.length]; byte[] header = new byte[HEADER.length];
buffer.get(header); buffer.get(header);
if (!Arrays.equals(header, bHeader)) { if (!Arrays.equals(header, HEADER)) {
throw new Exception("Bad header"); throw new Exception("Bad header");
} }
// TODO: support different version deserialization providers // TODO: support different version deserialization providers
byte version = buffer.get(); byte version = buffer.get();
if (version != bVersion) { if (version != VERSION) {
throw new Exception("Unsupported version"); throw new Exception("Unsupported version");
} }
CryptParameters cryptParams = null; CryptParameters cryptParams = null;
SlotCollection slots = null; SlotCollection slots = new SlotCollection();
for (section s = readSection(buffer); s.ID != bSectionEnd; s = readSection(buffer)) { for (section s = readSection(buffer); s.ID != SECTION_END; s = readSection(buffer)) {
LittleByteBuffer sBuff = LittleByteBuffer.wrap(s.Data); LittleByteBuffer sBuff = LittleByteBuffer.wrap(s.Data);
switch (s.ID) { switch (s.ID) {
case bSectionEncryptionParameters: case SECTION_ENCRYPTION_PARAMETERS:
assertLength(s.Data, CryptoUtils.CRYPTO_NONCE_SIZE + CryptoUtils.CRYPTO_TAG_SIZE); assertLength(s.Data, CryptoUtils.CRYPTO_NONCE_SIZE + CryptoUtils.CRYPTO_TAG_SIZE);
byte[] nonce = new byte[CryptoUtils.CRYPTO_NONCE_SIZE]; byte[] nonce = new byte[CryptoUtils.CRYPTO_NONCE_SIZE];
@ -98,7 +98,7 @@ public class DatabaseFile {
Tag = tag; Tag = tag;
}}; }};
break; break;
case bSectionSlots: case SECTION_SLOTS:
slots = SlotCollection.deserialize(s.Data); slots = SlotCollection.deserialize(s.Data);
break; break;
} }
@ -113,19 +113,19 @@ public class DatabaseFile {
} }
public boolean isEncrypted() { public boolean isEncrypted() {
return slots != null && cryptParameters != null; return !_slots.isEmpty() && _cryptParameters != null;
} }
public void save(Context context) throws IOException { public void save(Context context) throws IOException {
byte[] data = serialize(); byte[] data = serialize();
FileOutputStream file = context.openFileOutput(dbFilename, Context.MODE_PRIVATE); FileOutputStream file = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
file.write(data); file.write(data);
file.close(); file.close();
} }
public static DatabaseFile load(Context context) throws Exception { public static DatabaseFile load(Context context) throws Exception {
FileInputStream file = context.openFileInput(dbFilename); FileInputStream file = context.openFileInput(FILENAME);
byte[] data = new byte[(int) file.getChannel().size()]; byte[] data = new byte[(int) file.getChannel().size()];
file.read(data); file.read(data);
file.close(); file.close();
@ -169,27 +169,27 @@ public class DatabaseFile {
} }
public byte[] getContent() { public byte[] getContent() {
return content; return _content;
} }
public void setContent(byte[] content) { public void setContent(byte[] content) {
this.content = content; _content = content;
} }
public CryptParameters getCryptParameters() { public CryptParameters getCryptParameters() {
return cryptParameters; return _cryptParameters;
} }
public void setCryptParameters(CryptParameters parameters) { public void setCryptParameters(CryptParameters parameters) {
this.cryptParameters = parameters; _cryptParameters = parameters;
} }
public SlotCollection getSlots() { public SlotCollection getSlots() {
return slots; return _slots;
} }
public void setSlots(SlotCollection slots) { public void setSlots(SlotCollection slots) {
this.slots = slots; _slots = slots;
} }
private static class section { private static class section {

View file

@ -51,22 +51,17 @@ public class DatabaseManager {
_file.save(_context); _file.save(_context);
} }
public void addKey(KeyProfile profile) throws Exception { public void addKey(DatabaseEntry entry) throws Exception {
assertDecrypted(); assertDecrypted();
_db.addKey(profile); _db.addKey(entry);
} }
public void updateKey(KeyProfile profile) throws Exception { public void removeKey(DatabaseEntry entry) throws Exception {
assertDecrypted(); assertDecrypted();
_db.updateKey(profile); _db.removeKey(entry);
} }
public void removeKey(KeyProfile profile) throws Exception { public List<DatabaseEntry> getKeys() throws Exception {
assertDecrypted();
_db.removeKey(profile);
}
public List<KeyProfile> getKeys() throws Exception {
assertDecrypted(); assertDecrypted();
return _db.getKeys(); return _db.getKeys();
} }

View file

@ -13,8 +13,8 @@ import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import me.impy.aegis.KeyProfile;
import me.impy.aegis.crypto.KeyInfo; import me.impy.aegis.crypto.KeyInfo;
import me.impy.aegis.db.DatabaseEntry;
public class FreeOTPImporter extends KeyConverter { public class FreeOTPImporter extends KeyConverter {
public FreeOTPImporter(InputStream stream) { public FreeOTPImporter(InputStream stream) {
@ -27,9 +27,7 @@ public class FreeOTPImporter extends KeyConverter {
} }
@Override @Override
public List<KeyProfile> convert() throws Exception { public List<DatabaseEntry> convert() throws Exception {
List<KeyProfile> keys = new ArrayList<>();
XmlPullParser parser = Xml.newPullParser(); XmlPullParser parser = Xml.newPullParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
parser.setInput(_stream, null); parser.setInput(_stream, null);
@ -37,7 +35,7 @@ public class FreeOTPImporter extends KeyConverter {
return parse(parser); return parse(parser);
} }
private static List<KeyProfile> parse(XmlPullParser parser) throws IOException, XmlPullParserException, JSONException { private static List<DatabaseEntry> parse(XmlPullParser parser) throws IOException, XmlPullParserException, JSONException {
List<Entry> entries = new ArrayList<>(); List<Entry> entries = new ArrayList<>();
parser.require(XmlPullParser.START_TAG, null, "map"); parser.require(XmlPullParser.START_TAG, null, "map");
@ -54,7 +52,7 @@ public class FreeOTPImporter extends KeyConverter {
entries.add(parseEntry(parser)); entries.add(parseEntry(parser));
} }
List<KeyProfile> profiles = new ArrayList<>(); List<DatabaseEntry> profiles = new ArrayList<>();
for (Entry entry : entries) { for (Entry entry : entries) {
if (entry.Name.equals("tokenOrder")) { if (entry.Name.equals("tokenOrder")) {
@ -74,8 +72,8 @@ public class FreeOTPImporter extends KeyConverter {
byte[] secret = toBytes(obj.getJSONArray("secret")); byte[] secret = toBytes(obj.getJSONArray("secret"));
key.setSecret(secret); key.setSecret(secret);
KeyProfile profile = new KeyProfile(); DatabaseEntry profile = new DatabaseEntry(null);
profile.Info = key; profile.setInfo(key);
profiles.add(profile); profiles.add(profile);
} }
} }
@ -92,7 +90,6 @@ public class FreeOTPImporter extends KeyConverter {
} }
private static Entry parseEntry(XmlPullParser parser) throws IOException, XmlPullParserException { private static Entry parseEntry(XmlPullParser parser) throws IOException, XmlPullParserException {
KeyProfile profile = new KeyProfile();
parser.require(XmlPullParser.START_TAG, null, "string"); parser.require(XmlPullParser.START_TAG, null, "string");
String name = parser.getAttributeValue(null, "name"); String name = parser.getAttributeValue(null, "name");
String value = parseText(parser); String value = parseText(parser);

View file

@ -3,7 +3,7 @@ package me.impy.aegis.ext;
import java.io.InputStream; import java.io.InputStream;
import java.util.List; import java.util.List;
import me.impy.aegis.KeyProfile; import me.impy.aegis.db.DatabaseEntry;
public abstract class KeyConverter { public abstract class KeyConverter {
protected InputStream _stream; protected InputStream _stream;
@ -12,5 +12,5 @@ public abstract class KeyConverter {
_stream = stream; _stream = stream;
} }
public abstract List<KeyProfile> convert() throws Exception; public abstract List<DatabaseEntry> convert() throws Exception;
} }

View file

@ -5,10 +5,10 @@ import android.support.v7.widget.helper.ItemTouchHelper;
public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback { public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
private final ItemTouchHelperAdapter mAdapter; private final ItemTouchHelperAdapter _adapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) { public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter; _adapter = adapter;
} }
@Override @Override
@ -31,13 +31,13 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
@Override @Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) { RecyclerView.ViewHolder target) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition()); _adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true; return true;
} }
@Override @Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) { public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
mAdapter.onItemDismiss(viewHolder.getAdapterPosition()); _adapter.onItemDismiss(viewHolder.getAdapterPosition());
} }
} }

View file

@ -7,34 +7,25 @@ import me.impy.aegis.crypto.otp.HOTP;
import static org.junit.Assert.*; import static org.junit.Assert.*;
public class HOTPTest { public class HOTPTest {
private class testVector {
public long Count;
public String OTP;
}
// https://tools.ietf.org/html/rfc4226#page-32 // https://tools.ietf.org/html/rfc4226#page-32
private final testVector[] _vectors = { private final String[] _vectors = {
new testVector(){{ Count = 0; OTP = "755224"; }}, "755224", "287082",
new testVector(){{ Count = 1; OTP = "287082"; }}, "359152", "969429",
new testVector(){{ Count = 2; OTP = "359152"; }}, "338314", "254676",
new testVector(){{ Count = 3; OTP = "969429"; }}, "287922", "162583",
new testVector(){{ Count = 4; OTP = "338314"; }}, "399871", "520489"
new testVector(){{ Count = 5; OTP = "254676"; }},
new testVector(){{ Count = 6; OTP = "287922"; }},
new testVector(){{ Count = 7; OTP = "162583"; }},
new testVector(){{ Count = 8; OTP = "399871"; }},
new testVector(){{ Count = 9; OTP = "520489"; }},
}; };
private final byte[] _secret = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, private final byte[] _secret = new byte[] {
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
}; };
@Test @Test
public void vectors_match() throws Exception { public void vectorsMatch() throws Exception {
for (testVector v : _vectors) { for (int i = 0; i < _vectors.length; i++) {
String otp = HOTP.generateOTP(_secret, v.Count, 6, false, -1); String otp = HOTP.generateOTP(_secret, i, 6, false, -1);
assertEquals(v.OTP, otp); assertEquals(_vectors[i], otp);
} }
} }
} }

View file

@ -15,42 +15,47 @@ public class TOTPTest {
// https://tools.ietf.org/html/rfc6238#appendix-B // https://tools.ietf.org/html/rfc6238#appendix-B
private final testVector[] _vectors = { private final testVector[] _vectors = {
new testVector(){{ Time = "0000000000000001"; OTP = "94287082"; Mode = "HmacSHA1"; }}, new testVector(){{ Time = "0000000000000001"; OTP = "94287082"; Mode = "HmacSHA1"; }},
new testVector(){{ Time = "0000000000000001"; OTP = "46119246"; Mode = "HmacSHA256"; }}, new testVector(){{ Time = "0000000000000001"; OTP = "46119246"; Mode = "HmacSHA256"; }},
new testVector(){{ Time = "0000000000000001"; OTP = "90693936"; Mode = "HmacSHA512"; }}, new testVector(){{ Time = "0000000000000001"; OTP = "90693936"; Mode = "HmacSHA512"; }},
new testVector(){{ Time = "00000000023523EC"; OTP = "07081804"; Mode = "HmacSHA1"; }}, new testVector(){{ Time = "00000000023523EC"; OTP = "07081804"; Mode = "HmacSHA1"; }},
new testVector(){{ Time = "00000000023523EC"; OTP = "68084774"; Mode = "HmacSHA256"; }}, new testVector(){{ Time = "00000000023523EC"; OTP = "68084774"; Mode = "HmacSHA256"; }},
new testVector(){{ Time = "00000000023523EC"; OTP = "25091201"; Mode = "HmacSHA512"; }}, new testVector(){{ Time = "00000000023523EC"; OTP = "25091201"; Mode = "HmacSHA512"; }},
new testVector(){{ Time = "00000000023523ED"; OTP = "14050471"; Mode = "HmacSHA1"; }}, new testVector(){{ Time = "00000000023523ED"; OTP = "14050471"; Mode = "HmacSHA1"; }},
new testVector(){{ Time = "00000000023523ED"; OTP = "67062674"; Mode = "HmacSHA256"; }}, new testVector(){{ Time = "00000000023523ED"; OTP = "67062674"; Mode = "HmacSHA256"; }},
new testVector(){{ Time = "00000000023523ED"; OTP = "99943326"; Mode = "HmacSHA512"; }}, new testVector(){{ Time = "00000000023523ED"; OTP = "99943326"; Mode = "HmacSHA512"; }},
new testVector(){{ Time = "000000000273EF07"; OTP = "89005924"; Mode = "HmacSHA1"; }}, new testVector(){{ Time = "000000000273EF07"; OTP = "89005924"; Mode = "HmacSHA1"; }},
new testVector(){{ Time = "000000000273EF07"; OTP = "91819424"; Mode = "HmacSHA256"; }}, new testVector(){{ Time = "000000000273EF07"; OTP = "91819424"; Mode = "HmacSHA256"; }},
new testVector(){{ Time = "000000000273EF07"; OTP = "93441116"; Mode = "HmacSHA512"; }}, new testVector(){{ Time = "000000000273EF07"; OTP = "93441116"; Mode = "HmacSHA512"; }},
new testVector(){{ Time = "0000000003F940AA"; OTP = "69279037"; Mode = "HmacSHA1"; }}, new testVector(){{ Time = "0000000003F940AA"; OTP = "69279037"; Mode = "HmacSHA1"; }},
new testVector(){{ Time = "0000000003F940AA"; OTP = "90698825"; Mode = "HmacSHA256"; }}, new testVector(){{ Time = "0000000003F940AA"; OTP = "90698825"; Mode = "HmacSHA256"; }},
new testVector(){{ Time = "0000000003F940AA"; OTP = "38618901"; Mode = "HmacSHA512"; }}, new testVector(){{ Time = "0000000003F940AA"; OTP = "38618901"; Mode = "HmacSHA512"; }},
new testVector(){{ Time = "0000000027BC86AA"; OTP = "65353130"; Mode = "HmacSHA1"; }}, new testVector(){{ Time = "0000000027BC86AA"; OTP = "65353130"; Mode = "HmacSHA1"; }},
new testVector(){{ Time = "0000000027BC86AA"; OTP = "77737706"; Mode = "HmacSHA256"; }}, new testVector(){{ Time = "0000000027BC86AA"; OTP = "77737706"; Mode = "HmacSHA256"; }},
new testVector(){{ Time = "0000000027BC86AA"; OTP = "47863826"; Mode = "HmacSHA512"; }} new testVector(){{ Time = "0000000027BC86AA"; OTP = "47863826"; Mode = "HmacSHA512"; }}
}; };
private final byte[] _seed = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, private final byte[] _seed = new byte[] {
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[] { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, private final byte[] _seed32 = new byte[] {
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32 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
}; };
private final byte[] _seed64 = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, private final byte[] _seed64 = new byte[] {
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, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34 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
}; };
@Test @Test
public void vectors_match() throws Exception { public void vectorsMatch() throws Exception {
for (testVector v : _vectors) { for (testVector v : _vectors) {
byte[] seed; byte[] seed;