SQLCipher核心思想

2023-11-18

加密原理

+--------------------------------------+----------------+--------------------+
|            page data                 |     iv         |     hmac           |
+--------------------------------------+----------------+--------------------+

iv是一段随机数,可以保证每一页的iv值都不一样。和page data一起作用,用于生成hmac值。
sizeof(page data) = page sz - reserved sz
hmac是一段校验和,可以用来检查page data是否损坏。
sizeof(iv + hmac) = reserved sz

加密实现是通过派生后的key+盐值,对原始page加密,生成加密数据。然后通过iv,对加密数据生成校验和hmac值。

Set key / Attach

SQLCipher的实现方式是在读、写page的时候实现的加、解密。通过pragma key和attach流程中可以分别设置key,在这一过程中只是注册了加解密的实现算法、保存了key。在后面的第一次操作中才开始派生key。

pragma key的入口函数是sqlite3Pragma->sqlite3_key_v2,attach的入口函数是attachFunc。

在这两个函数内,实际上都是执行sqlite3CodecAttach操作

int sqlite3CodecAttach(
    sqlite3* db,
    int nDb,            // 数据库数组db->aDb的索引,前两个分别是main和temp,后面的是attach的
    const void *zKey,   // 密文或者密钥的地址
    int nKey            // 密钥的长度,如果是密文,这里是-1
);

在这个函数里。主要执行了以下动作:

  • sqlcipher_activate
    注册了全局的sqlcipher_provider *default_provider。这个里面主要存了一些加解密算法的实现函数的指针。可以通过宏选择加解密算法,这些算法都是利用第三方的开源加密库。比如SQLCIPHER_CRYPTO_CC,可以选择common crypto算法,实现放在crypto_cc.c里。

  • sqlcipher_codec_ctx_init
    这个函数主要填充了codec_ctx对象,这个对象对应于一个数据库。这里面的一些关于加密的参数都先设置成了默认值,密文(或密钥)填充进两个cipher_ctx——read_ctx和write_ctx里。

    typedef struct {
      int derive_key;               // 是否需要派生key。设置原始key后置位,派生key后取消置位
      int pass_sz;                  // 原始key的size。因为有可能是blob,所以需要size
      unsigned char *key;           // 派生后的key。可能是用户设置的HEX key转换成二进制得到,或者由用户设置的密文和盐值经过kdf_iter次派生得到
      unsigned char *hmac_key;      // 由key和hmac_kdf_salt经过fast_kdf_iter次派生得到
      unsigned char *pass;          // 配置的原始key,可能是密文、x'HEX key'、x'HEX key + HEX kdf_salt'
      char *keyspec;                // x'HEX key + HEX kdf_salt'
    } cipher_ctx;
    
    typedef struct {
      int store_pass;               // 是否要保存原始key。如果设成false,应该在派生key后清空原始key
      int kdf_iter;                 // key的派生次数
      int fast_kdf_iter;            // hmac_key的派生次数
      int kdf_salt_sz;
      int key_sz;
      int iv_sz;
      int block_sz;
      int page_sz;
      int keyspec_sz;
      int reserve_sz;
      int hmac_sz;
      int plaintext_header_sz;
      int hmac_algorithm;
      int kdf_algorithm;
      unsigned int skip_read_hmac;
      unsigned int need_kdf_salt;   // 是否需要取kdf_salt。默认置位,取到kdf_salt后取消置位
      unsigned int flags;           // 默认值DEFAULT_CIPHER_FLAGS,标志是否要hmac校验、大小端
      unsigned char *kdf_salt;      // 生成key的盐值。优先使用用户配置的,其次从文件头取,取不到用随机数
      unsigned char *hmac_kdf_salt; // kdf_salt的每字节 XOR hmac_salt_mask
      unsigned char *buffer;        // 预申请的一段内存,用于加、解密的缓存区,大小为page_sz
      Btree *pBt;
      cipher_ctx *read_ctx;         // 读page用的密钥配置
      cipher_ctx *write_ctx;        // 写page用的密钥配置
      sqlcipher_provider *provider; // 默认的provider,算法可以通过宏配置
      void *provider_ctx;
    } codec_ctx;
    
  • sqlite3PagerSetCodec
    这个函数把加解密的函数注册进了pager里面。这些函数后面在读写page的时候会用到。

    db->aDb[nDb]->pBt->pBt->pPager->xCodec;     // sqlite3Codec
    db->aDb[nDb]->pBt->pBt->pPager->xCodecFree; // sqlite3FreeCodecArg
    db->aDb[nDb]->pBt->pBt->pPager->pCodec;     // codec_ctx
    

    最重要的是sqlite3Codec这个函数,这个函数实现了key的派生,对页面的加密、解密。代码中没有直接调用过这个函数,而是把这个函数注册进pager,又把pager->xCodec封装成两个宏。CODEC1用于解密,CODEC2用于加密。

    # define CODEC1(P,D,N,X,E) \
        if( P->xCodec && P->xCodec(P->pCodec,D,N,X)==0 ){ E; }
    # define CODEC2(P,D,N,X,E,O) \
        if( P->xCodec==0 ){ O=(char*)D; }else \
        if( (O=(char*)(P->xCodec(P->pCodec,D,N,X)))==0 ){ E; }
    

    P代表pager,D代表输入数据pData(如果是解密操作,也是输出数据),N代表pageno,X代表操作码CODEC_READ_OP或CODEC_WRITE_OP或CODEC_JOURNAL_OP,E代表执行出错时的动作,O代表加密后的输出数据。

    sqlite3Codec执行以下动作:

    • sqlcipher_codec_key_derive
      派生key。检查derive_key标志位,如果置位,执行sqlcipher_cipher_ctx_key_derive,派生key,然后清除derive_key标志位。先read_ctx后write_ctx,如果两个ctx里的原始key一样,派生一个就行,另一个copy过去。然后检查store_pass标志位,如果未置位,需要清空两个原始key。
    • 根据不同的操作码分别做处理。如果是CODEC_READ_OP,利用read_ctx执行解密操作,page数据pData解密后,缓存到buffer里,然后再copy buffer数据到pData中,返回pData;如果是CODEC_WRITE_OP,利用write_ctx执行加密操作,pData数据加密后,缓存到buffer里,返回buffer;如果是CODEC_JOURNAL_OP,也是执行加密操作,不过是利用read_ctx使用原始key加密日志数据,这是为了防止rekey事务失败,需要rollback的场景,此时需要从journal文件中读取数据。具体加解密、hmac校验的动作在sqlcipher_page_cipher里实现。

