本文介绍了如何在没有第3方库的情况下加密sqlite文本(Android)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在android应用程序中使用外部数据库,并且在编译后直接将其嵌入apk包中.我想在应用购买中实施以访问其某些数据,所以我不想不进行任何加密就保留它.我使用了Sqlcipher库,但它使应用程序变得又大又慢.没有其他方法可以做到这一点吗?例如,有一种算法可以对字符串进行加密,以便我将加密后的文本放入数据库中,然后在应用程序代码中对其进行解密?

解决方案

以下是一个示例应用程序,该应用程序对部分数据进行加密,然后可以将其打开.它基于我评论中的代码.

阶段1-主数据库.

首先,您需要将数据库作为加密数据库的基础(即应用程序中未包含的 MASTER 数据库,它的用途是创建加密数据库(或数据库,也许是一个库,如果需要更高的安全性,则每个数据库都具有唯一的密码/秘密密钥))在某种程度上考虑了这一点(在整个示例中都如此):

如您所见,通过拥有一个名为FreeData的表和另一个名为PaidData的表,此功能将起作用.这些表的定义与PaidData没有ID列的定义相同(此方法的目的是当/如果请求的密钥和SecretKey(密码)有效,则将PaidData中的行解密为FreeData)./p>

所以 FreeData 表看起来像:-

PaidData 表如下:-

  • 因此,表之间的唯一区别是其中包含的实际数据,并且缺少 id 列.
  • PaidData 表中提取加密数据,解密并将其插入 FreeData 表中时,将生成ID.因此,只需进行一次解密即可访问数据.

第2阶段-生成加密数据库以通过App分发

为此,应用程序仅使用EncryptDecrypt类与

PaidData表:-

启动该应用程序后,如果从资产文件夹中复制数据库( 硬编码为basedb.db ),该数据库便存在并显示加密"按钮.

  • 如果看不到加密"按钮,则找不到资产文件.因此,是时候解决问题了(提供正确的数据库文件).
    • 请注意,由于这只是一个演示,为简便起见,跳过了许多可能/应该完成或应添加的检查/选项.

如果出现加密"按钮,则只需按一下按钮即可加密.

点击按钮后,将调用 createEncryptedDatabase 方法.

这将创建从资产文件夹复制的数据库的副本(将是加密数据库),方法是将该文件复制到新名称(根据给定的数据库名称,该名称必须与资产的文件名不同)./p>

使用复制的数据库查询 mTCCL 中定义的表( TableColumnConvertList 类的实例).

查询将仅提取已指定为要加密的列的数据.该查询仅获得不同的行(即,如果存在多行,且各列中的数据相同,则仅提取其中一行).

对于每个提取的行:-

  • 已清除常用的ContentValues实例.
  • 已清除whereClause StringBuilder.
  • 检查游标中的每个列,以查看它是否为正在处理的表中定义的列(应该是因为仅提取了要加密的列t).
    • 如果没有,则将其跳过.
  • 原始值保存在字符串数组 columnOriginalValues 的适当元素中(用作UPDATE的WHERE子句的绑定参数)
  • ContentValues实例的元素添加了当前列名和加密的数据.
    • 这是根据 cv.put(s,ed.encrypt(c.getString(c.getColumnIndex(s))));
    • 完成的
  • 如果whereClause的长度大于0,则将AND加到whereClause中,然后后缀==的列名.被添加到正在构建的whereClause中.处理完所有列之后,将调用SQLiteDatabase update 方法来更新将值设置为加密值的列,而所有列均与原始数据匹配.
  • 处理完所有行后,关闭游标并处理下一个表.
  • 如果在处理完所有表之后错误计数为0,则将事务设置为成功,否则将消息已烘烤".加密数据库时遇到错误.回滚(未更改).
  • 然后交易结束(如果未设置为成功,则不更新数据但回滚数据).

数据库将位于data/data/package_name/databases文件夹中,例如:-

I'm using an external database inside my android application and it directly embeds inside the apk package after compiling.As I want to implement in app purchase in order to access some of its data I don't want to leave it without any encryption.I used Sqlcipher library but it makes the app too big and slow.Isn't there any other way to do this? For example an algorithm to encrypt the strings so I put the encrypted text in database and decrypt it inside application code?

解决方案

The following is an example App that Encrypts part of the data that can then be turned on. It is based upon the code in my comment.

Stage 1 - The Master Database.

