Używam następującego do szyfrowania/odszyfrowywania na poziomie kolumny, tj. jest stosowany tylko do wrażliwych danych.
class EncryptDecrypt {
private Cipher cipher;
private static SecretKeySpec secretKeySpec;
private static IvParameterSpec ivParameterSpec;
private boolean do_encrypt = true;
/**
* Construct EncryptDecrypt instance that checks the current logged-in
* user status; basically if the user is the special NOUSER, where
* the user does not use a password, then encryption decryption is
* skipped, the alternative constructor does not undergo this check and
* thus will always encrypt (see alternative)
* @param context The context, required for database usage (user)
* @param skey The secret key to be used to encrypt/decrypt
* @param userid The userid (so that the salt can be obtained)
*/
EncryptDecrypt(Context context, String skey, long userid) {
DBUsersMethods users = new DBUsersMethods(context);
if (MainActivity.mLoginMode == LoginActivity.LOGINMODE_NONE) {
do_encrypt = false;
return;
}
String saltasString = users.getUserSalt(userid);
String paddedskey = (skey + saltasString).substring(0,16);
secretKeySpec = new SecretKeySpec(paddedskey.getBytes(),"AES/CBC/PKCS5Padding");
ivParameterSpec = new IvParameterSpec((saltasString.substring(0,16)).getBytes());
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (Exception e){
}
}
/**
* Construct EncryptDecrypt instance that does not check user login-in
* mode, thus the assumption is that this user is NOT the special user
* NOUSER that doesn't require a password to login; this constructor
* is designed to ONLY be used when a user has been added by NOUSER,
* and to then encrypt the data using the enccryptForced method solely
* to encrypt any existing card data for the new user that has a password.
*
* @param context The context, required for database usage (user)
* @param skey The secret key to be used to encrypt/decrypt
* @param userid The userid (so that the salt can be obtained)
* @Param mode Not used other than to distinguish constructor
*/
EncryptDecrypt(Context context, String skey, long userid, boolean mode) {
DBUsersMethods users = new DBUsersMethods(context);
String saltasString = users.getUserSalt(userid);
String paddedskey = (skey + saltasString).substring(0,16);
secretKeySpec = new SecretKeySpec(paddedskey.getBytes(),"AES/CBC/PKCS5Padding");
ivParameterSpec = new IvParameterSpec((saltasString.substring(0,16)).getBytes());
try {
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
} catch (Exception e){
//e.printStackTrace();
}
}
/**
* Normal encryption routine that will not encrypt data if the user is
* the special case NOUSER (i.e LOGIN mode is NOUSER), otherwise data
* is encrypted.
*
* @Param toEncrypt The string to be encrypted
* @return The encryted (or not if NOUSER) data as a string
*/
String encrypt(String toEncrypt) {
if (!do_encrypt) {
return toEncrypt;
}
byte[] encrypted;
try {
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,ivParameterSpec);
encrypted = cipher.doFinal(toEncrypt.getBytes());
} catch (Exception e) {
//e.printStackTrace();
return null;
}
return Base64.encodeToString(encrypted,Base64.DEFAULT);
}
/**
* Encryption, irrespective of the USER type, noting that this should
* only be used in conjunction with an EncryptDecrypt instance created
* using the 2nd/extended constructor
*
* @param toEncrypt The string to be encrypted
* @return The encrypted data as a string
*/
String encryptForced(String toEncrypt) {
byte[] encrypted;
try {
cipher.init(Cipher.ENCRYPT_MODE,secretKeySpec,ivParameterSpec);
encrypted = cipher.doFinal(toEncrypt.getBytes());
} catch (Exception e) {
//e.printStackTrace();
return null;
}
return Base64.encodeToString(encrypted,Base64.DEFAULT);
}
/**
* Decrypt an encrypted string
* @param toDecrypt The encrypted string to be decrypted
* @return The decrypted string
*/
String decrypt(String toDecrypt) {
if (!do_encrypt) {
return toDecrypt;
}
byte[] decrypted;
try {
cipher.init(Cipher.DECRYPT_MODE,secretKeySpec,ivParameterSpec);
decrypted = cipher.doFinal(Base64.decode(toDecrypt,Base64.DEFAULT));
} catch (Exception e) {
//e.printStackTrace();
return null;
}
return new String(decrypted);
}
}
Przykładowe użycie (szyfrowanie):-
........
db.beginTransaction();
........
newed = new EncryptDecrypt(mContext,newPassword,newUserId,true);
// Process the MatrixCursor created above
while (mxc.moveToNext()) {
// Generate the whereclause to determine which row is to be updated
whereclause = DBCardsTableConstants.CARDID.getDBColumnName() + "=?";
// Set the value to replace the ? plcaeholder with the current CARDID
whereargs = new String[]{
Long.toString(
mxc.getLong(
mxc.getColumnIndex(
DBCardsTableConstants.CARDID.getDBColumnName()
)
)
)
};
String mxc_nameoncard = mxc.getString(mxc.getColumnIndex(DBCardsTableConstants.CARDNAMEONCARD.getDBColumnName()));
String mxc_number = mxc.getString(mxc.getColumnIndex(DBCardsTableConstants.CARDNUMBER.getDBColumnName()));
String mxc_cvv = mxc.getString(mxc.getColumnIndex(DBCardsTableConstants.CARDCVVCODE.getDBColumnName()));
String mxc_pin = mxc.getString(mxc.getColumnIndex(DBCardsTableConstants.CARDPIN.getDBColumnName()));
String mxc_exp = mxc.getString(mxc.getColumnIndex(DBCardsTableConstants.CARDEXPIRYDATE.getDBColumnName()));
String enc_nameoncard = newed.encryptForced(mxc_nameoncard);
String enc_number = newed.encryptForced(mxc_number);
String enc_cvv = newed.encryptForced(mxc_cvv);
String enc_pin = newed.encryptForced(mxc_pin);
String enc_exp = newed.encryptForced(mxc_exp);
// Prepare the data to be updated.
ContentValues cv = new ContentValues();
cv.put(DBCardsTableConstants.CARDOWNER.getDBColumnName(),
newUserId
);
cv.put(DBCardsTableConstants.CARDNAMEONCARD.getDBColumnName(),enc_nameoncard);
cv.put(DBCardsTableConstants.CARDNUMBER.getDBColumnName(),enc_number);
cv.put(DBCardsTableConstants.CARDCVVCODE.getDBColumnName(),enc_cvv);
cv.put(DBCardsTableConstants.CARDPIN.getDBColumnName(),enc_pin);
cv.put(DBCardsTableConstants.CARDEXPIRYDATE.getDBColumnName(),enc_exp);
// Perform the update
db.update(DBCardsTableConstants.CARDS.getDBTableName(),
cv,
whereclause,
whereargs
);
}
// Done with the MatrixCursor so close it
mxc.close();
// Done updating so apply all the changes
db.setTransactionSuccessful();
// Done with the transaction
db.endTransaction();
Przykładowe użycie (odszyfrowywanie)
Cursor getDecyrptedCard(long cardid) {
EncryptDecrypt ed = new EncryptDecrypt(mContext,
LoginActivity.getCurrentUserPassWord(),
MainActivity.mCurrentUserid);
MatrixCursor cnvcsr = new MatrixCursor(mCardsTableColumns,10);
String whereclause = DBCardsTableConstants.CARDID.getDBColumnName() +
"=? AND " +
DBCardsTableConstants.CARDOWNER.getDBColumnName() +
"=?";
String[] whereargs = {Long.toString(cardid), Long.toString(MainActivity.mCurrentUserid)};
Cursor basecsr = db.query(DBCardsTableConstants.CARDS.getDBTableName(),
null,
whereclause,
whereargs,
null,null,null,null);
// Check to see of card exists (always should)
if (!basecsr.moveToFirst()) {
cnvcsr.addRow(new Object[]{0L,0L,"NOTACARD","NOTACARD","","","","",""});
return cnvcsr;
}
// If Card is for NOUSER then no decryption requires so return
// base cursor after repositioning to before first.
if (MainActivity.getLoginMode() == LoginActivity.LOGINMODE_NONE) {
basecsr.moveToPosition(-1);
return basecsr;
}
// Get data to decrypt
String extracted_cardnameoncard = basecsr.getString(basecsr.getColumnIndex(
DBCardsTableConstants.CARDNAMEONCARD.getDBColumnName()
));
String extracted_cardnumber = basecsr.getString(basecsr.getColumnIndex(
DBCardsTableConstants.CARDNUMBER.getDBColumnName()
));
String extracted_cardcvv = basecsr.getString(basecsr.getColumnIndex(
DBCardsTableConstants.CARDCVVCODE.getDBColumnName()
));
String extracted_cardpin = basecsr.getString(basecsr.getColumnIndex(
DBCardsTableConstants.CARDPIN.getDBColumnName()
));
String extracted_cardexpiry = basecsr.getString(basecsr.getColumnIndex(
DBCardsTableConstants.CARDEXPIRYDATE.getDBColumnName()
));
// Decrypt data
String decrypted_nameoncard = ed.decrypt(extracted_cardnameoncard);
String decrypted_cardnumber = ed.decrypt(extracted_cardnumber);
String deccrypted_cardcvv = ed.decrypt(extracted_cardcvv);
String decrypted_expiry = ed.decrypt(extracted_cardexpiry);
String decrypted_cardpin = ed.decrypt(extracted_cardpin);
// Store decrypted data
cnvcsr.addRow(new Object[]{
basecsr.getLong(
basecsr.getColumnIndex(
DBCardsTableConstants.CARDID.getDBColumnName()
)),
basecsr.getLong(
basecsr.getColumnIndex(
DBCardsTableConstants.CARDTYPEREF.getDBColumnName()
)
),
basecsr.getLong(
basecsr.getColumnIndex(
DBCardsTableConstants.CARDOWNER.getDBColumnName()
)
),
basecsr.getString(
basecsr.getColumnIndex(
DBCardsTableConstants.CARDNAME.getDBColumnName()
)
),
decrypted_nameoncard,
decrypted_cardnumber,
deccrypted_cardcvv,
decrypted_cardpin,
decrypted_expiry,
basecsr.getString(
basecsr.getColumnIndex(
DBCardsTableConstants.CARDNOTES.getDBColumnName()
)
),
basecsr.getInt(
basecsr.getColumnIndex(
DBCardsTableConstants.CARDCOLOUR.getDBColumnName()
)
)
});
basecsr.close();
return cnvcsr;
}
Notatka! NOUSER to sytuacja, w której pojedynczy użytkownik aplikacji decyduje się nie używać hasła/loginu.