Rekey

Rekey是对一个加密数据库更改密钥的操作。

在set key的流程中,有一个生成reat_ctx和write_ctx的过程sqlcipher_codec_ctx_init。这两个对象绝大多数情况都是相同的,只有在rekey过程中不同。

在rekey过程中,正是利用了这两个对象实现了更改密文的操作。可以分为三步:

  1. 设置新key到write_ctx;
  2. 逐页读出后重新写入。读的过程中使用read_ctx解密,写的过程中使用write_ctx加密;
  3. 复制write_ctx到read_ctx中。

这三步完成后,rekey操作成功。老的数据都已经转换成新key加密的了,再写入新数据也是用新key加密的。

Export

Export可以实现将一个加密数据库导出到一个明文数据库、将一个明文数据库导出到一个加密数据库,将一个加密数据库导出到一个不同key的加密数据库中。export过程的内部实现方法是sqlcipher_exportFunc。该函数内实际上是利用原生的sqlite语句实现了导出。

下面的语句执行后可以得到 CREATE table/index 或者 INSERT INTO SELECT 语句,然后再执行查询出的语句即可实现复制。

-- CREATE table/index/unique index ...
SELECT sql FROM source.sqlite_schema WHERE type='table' AND name!='sqlite_sequence' AND rootpage>0;
SELECT sql FROM source.sqlite_schema WHERE sql LIKE 'CREATE INDEX %%';
SELECT sql FROM source.sqlite_schema WHERE sql LIKE 'CREATE UNIQUE INDEX %%';

-- INSERT INTO target.xxx SELECT * FROM main.xxx
SELECT 'INSERT INTO target.' || quote(name) || '
          SELECT * FROM source.' || quote(name) || ';'
FROM source.sqlite_schema
WHERE type = 'table' AND name!='sqlite_sequence' AND rootpage>0;

-- INSERT INTO target.sqlite_sequence SELECT * FROM main.sqlite_sequence
SELECT 'INSERT INTO target.' || quote(name) || '
          SELECT * FROM source.' || quote(name) || ';'
FROM target.sqlite_schema
WHERE name=='sqlite_sequence';

下面的语句可以直接执行。