To start with you need the database that is to be the basis of the encrypted database (i.e. the MASTER database that IS NOT include in the App, it's use is to create the Encrypted database (or databases, perhaps a library, each database with a unique password/secret key if you wanted greater security)) in part consider this (as is used throughout the example) :-

As you can see this one will work by having a table called FreeData and another called PaidData. The tables definitions are the same EXCEPT that for the PaidData there is no ID column (the intention of this method is to decrypt the rows in the PaidData into the FreeData when/if the requested and the SecretKey (password) is valid.).

So The FreeData table looks like :-

The PaidData table looks like :-

  • So the only difference between the tables is the actual data contained within and that the id column is missing.
  • The id's will be generated when the encrypted data is extracted from the PaidData table, decrypted and the inserted into the FreeData table. Thus just one decryption is required to get access to the data.

Stage 2 - Generating the Encrypted Database for distribution with the App

This is done by a App just for this purpose using the EncryptDecrypt class very similar to the one at Encrypt data in SQLite

as per EncryptDecrypt.java

class EncryptDecrypt {
    private Cipher cipher;
    private static SecretKeySpec secretKeySpec;
    private static IvParameterSpec ivParameterSpec;
    private boolean do_encrypt = true;

    /**
     * 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
     */
    EncryptDecrypt(Context context, String skey) {
        //DBUsersMethods users = new DBUsersMethods(context);
        String saltasString = "there is no dark side of the moon it is all dark.";
        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);
    }
}

  • As this was designed for user login and multiple users where a salt was part of the database the salt has been hard coded using :- String saltasString = "there is no dark side of the moon it is all dark.";, The phrase can be changed as long as it is at least 16 characters in length (only the first 16 bytes are used).

A class is used to cater for potential flexibility/expansion where multiple tables can be specified or not for encryption and for multiple columns that can be encrypted, copied asis or skipped (e.g. id's would probably be skipped (in the example it's not even defined as a column).).

This class is TableColumnConvertList.java and is :-

public class TableColumnConvertList {
    private ArrayList<TableEntry> tables;

    public TableColumnConvertList() {
        this.tables = new ArrayList<>();
    }

    public String[] getTables() {
        String[] tableList = new String[tables.size()];
        int ix = 0;
        for (TableEntry te: this.tables) {
                tableList[ix++] = te.getSourceTableName();
        }
        return tableList;
    }

    public String[] getTableColumnNamesToEncrypt(String tableName) {
        String[] rv = null;
        for(TableEntry te: this.tables) {
            if (te.getSourceTableName().equals(tableName)) {
                rv = new String[te.getColumnNamesToEncrypt().size()];
                int ix=0;
                for (String s: te.getColumnNamesToEncrypt()) {
                    rv[ix++] = s;
                }
            }
        }
        return rv;
    }

    public String[] getTableColumnNamesToCopyAsis(String tableName) {
        String[] rv = null;
        for (TableEntry te: this.tables) {
            if (te.getSourceTableName().equals(tableName)) {
                rv = new String[te.getColumnNamesToCopyAsis().size()];
                int ix=0;
                for (String s: te.getColumnNamesToCopyAsis()) {
                    rv[ix++] = s;
                }
            }
        }
        return rv;
    }

    public String[] getTableColumnNamesToSkip(String tableName) {
        String[] rv = null;
        for (TableEntry te: this.tables) {
            if (te.sourceTableName.equals(tableName)) {
                rv = new String[te.getColumnNamesToSkip().size()];
                int ix =0;
                for (String s: te.getColumnNamesToSkip()) {
                    rv[ix++] = s;
                }
            }
        }
        return rv;
    }


    public void addTable(
            String sourceTableName,
            String destinationTableName,
            String[] columnNamesToEncrypt,
            String[] columnNamesToCopyAsis,
            String[] columnNamesToSkip
    ) {
        tables.add(
                new TableEntry(
                        sourceTableName,
                        destinationTableName,
                        columnNamesToEncrypt,
                        columnNamesToCopyAsis,
                        columnNamesToSkip
                )
        );
    }

    private class TableEntry {
       private String sourceTableName;
       private String destinationTableName;
       private ArrayList<String> columnNamesToEncrypt;
       private ArrayList<String> columnNamesToCopyAsis;
       private ArrayList<String> columnNamesToSkip;

       private TableEntry() {}

