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.TextView;
import me.impy.aegis.crypto.KeyInfo;
import me.impy.aegis.crypto.otp.OTP;
public class AddProfileActivity extends AppCompatActivity {
KeyProfile keyProfile;
EditText profileName;
TextView tvAlgorithm;
TextView tvIssuer;
TextView tvPeriod;
TextView tvOtp;
KeyProfile _keyProfile;
EditText _profileName;
TextView _textAlgorithm;
TextView _textIssuer;
TextView _textPeriod;
TextView _textOtp;
@Override
protected void onCreate(Bundle savedInstanceState) {
@ -31,16 +31,16 @@ public class AddProfileActivity extends AppCompatActivity {
setPreferredTheme();
setContentView(R.layout.activity_add_profile);
profileName = (EditText) findViewById(R.id.addProfileName);
tvAlgorithm = (TextView) findViewById(R.id.tvAlgorithm);
tvIssuer = (TextView) findViewById(R.id.tvIssuer);
tvPeriod = (TextView) findViewById(R.id.tvPeriod);
tvOtp = (TextView) findViewById(R.id.tvOtp);
_profileName = (EditText) findViewById(R.id.addProfileName);
_textAlgorithm = (TextView) findViewById(R.id.tvAlgorithm);
_textIssuer = (TextView) findViewById(R.id.tvIssuer);
_textPeriod = (TextView) findViewById(R.id.tvPeriod);
_textOtp = (TextView) findViewById(R.id.tvOtp);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
keyProfile = (KeyProfile)getIntent().getSerializableExtra("KeyProfile");
_keyProfile = (KeyProfile) getIntent().getSerializableExtra("KeyProfile");
initializeForm();
@ -50,33 +50,33 @@ public class AddProfileActivity extends AppCompatActivity {
public void onClick(View view) {
Intent resultIntent = new Intent();
keyProfile.Name = profileName.getText().toString();
resultIntent.putExtra("KeyProfile", keyProfile);
_keyProfile.getEntry().setName(_profileName.getText().toString());
resultIntent.putExtra("KeyProfile", _keyProfile);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
});
//profileName.setText(keyProfile.Info.getAccountName());
//_profileName.setText(_keyProfile.Info.getAccountName());
}
private void initializeForm()
{
profileName.setText(keyProfile.Info.getAccountName());
tvAlgorithm.setText(keyProfile.Info.getAlgorithm());
tvIssuer.setText(keyProfile.Info.getIssuer());
tvPeriod.setText(keyProfile.Info.getPeriod() + " seconds");
private void initializeForm() {
KeyInfo info = _keyProfile.getEntry().getInfo();
_profileName.setText(info.getAccountName());
_textAlgorithm.setText(info.getAlgorithm());
_textIssuer.setText(info.getIssuer());
_textPeriod.setText(info.getPeriod() + " seconds");
String otp;
try {
otp = OTP.generateOTP(keyProfile.Info);
otp = OTP.generateOTP(info);
} catch (Exception e) {
e.printStackTrace();
return;
}
keyProfile.Code = otp;
tvOtp.setText(otp.substring(0, 3) + " " + otp.substring(3));
_keyProfile.setCode(otp);
_textOtp.setText(otp.substring(0, 3) + " " + otp.substring(3));
}
@Override
@ -90,15 +90,11 @@ public class AddProfileActivity extends AppCompatActivity {
}
}
private void setPreferredTheme()
{
private void setPreferredTheme() {
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);
} else
{
} else {
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_EXCEPTION = 1;
private EditText textPassword;
private EditText _textPassword;
private SlotCollection slots;
private LinearLayout boxFingerprint;
private SwirlView imgFingerprint;
private TextView textFingerprint;
private FingerprintUiHelper fingerHelper;
private Cipher fingerCipher;
private SlotCollection _slots;
private FingerprintUiHelper _fingerHelper;
private Cipher _fingerCipher;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auth);
textPassword = (EditText) findViewById(R.id.text_password);
boxFingerprint = (LinearLayout) findViewById(R.id.box_fingerprint);
imgFingerprint = (SwirlView) findViewById(R.id.img_fingerprint);
textFingerprint = (TextView) findViewById(R.id.text_fingerprint);
_textPassword = (EditText) findViewById(R.id.text_password);
LinearLayout boxFingerprint = (LinearLayout) findViewById(R.id.box_fingerprint);
SwirlView imgFingerprint = (SwirlView) findViewById(R.id.img_fingerprint);
TextView textFingerprint = (TextView) findViewById(R.id.text_fingerprint);
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
Context context = getApplicationContext();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
FingerprintManager manager = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
if (ActivityCompat.checkSelfPermission(context, Manifest.permission.USE_FINGERPRINT) == PackageManager.PERMISSION_GRANTED && manager.isHardwareDetected()) {
if (slots.has(FingerprintSlot.class)) {
if (_slots.has(FingerprintSlot.class)) {
try {
KeyStoreHandle handle = new KeyStoreHandle();
if (handle.keyExists()) {
SecretKey key = handle.getKey();
fingerCipher = Slot.createCipher(key, Cipher.DECRYPT_MODE);
fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this);
_fingerCipher = Slot.createCipher(key, Cipher.DECRYPT_MODE);
_fingerHelper = new FingerprintUiHelper(manager, imgFingerprint, textFingerprint, this);
boxFingerprint.setVisibility(View.VISIBLE);
}
} catch (Exception e) {
@ -104,25 +101,25 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
}
private MasterKey decryptPasswordSlot(PasswordSlot slot) throws Exception {
char[] password = AuthHelper.getPassword(textPassword, true);
char[] password = AuthHelper.getPassword(_textPassword, true);
SecretKey key = slot.deriveKey(password);
CryptoUtils.zero(password);
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 {
return slots.decrypt(slot, fingerCipher);
return _slots.decrypt(slot, _fingerCipher);
}
private <T extends Slot> void trySlots(Class<T> type) {
try {
if (!slots.has(type)) {
if (!_slots.has(type)) {
throw new RuntimeException();
}
MasterKey masterKey = null;
for (Slot slot : slots.findAll(type)) {
for (Slot slot : _slots.findAll(type)) {
try {
if (slot instanceof PasswordSlot) {
masterKey = decryptPasswordSlot((PasswordSlot) slot);
@ -132,8 +129,7 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
throw new RuntimeException();
}
break;
} catch (SlotIntegrityException e) {
}
} catch (SlotIntegrityException e) { }
}
if (masterKey == null) {
@ -165,8 +161,8 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
public void onResume() {
super.onResume();
if (fingerHelper != null) {
fingerHelper.startListening(new FingerprintManager.CryptoObject(fingerCipher));
if (_fingerHelper != null) {
_fingerHelper.startListening(new FingerprintManager.CryptoObject(_fingerCipher));
}
}
@ -174,8 +170,8 @@ public class AuthActivity extends AppCompatActivity implements FingerprintUiHelp
public void onPause() {
super.onPause();
if (fingerHelper != null) {
fingerHelper.stopListening();
if (_fingerHelper != null) {
_fingerHelper.stopListening();
}
}

View file

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

View file

@ -9,24 +9,15 @@ import android.view.ViewGroup;
import android.widget.LinearLayout;
public class EditProfileBottomSheetdialog extends BottomSheetDialogFragment {
LinearLayout copyLayout;
LinearLayout _copyLayout;
public static EditProfileBottomSheetdialog getInstance() {
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()
{
return copyLayout;
return _copyLayout;
}
@Nullable

View file

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

View file

@ -2,22 +2,24 @@ package me.impy.aegis;
import java.io.Serializable;
import me.impy.aegis.crypto.KeyInfo;
import me.impy.aegis.db.DatabaseEntry;
public class KeyProfile implements Serializable {
public String Name;
public String Icon;
public String Code;
public String Issuer;
public KeyInfo Info;
public int Order;
public int ID;
private String _code;
private DatabaseEntry _entry;
public int compareTo(KeyProfile another) {
if (this.Order>another.Order){
return -1;
}else{
return 1;
}
public KeyProfile(DatabaseEntry entry) {
_entry = entry;
}
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;
public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileAdapter.KeyProfileHolder> implements ItemTouchHelperAdapter {
private final List<KeyProfileHolder> lstHolders;
private ArrayList<KeyProfile> mKeyProfiles;
private Handler uiHandler;
private static ItemClickListener itemClickListener;
private static LongItemClickListener longItemClickListener;
private final List<KeyProfileHolder> _holders;
private ArrayList<KeyProfile> _keyProfiles;
private Handler _uiHandler;
private static ItemClickListener _itemClickListener;
private static LongItemClickListener _longItemClickListener;
public KeyProfileAdapter(ArrayList<KeyProfile> keyProfiles) {
mKeyProfiles = keyProfiles;
lstHolders = new ArrayList<>();
uiHandler = new Handler();
_keyProfiles = keyProfiles;
_holders = new ArrayList<>();
_uiHandler = new Handler();
}
@Override
public void onItemDismiss(int position) {
return;
}
private void remove(int position) {
mKeyProfiles.remove(position);
_keyProfiles.remove(position);
notifyItemRemoved(position);
}
@Override
public void onItemMove(int firstPosition, int secondPosition) {
Collections.swap(mKeyProfiles, firstPosition, secondPosition);
Collections.swap(_keyProfiles, firstPosition, secondPosition);
notifyItemMoved(firstPosition, secondPosition);
mKeyProfiles.get(firstPosition).Order = secondPosition;
_keyProfiles.get(firstPosition).getEntry().setOrder(secondPosition);
adjustOrder(secondPosition);
}
@ -61,12 +61,12 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileAdapter.Ke
Comparator<KeyProfile> comparator = new Comparator<KeyProfile>() {
@Override
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++) {
mKeyProfiles.get(i).Order = i + 1;
for (int i = startPosition; i < _keyProfiles.size(); i++) {
_keyProfiles.get(i).getEntry().setOrder(i + 1);
}
}
@ -79,130 +79,127 @@ public class KeyProfileAdapter extends RecyclerView.Adapter<KeyProfileAdapter.Ke
@Override
public void onBindViewHolder(final KeyProfileHolder holder, int position) {
holder.setData(mKeyProfiles.get(position));
holder.setData(_keyProfiles.get(position));
holder.updateCode();
lstHolders.add(holder);
_holders.add(holder);
Runnable runnable = new Runnable() {
@Override
public void run() {
// check if this key profile still exists
if (lstHolders.contains(holder)) {
if (_holders.contains(holder)) {
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
public int getItemCount() {
return mKeyProfiles.size();
return _keyProfiles.size();
}
public static class KeyProfileHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
TextView profileName;
TextView profileCode;
TextView profileIssuer;
ImageView profileDrawable;
KeyProfile keyProfile;
ProgressBar progressBar;
TextView _profileName;
TextView _profileCode;
TextView _profileIssuer;
ImageView _profileDrawable;
KeyProfile _keyProfile;
ProgressBar _progressBar;
View _itemView;
KeyProfileHolder(final View itemView) {
super(itemView);
_itemView = itemView;
profileName = (TextView) itemView.findViewById(R.id.profile_name);
profileCode = (TextView) itemView.findViewById(R.id.profile_code);
profileIssuer = (TextView) itemView.findViewById(R.id.profile_issuer);
profileDrawable = (ImageView) itemView.findViewById(R.id.ivTextDrawable);
progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar);
_profileName = (TextView) itemView.findViewById(R.id.profile_name);
_profileCode = (TextView) itemView.findViewById(R.id.profile_code);
_profileIssuer = (TextView) itemView.findViewById(R.id.profile_issuer);
_profileDrawable = (ImageView) itemView.findViewById(R.id.ivTextDrawable);
_progressBar = (ProgressBar) itemView.findViewById(R.id.progressBar);
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
public void setData(KeyProfile profile) {
this.keyProfile = profile;
profileName.setText(profile.Name);
profileCode.setText(profile.Code);
_keyProfile = profile;
_profileName.setText(profile.getEntry().getName());
_profileCode.setText(profile.getCode());
// 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());
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() {
progressBar.setProgress(1000);
if (this.keyProfile == null) {
_progressBar.setProgress(1000);
if (_keyProfile == null) {
return;
}
String otp = "";
try {
otp = OTP.generateOTP(this.keyProfile.Info);
otp = OTP.generateOTP(_keyProfile.getEntry().getInfo());
} catch (Exception e) {
throw new UndeclaredThrowableException(e);
}
this.keyProfile.Code = otp;
profileCode.setText(otp.substring(0, 3) + " " + otp.substring(3));
_keyProfile.setCode(otp);
_profileCode.setText(otp.substring(0, 3) + " " + otp.substring(3));
long millisTillRotation = keyProfile.Info.getMillisTillNextRotation();
long period = keyProfile.Info.getPeriod() * 1000;
long millisTillRotation = _keyProfile.getEntry().getInfo().getMillisTillNextRotation();
long period = _keyProfile.getEntry().getInfo().getPeriod() * 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.setInterpolator(new LinearInterpolator());
animation.start();
}
private TextDrawable generateTextDrawable(KeyProfile profile) {
if (profileName == null)
if (_profileName == null)
return null;
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 newDrawable;
return TextDrawable.builder().buildRound(profile.getEntry().getName().substring(0, 1).toUpperCase(), profileKeyColor);
}
@Override
public void onClick(View view) {
itemClickListener.onItemClick(getAdapterPosition(), view);
_itemClickListener.onItemClick(getAdapterPosition(), view);
}
@Override
public boolean onLongClick(View view) {
longItemClickListener.onLongItemClick(getAdapterPosition(), view);
_longItemClickListener.onLongItemClick(getAdapterPosition(), view);
return true;
}
}
public void setOnItemClickListener(ItemClickListener clickListener) {
KeyProfileAdapter.itemClickListener = clickListener;
KeyProfileAdapter._itemClickListener = clickListener;
}
public void setOnLongItemClickListener(LongItemClickListener clickListener) {
KeyProfileAdapter.longItemClickListener = clickListener;
KeyProfileAdapter._longItemClickListener = clickListener;
}
public interface ItemClickListener
{
public interface ItemClickListener {
void onItemClick(int position, View v);
}
public interface LongItemClickListener
{
public interface LongItemClickListener {
void onLongItemClick(int position, View v);
}
}

View file

@ -26,19 +26,17 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.UndeclaredThrowableException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import me.impy.aegis.crypto.MasterKey;
import me.impy.aegis.crypto.otp.OTP;
import me.impy.aegis.db.DatabaseEntry;
import me.impy.aegis.db.DatabaseManager;
import me.impy.aegis.ext.FreeOTPImporter;
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_IMPORT = 4;
RecyclerView rvKeyProfiles;
KeyProfileAdapter mKeyProfileAdapter;
ArrayList<KeyProfile> mKeyProfiles = new ArrayList<>();
private DatabaseManager db;
private KeyProfileAdapter _keyProfileAdapter;
private ArrayList<KeyProfile> _keyProfiles = new ArrayList<>();
private DatabaseManager _db;
boolean nightMode = false;
int clickedItemPosition = -1;
private boolean _nightMode = false;
private int _clickedItemPosition = -1;
private Menu _menu;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
db = new DatabaseManager(getApplicationContext());
_db = new DatabaseManager(getApplicationContext());
SharedPreferences prefs = this.getSharedPreferences("me.impy.aegis", Context.MODE_PRIVATE);
if (!prefs.getBoolean("passedIntro", false)) {
@ -69,14 +68,14 @@ public class MainActivity extends AppCompatActivity {
startActivityForResult(intro, CODE_DO_INTRO);
} else {
try {
db.load();
_db.load();
} catch (Exception e) {
// TODO: feedback
throw new UndeclaredThrowableException(e);
}
if (!db.isDecrypted()) {
if (!_db.isDecrypted()) {
Intent intent = new Intent(this, AuthActivity.class);
intent.putExtra("slots", db.getFile().getSlots());
intent.putExtra("slots", _db.getFile().getSlots());
startActivityForResult(intent, CODE_DECRYPT);
} else {
loadKeyProfiles();
@ -85,7 +84,7 @@ public class MainActivity extends AppCompatActivity {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPreferences.getBoolean("pref_night_mode", false)) {
nightMode = true;
_nightMode = true;
setTheme(R.style.AppTheme_Dark_NoActionBar);
} else {
setPreferredTheme();
@ -102,31 +101,31 @@ public class MainActivity extends AppCompatActivity {
startActivityForResult(scannerActivity, CODE_GET_KEYINFO);
});
rvKeyProfiles = (RecyclerView) findViewById(R.id.rvKeyProfiles);
RecyclerView rvKeyProfiles = (RecyclerView) findViewById(R.id.rvKeyProfiles);
LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
rvKeyProfiles.setLayoutManager(mLayoutManager);
mKeyProfileAdapter = new KeyProfileAdapter(mKeyProfiles);
mKeyProfileAdapter.setOnItemClickListener((position, v) -> {
clickedItemPosition = position;
_keyProfileAdapter = new KeyProfileAdapter(_keyProfiles);
_keyProfileAdapter.setOnItemClickListener((position, v) -> {
_clickedItemPosition = position;
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);
touchHelper.attachToRecyclerView(rvKeyProfiles);
rvKeyProfiles.setAdapter(mKeyProfileAdapter);
rvKeyProfiles.setAdapter(_keyProfileAdapter);
Comparator<KeyProfile> comparator = new Comparator<KeyProfile>() {
@Override
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
@ -151,6 +150,10 @@ public class MainActivity extends AppCompatActivity {
}
private void onImportResult(int resultCode, Intent data) {
if (resultCode != RESULT_OK) {
return;
}
InputStream stream = null;
try {
try {
@ -162,8 +165,8 @@ public class MainActivity extends AppCompatActivity {
FreeOTPImporter importer = new FreeOTPImporter(stream);
try {
for (KeyProfile profile : importer.convert()) {
addKey(profile);
for (DatabaseEntry profile : importer.convert()) {
addKey(new KeyProfile(profile));
}
} catch (Exception e) {
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 {
if (stream != null) {
try { stream.close(); }
catch (Exception e) { }
try {
stream.close();
} catch (Exception e) {
}
}
}
@ -203,27 +208,29 @@ public class MainActivity extends AppCompatActivity {
}
private void addKey(KeyProfile profile) {
DatabaseEntry entry = profile.getEntry();
String otp;
try {
otp = OTP.generateOTP(profile.Info);
otp = OTP.generateOTP(entry.getInfo());
} catch (Exception e) {
e.printStackTrace();
return;
}
profile.Name = profile.Info.getAccountName();
profile.Order = mKeyProfiles.size() + 1;
profile.Code = otp;
entry.setName(entry.getInfo().getAccountName());
entry.setOrder(_keyProfiles.size() + 1);
profile.setCode(otp);
try {
db.addKey(profile);
_db.addKey(entry);
} catch (Exception e) {
e.printStackTrace();
// TODO: feedback
return;
}
mKeyProfiles.add(profile);
mKeyProfileAdapter.notifyDataSetChanged();
_keyProfiles.add(profile);
_keyProfileAdapter.notifyDataSetChanged();
}
private void onDoIntroResult(int resultCode, Intent data) {
@ -235,9 +242,9 @@ public class MainActivity extends AppCompatActivity {
MasterKey key = (MasterKey) data.getSerializableExtra("key");
try {
db.load();
if (!db.isDecrypted()) {
db.setMasterKey(key);
_db.load();
if (!_db.isDecrypted()) {
_db.setMasterKey(key);
}
} catch (Exception e) {
// TODO: feedback
@ -250,7 +257,7 @@ public class MainActivity extends AppCompatActivity {
private void onDecryptResult(int resultCode, Intent data) {
MasterKey key = (MasterKey) data.getSerializableExtra("key");
try {
db.setMasterKey(key);
_db.setMasterKey(key);
} catch (Exception e) {
// TODO: feedback
throw new UndeclaredThrowableException(e);
@ -262,21 +269,12 @@ public class MainActivity extends AppCompatActivity {
@Override
protected void onResume() {
super.onResume();
mKeyProfileAdapter.notifyDataSetChanged();
_keyProfileAdapter.notifyDataSetChanged();
setPreferredTheme();
}
@Override
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();
super.onPause();
}
@ -298,7 +296,7 @@ public class MainActivity extends AppCompatActivity {
copyLayout.setOnClickListener(view -> {
bottomDialog.dismiss();
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);
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 -> {
bottomDialog.dismiss();
KeyProfile keyProfile = mKeyProfiles.get(clickedItemPosition);
KeyProfile keyProfile = _keyProfiles.get(_clickedItemPosition);
deleteProfile(keyProfile);
});
@ -326,14 +324,14 @@ public class MainActivity extends AppCompatActivity {
.setMessage("Are you sure you want to delete this profile?")
.setPositiveButton(android.R.string.yes, (dialog, which) -> {
try {
db.removeKey(profile);
_db.removeKey(profile.getEntry());
} catch (Exception e) {
e.printStackTrace();
//TODO: feedback
return;
}
mKeyProfiles.remove(clickedItemPosition);
mKeyProfileAdapter.notifyItemRemoved(clickedItemPosition);
_keyProfiles.remove(_clickedItemPosition);
_keyProfileAdapter.notifyItemRemoved(_clickedItemPosition);
})
.setNegativeButton(android.R.string.no, (dialog, which) -> {
})
@ -342,7 +340,9 @@ public class MainActivity extends AppCompatActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
_menu = menu;
getMenuInflater().inflate(R.menu.menu_main, menu);
updateLockIcon();
return true;
}
@ -367,15 +367,11 @@ public class MainActivity extends AppCompatActivity {
}
}
private void initializeAppShortcuts()
{
private void initializeAppShortcuts() {
String mode = getIntent().getStringExtra("Action");
if(mode != null)
{
if (mode != null) {
Log.println(Log.DEBUG, "MODE: ", mode);
if(Objects.equals(mode, "Scan"))
{
Log.println(Log.DEBUG, "OKK ", "OKKK");
if (Objects.equals(mode, "Scan")) {
Intent scannerActivity = new Intent(getApplicationContext(), ScannerActivity.class);
startActivityForResult(scannerActivity, CODE_GET_KEYINFO);
}
@ -407,17 +403,16 @@ public class MainActivity extends AppCompatActivity {
}
}
private void setPreferredTheme()
{
private void setPreferredTheme() {
boolean restart = false;
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if (sharedPreferences.getBoolean("pref_night_mode", false)) {
if(!nightMode) {
if (!_nightMode) {
setTheme(R.style.AppTheme_Dark_NoActionBar);
restart = true;
}
} else {
if(nightMode) {
if (_nightMode) {
setTheme(R.style.AppTheme_Default_NoActionBar);
restart = true;
}
@ -430,12 +425,12 @@ public class MainActivity extends AppCompatActivity {
}
private void saveDatabase() {
if (!db.isDecrypted()) {
if (!_db.isDecrypted()) {
return;
}
try {
db.save();
_db.save();
} catch (Exception e) {
//TODO: feedback
throw new UndeclaredThrowableException(e);
@ -443,11 +438,23 @@ public class MainActivity extends AppCompatActivity {
}
private void loadKeyProfiles() {
updateLockIcon();
try {
mKeyProfiles.addAll(db.getKeys());
mKeyProfileAdapter.notifyDataSetChanged();
for (DatabaseEntry entry : _db.getKeys()) {
_keyProfiles.add(new KeyProfile(entry));
}
_keyProfileAdapter.notifyDataSetChanged();
} catch (Exception e) {
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;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceFragment;
import android.preference.PreferenceManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.app.AppCompatDelegate;
import android.widget.Toast;
public class PreferencesActivity extends AppCompatActivity {
@ -16,24 +13,23 @@ public class PreferencesActivity extends AppCompatActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedPreferences mySharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
if(mySharedPreferences.getBoolean("pref_night_mode", false))
{
if (mySharedPreferences.getBoolean("pref_night_mode", false)) {
setTheme(R.style.AppTheme_Dark);
} else
{
} else {
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 {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
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.Result;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import me.dm7.barcodescanner.core.IViewFinder;
import me.dm7.barcodescanner.zxing.ZXingScannerView;
import me.impy.aegis.crypto.KeyInfo;
import me.impy.aegis.db.DatabaseEntry;
import me.impy.aegis.helpers.SquareFinderView;
public class ScannerActivity extends Activity implements ZXingScannerView.ResultHandler {
private ZXingScannerView mScannerView;
private static final int CODE_ASK_PERMS = 0;
private ZXingScannerView _scannerView;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
mScannerView = new ZXingScannerView(this) {
_scannerView = new ZXingScannerView(this) {
@Override
protected IViewFinder createViewFinderView(Context context) {
return new SquareFinderView(context);
}
};
setContentView(mScannerView); // Set the scanner view as the content view
mScannerView.setFormats(getSupportedFormats());
setContentView(_scannerView);
_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
@ -48,54 +50,39 @@ public class ScannerActivity extends Activity implements ZXingScannerView.Result
@Override
public void onPause() {
super.onPause();
mScannerView.stopCamera(); // Stop camera on pause
_scannerView.stopCamera();
}
@Override
public void handleResult(Result rawResult) {
// Do something with the result here
Toast.makeText(this, rawResult.getText(), Toast.LENGTH_SHORT).show();
try {
//TODO: Handle non TOTP / HOTP qr codes.
KeyInfo info = KeyInfo.fromURL(rawResult.getText());
KeyProfile keyProfile = new KeyProfile();
keyProfile.Info = info;
KeyProfile profile = new KeyProfile(new DatabaseEntry(info));
Intent resultIntent = new Intent();
resultIntent.putExtra("KeyProfile", keyProfile);
resultIntent.putExtra("KeyProfile", profile);
setResult(Activity.RESULT_OK, resultIntent);
finish();
} 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:
mScannerView.resumeCameraPreview(this);
_scannerView.resumeCameraPreview(this);
}
@Override
public void onRequestPermissionsResult(int requestCode, String permissions[], int[] grantResults) {
switch (requestCode) {
case 1: {
// If request is cancelled, the result arrays are empty.
case CODE_ASK_PERMS: {
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
mScannerView.setResultHandler(this); // Register ourselves as a handler for scan results.
mScannerView.startCamera(); // Start camera on resume
_scannerView.setResultHandler(this);
_scannerView.startCamera();
} else {
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_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_p = 1;

View file

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

View file

@ -15,17 +15,17 @@ import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
public class KeyStoreHandle {
private final KeyStore keyStore;
private final KeyStore _keyStore;
private static final String KEY_NAME = "AegisKey";
private static final String STORE_NAME = "AndroidKeyStore";
public KeyStoreHandle() throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException {
keyStore = KeyStore.getInstance(STORE_NAME);
keyStore.load(null);
_keyStore = KeyStore.getInstance(STORE_NAME);
_keyStore.load(null);
}
public boolean keyExists() throws KeyStoreException {
return keyStore.containsAlias(KEY_NAME);
return _keyStore.containsAlias(KEY_NAME);
}
public SecretKey generateKey(boolean authRequired) throws Exception {
@ -47,6 +47,6 @@ public class KeyStoreHandle {
}
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();
}
public boolean isEmpty() {
return _slots.size() == 0;
}
public <T extends Slot> T find(Class<T> type) {
for (Slot slot : this) {
if (slot.getClass() == type) {

View file

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

View file

@ -1,27 +1,67 @@
package me.impy.aegis.db;
import org.json.JSONException;
import org.json.JSONObject;
public class DatabaseEntry {
public int ID;
public String Name;
public String URL;
public int Order;
import java.io.Serializable;
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();
obj.put("id", ID);
obj.put("name", Name);
obj.put("url", URL);
obj.put("order", Order);
obj.put("id", _id);
obj.put("name", _name);
obj.put("url", _info.getURL());
obj.put("order", _order);
return obj;
}
public void deserialize(JSONObject obj) throws JSONException {
ID = obj.getInt("id");
Name = obj.getString("name");
URL = obj.getString("url");
Order = obj.getInt("order");
public void deserialize(JSONObject obj) throws Exception {
_id = obj.getInt("id");
_name = obj.getString("name");
_info = KeyInfo.fromURL(obj.getString("url"));
_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;
public class DatabaseFile {
private static final byte bSectionEncryptionParameters = 0x00;
private static final byte bSectionSlots = 0x01;
private static final byte bSectionEnd = (byte) 0xFF;
private static final byte bVersion = 1;
private static final String dbFilename = "aegis.db";
private static final byte SECTION_ENCRYPTION_PARAMETERS = 0x00;
private static final byte SECTION_SLOTS = 0x01;
private static final byte SECTION_END = (byte) 0xFF;
private static final byte VERSION = 1;
private static final String FILENAME = "aegis.db";
private final byte[] bHeader;
private final byte[] HEADER;
private byte[] content;
private CryptParameters cryptParameters;
private SlotCollection slots;
private byte[] _content;
private CryptParameters _cryptParameters;
private SlotCollection _slots;
public DatabaseFile() {
try {
bHeader = "AEGIS".getBytes("US_ASCII");
HEADER = "AEGIS".getBytes("US_ASCII");
} catch (Exception e) {
throw new UndeclaredThrowableException(e);
}
slots = new SlotCollection();
_slots = new SlotCollection();
}
public byte[] serialize() throws IOException {
CryptParameters cryptParams = getCryptParameters();
byte[] content = getContent();
CryptParameters cryptParams = getCryptParameters();
// this is dumb, java doesn't provide an endianness-aware data stream
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
DataOutputStream stream = new DataOutputStream(byteStream);
stream.write(bHeader);
stream.write(bVersion);
stream.write(HEADER);
stream.write(VERSION);
if (cryptParams != null) {
LittleByteBuffer paramBuffer = LittleByteBuffer.allocate(CryptoUtils.CRYPTO_NONCE_SIZE + CryptoUtils.CRYPTO_TAG_SIZE);
paramBuffer.put(cryptParams.Nonce);
paramBuffer.put(cryptParams.Tag);
writeSection(stream, bSectionEncryptionParameters, paramBuffer.array());
writeSection(stream, SECTION_ENCRYPTION_PARAMETERS, paramBuffer.array());
}
if (slots != null) {
byte[] bytes = SlotCollection.serialize(slots);
writeSection(stream, bSectionSlots, bytes);
if (!_slots.isEmpty()) {
byte[] bytes = SlotCollection.serialize(_slots);
writeSection(stream, SECTION_SLOTS, bytes);
}
writeSection(stream, bSectionEnd, null);
writeSection(stream, SECTION_END, null);
stream.write(content);
return byteStream.toByteArray();
}
@ -67,25 +67,25 @@ public class DatabaseFile {
public void deserialize(byte[] data) throws Exception {
LittleByteBuffer buffer = LittleByteBuffer.wrap(data);
byte[] header = new byte[bHeader.length];
byte[] header = new byte[HEADER.length];
buffer.get(header);
if (!Arrays.equals(header, bHeader)) {
if (!Arrays.equals(header, HEADER)) {
throw new Exception("Bad header");
}
// TODO: support different version deserialization providers
byte version = buffer.get();
if (version != bVersion) {
if (version != VERSION) {
throw new Exception("Unsupported version");
}
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);
switch (s.ID) {
case bSectionEncryptionParameters:
case SECTION_ENCRYPTION_PARAMETERS:
assertLength(s.Data, CryptoUtils.CRYPTO_NONCE_SIZE + CryptoUtils.CRYPTO_TAG_SIZE);
byte[] nonce = new byte[CryptoUtils.CRYPTO_NONCE_SIZE];
@ -98,7 +98,7 @@ public class DatabaseFile {
Tag = tag;
}};
break;
case bSectionSlots:
case SECTION_SLOTS:
slots = SlotCollection.deserialize(s.Data);
break;
}
@ -113,19 +113,19 @@ public class DatabaseFile {
}
public boolean isEncrypted() {
return slots != null && cryptParameters != null;
return !_slots.isEmpty() && _cryptParameters != null;
}
public void save(Context context) throws IOException {
byte[] data = serialize();
FileOutputStream file = context.openFileOutput(dbFilename, Context.MODE_PRIVATE);
FileOutputStream file = context.openFileOutput(FILENAME, Context.MODE_PRIVATE);
file.write(data);
file.close();
}
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()];
file.read(data);
file.close();
@ -169,27 +169,27 @@ public class DatabaseFile {
}
public byte[] getContent() {
return content;
return _content;
}
public void setContent(byte[] content) {
this.content = content;
_content = content;
}
public CryptParameters getCryptParameters() {
return cryptParameters;
return _cryptParameters;
}
public void setCryptParameters(CryptParameters parameters) {
this.cryptParameters = parameters;
_cryptParameters = parameters;
}
public SlotCollection getSlots() {
return slots;
return _slots;
}
public void setSlots(SlotCollection slots) {
this.slots = slots;
_slots = slots;
}
private static class section {

View file

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

View file

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

View file

@ -3,7 +3,7 @@ package me.impy.aegis.ext;
import java.io.InputStream;
import java.util.List;
import me.impy.aegis.KeyProfile;
import me.impy.aegis.db.DatabaseEntry;
public abstract class KeyConverter {
protected InputStream _stream;
@ -12,5 +12,5 @@ public abstract class KeyConverter {
_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 {
private final ItemTouchHelperAdapter mAdapter;
private final ItemTouchHelperAdapter _adapter;
public SimpleItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
mAdapter = adapter;
_adapter = adapter;
}
@Override
@ -31,13 +31,13 @@ public class SimpleItemTouchHelperCallback extends ItemTouchHelper.Callback {
@Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
mAdapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
_adapter.onItemMove(viewHolder.getAdapterPosition(), target.getAdapterPosition());
return true;
}
@Override
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.*;
public class HOTPTest {
private class testVector {
public long Count;
public String OTP;
}
// https://tools.ietf.org/html/rfc4226#page-32
private final testVector[] _vectors = {
new testVector(){{ Count = 0; OTP = "755224"; }},
new testVector(){{ Count = 1; OTP = "287082"; }},
new testVector(){{ Count = 2; OTP = "359152"; }},
new testVector(){{ Count = 3; OTP = "969429"; }},
new testVector(){{ Count = 4; OTP = "338314"; }},
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 String[] _vectors = {
"755224", "287082",
"359152", "969429",
"338314", "254676",
"287922", "162583",
"399871", "520489"
};
private final byte[] _secret = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
private final byte[] _secret = new byte[] {
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
};
@Test
public void vectors_match() throws Exception {
for (testVector v : _vectors) {
String otp = HOTP.generateOTP(_secret, v.Count, 6, false, -1);
assertEquals(v.OTP, otp);
public void vectorsMatch() throws Exception {
for (int i = 0; i < _vectors.length; i++) {
String otp = HOTP.generateOTP(_secret, i, 6, false, -1);
assertEquals(_vectors[i], otp);
}
}
}

View file

@ -35,22 +35,27 @@ public class TOTPTest {
new testVector(){{ Time = "0000000027BC86AA"; OTP = "47863826"; Mode = "HmacSHA512"; }}
};
private final byte[] _seed = new byte[] { 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
private final byte[] _seed = new byte[] {
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30
};
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,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32
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, 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,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36,
0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30,
0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34
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, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32,
0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34
};
@Test
public void vectors_match() throws Exception {
public void vectorsMatch() throws Exception {
for (testVector v : _vectors) {
byte[] seed;