INSERT INTO target.sqlite_schema
  SELECT type, name, tbl_name, rootpage, sql
  FROM source.sqlite_schema
  WHERE type='view' OR type='trigger' OR (type='table' AND rootpage=0)";

这两部分sql执行完,实际上是实现了export的功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SQLCipher核心思想 的相关文章

  • 跨境电商三大趋势已经涌现

    在过去的几年里 跨境电商在推动外贸增长中发挥了至关重要的作用 成为了引领行业发展的强大引擎 然而 随着2024年的到来 跨境电商行业又站在了崭新的起点 准备攀登新的发展高峰 数据显示 得益于经济的逐步复苏 未来三年跨境电商行业预计将以16
  • Redis Geo:掌握地理空间数据的艺术

    欢迎来到我的博客 代码的世界里 每一行都是一个故事 Redis Geo 掌握地理空间数据的艺术 前言 Redis Geo基本概念 Geo模块的目的 工作原理 地理坐标系统
  • 拓数派加入 OpenCloudOS 操作系统开源社区,作为成员单位参与社区共建

    近日 拓数派签署 CLA Contributor License Agreement 贡献者许可协议 正式加入 OpenCloudOS 操作系统开源社区 拓数派 英文名称 OpenPie 是国内基础数据计算领域的高科技创新企业 作为国内云上
  • MySQL中设置自增主键id从1开始

    可能遇到过这种问题 当你只想新增一条数据时 发现使用Insert语句后 发现id并不是从1开始的 握草 怎么回事 其实很简单 通过执行一下SQL 对应你的表就可以解决 ALTER TABLE user AUTO INCREMENT 1 具体
  • 【计算机开题报告】二手车交易平台

    一 选题依据 简述国内外研究现状 生产需求状况 说明选题目的 意义 列出主要参考文献 选题目的 意义 如今时代网络技术正在快速发展 电子商务技术也以极为强势的姿态闯入人们的视野之中 随着人们生活质量的提升 为了对身边二手物品进行回收利用 二
  • 【计算机开题报告】 医药信息管理系统

    一 选题依据 简述国内外研究现状 生产需求状况 说明选题目的 意义 列出主要参考文献 1 研究背景 随着医药事业的不断壮大 相关单位对于医药信息的管理变得越来越重要 传统的手工管理效率低 易出错 费时费力 不能及时精确的收集 传递 存储 加
  • 如何在CentOS安装SQL Server数据库并通过内网穿透工具实现公网访问

    文章目录 前言 1 安装sql server 2 局域网测试连接 3 安装cpolar内网穿透 4 将sqlserver映射到公网 5 公网远程连接 6 固定连接公网地址 7 使用固定公网地址连接 前言 简单几步实现在Linux cento
  • 实时获取建材网商品数据:API实现详解与代码示例

    一 引言 随着电子商务的快速发展 实时获取商品数据对于企业决策 市场分析以及数据驱动的营销策略至关重要 建材网作为国内知名的建材信息平台 提供了API接口 使得第三方开发者可以方便地获取商品数据 本文将详细介绍如何使用 建材网的API接口
  • 进程间通信

    进程间通信 进程间通信介绍 进程间通信目的 数据传输 一个进程需要将它的数据发送给另一个进程 资源共享 多个进程之间共享同样的资源 通知事件 一个进程需要向另一个或一组进程发送消息 通知它 它们 发生了某种事件 如进程终止 时要通知父进程
  • 软件开发和网络安全哪个更好找工作?

    为什么今年应届毕业生找工作这么难 有时间去看看张雪峰今年为什么这么火就明白了 这么多年人才供给和需求错配的问题 在经济下行的今年 集中爆发 供给端 大学生越来越多 需求端 低端工作大家不愿去 高端岗位又太少 很多基础行业 比如机械 土木 所
  • 拼多多详情API开启运营比价新纪元

    随着互联网的快速发展 电商行业正在迅速崛起 拼多多作为一家新兴的电商平台 凭借其独特的营销策略和创新的商业模式 成为了电商行业的一匹黑马 在拼多多的成功背后 其详情API接口营销起到了至关重要的作用 本文将详细介绍拼多多详情API接口营销的
  • Navicat 16 for MySQL:打造高效数据库开发管理工具

    随着数据的快速增长和复杂性的提升 数据库成为了现代应用开发中不可或缺的一部分 而在MySQL数据库领域 Navicat 16 for MySQL作为一款强大的数据库开发管理工具 正受到越来越多开发者的青睐 Navicat 16 for My
  • 【计算机毕业设计】校园体育赛事管理系统

    身处网络时代 随着网络系统体系发展的不断成熟和完善 人们的生活也随之发生了很大的变化 人们在追求较高物质生活的同时 也在想着如何使自身的精神内涵得到提升 而读书就是人们获得精神享受非常重要的途径 为了满足人们随时随地只要有网络就可以看书的要
  • 【计算机毕业设计】学生就业管理系统

    如今社会上各行各业 都喜欢用自己行业的专属软件工作 互联网发展到这个时候 人们已经发现离不开了互联网 新技术的产生 往往能解决一些老技术的弊端问题 因为传统学生就业信息管理难度大 容错率低 管理人员处理数据费工费时 所以专门为解决这个难题开
  • 【计算机毕业设计】北关村基本办公管理系统

    在如今社会上 关于信息上面的处理 没有任何一个企业或者个人会忽视 如何让信息急速传递 并且归档储存查询 采用之前的纸张记录模式已经不符合当前使用要求了 所以 对北关村基本办公信息管理的提升 也为了对北关村基本办公信息进行更好的维护 北关村基
  • python超详细基础文件操作【建议收藏】

    文章目录 前言 发现宝藏 1 文件操作 1 1 文件打开与关闭 1 1 1 打开文件 1 1 2 关闭文件 1 2 访问模式及说明 2 文件读写 2 1 写数据 write 2 2 读数据 read 2 3 读数据 readlines 2
  • 基于java的学生宿舍管理系统设计与实现

    基于java的学生宿舍管理系统设计与实现 I 引言 A 研究背景和动机 基于Java的学生宿舍管理系统设计与实现的研究背景和动机 在数字化时代的推动下 学生宿舍管理系统已经成为了管理学生宿舍的重要工具 学生宿舍管理系统能够帮助管理者更好地管
  • 基于java的饮食分享平台系统设计与实现

    基于java的饮食分享平台系统设计与实现 I 引言 A 研究背景和动机 近年来 随着人们生活水平的提高和健康意识的增强 饮食健康已经成为越来越多人的关注焦点 因此 一个方便快捷的饮食分享平台就显得尤为重要 基于Java的饮食分享平台系统设计
  • 电商数据api拼多多接口获取商品实时数据价格比价api代码演示案例

    拼多多商品详情接口 接口接入入口 它的主要功能是允许卖家从自己的系统中快速获取商品详细信息 通过这个接口 卖家可以提取到商品的各类数据 包括但不限于商品标题 价格 优惠价 收藏数 下单人数 月销售量等 此外 还可以获取到商品的SKU图 详情
  • 深入了解 Python MongoDB 查询:find 和 find_one 方法完全解析

    在 MongoDB 中 我们使用 find 和 find one 方法来在集合中查找数据 就像在MySQL数据库中使用 SELECT 语句来在表中查找数据一样 查找单个文档 要从MongoDB的集合中选择数据 我们可以使用 find one