       private TableEntry(String sourceTableName,
                          String destinationTableName,
                          String[] columnNamesToEncrypt,
                          String[] columnNamesToCopyAsis,
                          String[] columnNamesToSkip
       ) {
           this.sourceTableName = sourceTableName;
           this.destinationTableName = destinationTableName;
           this.columnNamesToEncrypt = new ArrayList<>();
           if (columnNamesToEncrypt != null && columnNamesToEncrypt.length > 0) {
               for (String s: columnNamesToEncrypt) {
                   addColumn(s);
               }
           }
       }

       private void addColumn(String s) {
           this.columnNamesToEncrypt.add(s);
       }

        private String getSourceTableName() {
            return sourceTableName;
        }

        public String getDestinationTableName() {
            return destinationTableName;
        }

        public void setSourceTableName(String sourceTableName) {
            this.sourceTableName = sourceTableName;
        }

        public void setDestinationTableName(String destinationTableName) {
            this.destinationTableName = destinationTableName;
        }

        private ArrayList<String> getColumnNamesToEncrypt() {
            return columnNamesToEncrypt;
        }

        public void setColumnNamesToEncrypt(ArrayList<String> columnNamesToEncrypt) {
            this.columnNamesToEncrypt = columnNamesToEncrypt;
        }

        private ArrayList<String> getColumnNamesToCopyAsis() {
            return columnNamesToCopyAsis;
        }

        public void setColumnNamesToCopyAsis(ArrayList<String> columnNamesToCopyAsis) {
            this.columnNamesToCopyAsis = columnNamesToCopyAsis;
        }

        public ArrayList<String> getColumnNamesToSkip() {
            return columnNamesToSkip;
        }

        public void setColumnNamesToSkip(ArrayList<String> columnNamesToSkip) {
            this.columnNamesToSkip = columnNamesToSkip;
        }
    }
}

The rest of this basic App, at present, is all in a single activity that uses two input's (EditTexts) :-

  • The secret key used to encrypt
  • The database name (file name) of the encrypted database.
    • Code in the App prevents using the same name as the base database, which needs to be copied into the assets folder.and a Button, to initiate the Encryption if the input is good (to a fashion aka with limited validation).

This the layout xml activiy_main.xml is :-

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Database EncryptTool" />

    <EditText
        android:id="@+id/secretkey"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="Secret Key to use to Encrypt the Database."
        >
    </EditText>
    <EditText
        android:id="@+id/databasename"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="MyDatabase"
        android:hint="Database Name"
        >
    </EditText>

    <Button
        android:id="@+id/encrypt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="ENCRYPT"
        android:visibility="gone"
        >
    </Button>
</LinearLayout>

MainActivity.java where the work is done is :-

public class MainActivity extends AppCompatActivity {

    public static final String ASSETDB_NAME = "basedb.db";
    public static final int ASSETDB_NOT_FOUND = -10;
    public static final int ASSETFILE_OPEN_ERROR = -11;
    public static final int ASSETDB_OPEN_ERROR = -12;
    public static final int ASSETDB_COPY_ERROR = -13;
    public static final int ASSETDB_FLUSH_ERROR = -14;
    public static final int ASSETDB_CLOSE_ERROR = -15;
    public static final int ASSETFILE_CLOSE_ERROR = -16;
    public static final int ASSETDB_CREATED_SUCCESSFULLY = 0;
    public static final int BUFFERSIZE = 1024 * 4;

    EditText mSecretKey, mDBName;
    Button mEncryptButton;
    TableColumnConvertList mTCCL = new TableColumnConvertList();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mDBName = this.findViewById(R.id.databasename);
        mSecretKey = this.findViewById(R.id.secretkey);
        mEncryptButton = this.findViewById(R.id.encrypt);

        //<<<<<<<<< set what data to encrypt i.e. table(s) and the column(s) in the table >>>>>>>>>
        mTCCL.addTable(
                "PaidData",
                "FreeData",
                new String[]{"theData"},
                new String[]{},
                new String[]{"id"}
                );

