【问题标题】:Encrypt data in SQLite在 SQLite 中加密数据
【发布时间】:2018-05-10 13:04:12
【问题描述】:

如何加密我的数据?

就我研究的解决方案而言,有两种方法:

  1. 使用 android 提供的算法加密数据。我使用 android 提供的“密码”来加密我的数据。但我在检索包含大量记录的数据时遇到问题,导致应用的性能显着降低。
  2. 我对整个数据库进行了编码,然后我对每个会话进行了解码并保存在缓存中,但没有找到解决此问题的算法。

【问题讨论】:

    标签: android sqlite encryption android-sqlite


    【解决方案1】:

    我在列级别使用以下加密/解密,即它仅应用于敏感数据。

    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);
        }
    }
    

    示例用法(加密):-

        ........
        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();
    

    示例用法(解密)

    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;
    }
    

    注意! NOUSER 是指应用程序的单个用户决定不使用密码/登录。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-22
      • 2014-08-25
      相关资源
      最近更新 更多