随机推荐

  • 【算法日志】哈希表应用:set和map容器,哈希表的使用(day5)

    代码随想录60day 链表 day4 链表 day3 目录 前言 一 三种哈希结构 数组 散列技术 哈希思想 哈希碰撞 set 集合 map 映射 二 哈希表的一些应用 总结 前言 哈希表 也叫散列表 是一种较为常用的数据结构 我们常用的数
  • 1486. XOR Operation in an Array

    class Solution public int xorOperation int n int start int nret start for int m 1 m lt n m nret nret start 2 m return nr
  • 编译原理(4)LR(0)语法分析程序设计(Python实现)

    1 实验要求 1 已知文法G S 0 S E 1 E aA 2 E bB 3 A cA 4 A d 5 B cB 6 B d 手工建立文法G S 的LR 0 的项目集规范族DFA和LR 0 分析表 2 根据清华大学版 编译原理 第3版 教材
  • Jfugue编程概要

    转自 http www sudu cn info html edu java 20060912 304274 html JFugue是个用于音乐作曲的Java API 和其他的音乐API不同 他能够让你用数据字符串来指定音符 乐器 和弦 及
  • java sql 查询中的转义序列不对_在 JDBC 中使用 SQL 转义序列 - SQL Server

    使用 SQL 转义序列Using SQL escape sequences 08 12 2019 本文内容 按照 JDBC API 的定义 Microsoft JDBC Driver for SQL ServerMicrosoft JDBC
  • 20天零基础自学Python

    大家好 我是宁一 Python 数字数据类型是用来存储数值的 是我们从小学就开始接触的老朋友了 也是python中最基础的数据类型 1 Number 数据类型 python3的 Number 数据类型包括 int 整数 float 浮点数
  • B站化播放量为播放时长,是谁的狂欢?

    6月26日晚 B站举办了14周年庆典晚会 在晚会上 除了周深 美依礼芽同框献唱受到关注 B站董事长兼CEO陈睿的演讲内容同样值得深思 一来 陈睿提到 要将目前B站视频前台显示的播放量数据从次数改为分钟数 计划未来几周 将完成产品更新 二来
  • 堆栈内存和闭包

    思维导图 堆栈内存小科普 1 js中的内存分为 堆内存和栈内存 堆内存 只要用来存储引用数据类型的值 对象存的是键值对 函数存的是字符串 栈内存 供js运行的环境 函数执行 存基本数据类型的值 堆栈内存的释放问题 我们每次给变量存值或者执行
  • 程序员秋招最全Java面试题及答案整理(2023最新版)

    前言 大家好 最近一个月 花了不少时间 给大家整理了一套 2023 的技术面试资料 包括各大厂最新面试题以及面经解析涉及JVM Mysql 并发 Spring Mybatis Redis RocketMQ Kafka Zookeeper N
  • 【C刷题】day1

    一 选择题 1 正确的输出结果是 int x 5 y 7 void swap int z z x x y y z int main int x 3 y 8 swap printf d d n x y return 0 答案 3 8 解析 考
  • 怎样将excel文件导入mysql中

    1 整理好excel表中的字段 2 在Navicat中创建表 如果导入的是一个追加的表 则无需创建新表 CREATE TABLE orderinfo orderid VARCHAR 10 NULL 订单 id 主键 userid INT 1
  • 华为OD机试2023年最新题库(JAVA、Python、C++)

    我是一名软件开发培训机构老师 我的学生已经有上百人通过了华为OD机试 学生们每次考完试 会把题目拿出来一起交流分享 重要 5 11月份考的都是OD统一考试 B卷 2023年5月份题库已经更新为OD统一考试 B卷 题库由三部分组成 1 202
  • 【H5】 svg内text、image、path标签的使用

    H5 svg内text image path标签的使用 text标签 div style width 500px height 500px border 2px solid pink margin 50px auto 0 div
  • XML中约束文档的引用和书写

    在XML中定义了一套规则 来对文档内容进行约束 这叫做XML约束 常用的俩种约束语言 DTD约束 Schema约束 XML文档中可以引入多个约束文档 为了防止出现不同含义的同名名称冲突 所以 所以可以XML提供了名称空间 1 DTD语法 D
  • 【HTML】列表标签、表格标签、块级标签、表单标签

    文章目录 一 列表标签 1 无序列表 2 无序列表 3 定义列表 项目列表 二 表格标签 1 表格整体架构 2 表格的标签介绍 3 table标签的属性 4 tr标签的属性 5 th td标签的属性 6 跨行 跨列的表格 三 块级标签 1
  • vue猜数字游戏

    div p msg p div
  • node.js JSON对象和string的相互转化

    JSON stringify obj 将JSON转为字符串 var json aa sdddssd bb 892394829342394792399 23894723984729374932874 cc 11111111111111 gt
  • html5期末知识点归纳总结,web期末考试知识点

    题型及知识点 一 知识点 上课内容全覆盖 除补充的html5和css3的内容 常用的html标记及属性 弄清楚哪些是块元素 哪些是行内元素 特殊字符标记 p40 Css属性 i 字体 font size font family font w
  • 蓝桥杯JAVA B组 2020(1)第五题 排序

    一 题目描述 小蓝最近学习了一些排序算法 其中冒泡排序让他印象深刻 在冒泡排序中 每次只能交换相邻的两个元素 小蓝发现 如果对一个字符串中的字符排序 只允许交换相邻的两个字符 则在所有可能的排序方案中 冒泡排序的总交换次数是最少的 例如 对
  • SQLCipher核心思想

    加密原理 page data iv hmac iv是一段随机数 可以保证每一页的iv值都不一样 和page data一起作用 用于生成hmac值 sizeof page data p