        if (getDBFromAsset() >= 0) {
            mEncryptButton.setVisibility(View.VISIBLE);
            mEncryptButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (mDBName.getText().toString().length() < 1) {
                        Toast.makeText(
                                v.getContext(),
                                "The Database Name cannot be blank.",
                                Toast.LENGTH_LONG
                        ).show();
                        mDBName.requestFocus();
                        return;
                    }
                    if (mDBName.getText().toString().equals(ASSETDB_NAME)) {
                        Toast.makeText(
                                v.getContext(),
                                "Database Name cannot be "
                                        + ASSETDB_NAME
                                        + ". Please change the name.",
                                Toast.LENGTH_LONG
                        ).show();
                        mDBName.requestFocus();
                        return;
                    }
                    if (mSecretKey.getText().toString().length() < 1) {
                        Toast.makeText(
                                v.getContext(),
                                "The Secret Key cannot be blank.",
                                Toast.LENGTH_LONG
                        ).show();
                        mSecretKey.requestFocus();
                        return;
                    }
                    if (createEncryptedDatabase(mTCCL,
                            mDBName.getText().toString(),
                            mSecretKey.getText().toString()
                    ) == 0) {
                        Toast.makeText(v.getContext(),"Successfully Encrypted Database " + mDBName + " using Secret Key " + mSecretKey,Toast.LENGTH_LONG).show();
                    }
                }
            });

        }
    }

    private boolean checkIfDataBaseExists(String databaseName) {
        File dbFile = new File(this.getDatabasePath(databaseName).getPath());
        if (dbFile.exists()) {
            return true;
        } else {
            if (!dbFile.getParentFile().exists()) {
                dbFile.getParentFile().mkdirs();
            }
        }
        return false;
    }

    private boolean checkIfAssetDBExists() {
        try {
            InputStream is = this.getAssets().open(ASSETDB_NAME);
            is.close();
            return true;
        } catch (IOException e) {
            return false;
        }
    }

    private int getDBFromAsset() {
        int rv = ASSETDB_NOT_FOUND;
        File dbFile = new File(this.getDatabasePath(ASSETDB_NAME).getPath());
        InputStream is;
        FileOutputStream os;
        int read_length;
        byte[] buffer = new byte[BUFFERSIZE];
        if (!checkIfAssetDBExists()) {
            return ASSETDB_NOT_FOUND;
        }
        if (checkIfDataBaseExists(ASSETDB_NAME)) {
            dbFile.delete();
        }
        try {
            rv = ASSETFILE_OPEN_ERROR;
            is = this.getAssets().open(ASSETDB_NAME);
            rv = ASSETDB_OPEN_ERROR;
            os = new FileOutputStream(dbFile);
            rv = ASSETDB_COPY_ERROR;
            while ((read_length = is.read(buffer)) > 0) {
                os.write(buffer,0,read_length);
            }
            rv = ASSETDB_FLUSH_ERROR;
            os.flush();
            rv = ASSETDB_CLOSE_ERROR;
            os.close();
            rv = ASSETFILE_CLOSE_ERROR;
            is.close();
            rv = ASSETDB_CREATED_SUCCESSFULLY;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return rv;
    }

    private int createEncryptedDatabase(TableColumnConvertList tableColumnConvertList, String databaseName, String key) {
        File copiedAssetDB = new File(this.getDatabasePath(ASSETDB_NAME).getPath());
        File encryptedDB = new File(this.getDatabasePath(databaseName).getPath());
        if (encryptedDB.exists()) {
            encryptedDB.delete();
        }
        try {
            byte[] buffer = new byte[BUFFERSIZE];
            int read_length;
            InputStream is = new FileInputStream(copiedAssetDB);
            OutputStream os = new FileOutputStream(encryptedDB);
            while ((read_length = is.read(buffer)) > 0) {
                os.write(buffer,0,read_length);
            }
            os.flush();
            os.close();
            is.close();
        } catch (IOException e) {
            e.printStackTrace();
            return -1;
        }

        SQLiteDatabase db = SQLiteDatabase.openDatabase(encryptedDB.getPath(),null,SQLiteDatabase.OPEN_READWRITE);
        EncryptDecrypt ed = new EncryptDecrypt(this,key);
        int errorcount = 0;

        db.beginTransaction();
        for (String t: tableColumnConvertList.getTables()) {
            ContentValues cv = new ContentValues();
            String[] columnsToEncrypt = tableColumnConvertList.getTableColumnNamesToEncrypt(t);
            String[] columnOriginalValues = new String[columnsToEncrypt.length];

            Cursor c = db.query(true,t,columnsToEncrypt,null,null,null,null,null, null);
            int totalRows = c.getCount();
            int updatedRows = 0;
            while (c.moveToNext()) {
                cv.clear();
                int ovix=0;
                StringBuilder whereClause = new StringBuilder();
                for (String s: c.getColumnNames()) {
                    for (String ec: columnsToEncrypt ) {
                        if (s.equals(ec)) {
                            cv.put(s,ed.encrypt(c.getString(c.getColumnIndex(s))));
                            columnOriginalValues[ovix++] = c.getString(c.getColumnIndex(s));
                            if (whereClause.length() > 0) {
                                whereClause.append(" AND ");
                            }
                            whereClause.append(s).append("=?");
                        }
                    }
                }
                updatedRows += db.update(t,cv,whereClause.toString(),columnOriginalValues);
            }
            c.close();
            Log.d("ENCRYPTRESULT","Read " + totalRows + " DISTINCT ROWS. Updated " + updatedRows);
            errorcount += totalRows - updatedRows;
        }
        if (errorcount == 0) {
            db.setTransactionSuccessful();
        } else  {
            Toast.makeText(
                    this,
                    "Errors encountered Encrypting Database. Rolled back (not changed)",
                    Toast.LENGTH_LONG
            ).show();
        }
        db.endTransaction();
        return errorcount;
    }
}

Of importance is this line/code :-

TableColumnConvertList mTCCL = new TableColumnConvertList();

..........

    //<<<<<<<<< set what data to encrypt i.e. table(s) and the column(s) in the table >>>>>>>>>
    mTCCL.addTable(
            "PaidData",
            "FreeData",
            new String[]{"theData"},
            new String[]{},
            new String[]{"id"}
            );

This adds a table to the List of tables to be encrypted. It's parameters are :-

  • The name of the table that is to be included in Encryption.
  • the name of the table into which the encrypted data is to be stored.
    • Note this functionality is not present but could be added. As such the value is ignored.
  • The list of columns that are to be encrypted.
  • The list of columns that are to be copied asis.
    • This functionality is not present but could be added. As such the list is ignored.
  • The list of columns that are to be skipped (e.g. id columns).
    • Although coded, the functionality is not present. As such the list is ignored.

What the App does.

The final result is an database as per the database in the assets folder (named basedb.db) that has the data in the theData column of the PaidData table encrypted, but the the FreeData table is unchanged. This database could then be copied (e.g. using device explorer) and then included as an asset in the App that is to be distributed. That App could include a reversal of the Encryption using the secret key and the decryption part of the EncryptDecrypt class.

e.g.

The FreeData table :-

The PaidData table :-

When the App is started if copies the database (hard coded as basedb.db) from the assets folder it it exists and makes the Encrypt button visible.

  • If the Encrypt button isn't visible then the asset file was not located. So it's time to correct the issue (provide the correct database file).
    • Note as this is just a demo many checks/options that could/should be done or added are skipped for brevity.

If the Encrypt button appears then encryption is just a matter of hitting the button.

After hitting the button createEncryptedDatabase method is called.

This creates a copy, this will be the encrypted database, of the database copied from the assets folder by copying the file to it's new name (as per the given database name which MUST be different to the asset's file name).

Using the copied database it queries the table(s) defined in mTCCL (an instance of the TableColumnConvertList class) .

The query will extract data only for the columns that have been specified as those to be encrypted. The query only obtain distinct rows (i.e if multiple rows exist that has the same data in the columns then only one of the rows is extracted).

For each extracted row :-

  • The commonly used ContentValues instance is cleared.
  • The whereClause StringBuilder is cleared.
  • Each column in the Cursor is checked to see if it is a column, defined in the table being processed (it should be as only column t be encrypted are extracted).
    • if not then it is skipped.
  • The original value is saved in the appropriate element of the string array columnOriginalValues (this to be used as the bind parameters for the WHERE clause of the UPDATE)
  • An element of the ContentValues instance is added with the current column name and the encrypted data.
    • This is done as per cv.put(s,ed.encrypt(c.getString(c.getColumnIndex(s))));
  • If the length of the whereClause is greater than 0 then AND is added to the whereClause, then the column name suffixed with =? is added to the whereClause being built.After all columns have been processed the SQLiteDatabase update method is called to update the columns setting the values to the encrypted values WHERE all the column match the original data.
  • After all rows have been processed the Cursor is closed and the next table processed.
  • If after all tables have been processed then error count is 0 then the transaction is set as successful, otherwise a message is Toasted Errors encountered Encrypting Database. Rolled back (not changed).
  • The transaction is then ended (if not set as successful then the data is not updated but rolled back).

The database will be in the data/data/package_name/databases folder e.g. :-

这篇关于如何在没有第3方库的情况下加密sqlite文本(Android)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 15:42