Andy Niu Help
1.0.0.0
|
变量 | |
和lua的交互流程 | |
类的层次化结构 | |
洋葱层调整测试 | |
加解密元数据的读写 | |
加解密元数据的读操作 | |
加解密元数据的写操作 | |
详细描述
变量说明
加解密元数据的写操作 |
1、CreateDelta::apply deltaOutputBeforeQuery insert到 generic_prefix_BleedingMetaObject deltaOutputAfterQuery insert到 generic_prefix_MetaObject 2、这些可以怎么来的,在什么地方插入到数据库? 序列化写入到数据库中 --> " INSERT INTO " + table_name + " (serial_object, serial_key, parent_id, id) VALUES ( --> esc_child_serial = escapeString(e_conn, child_serial); // mysql转义 --> object.serialize(parent) // 序列化,看一下DBMeta,找到各个序列化的实现 --> EncLayer::serialize --> return serial_pack(this->level(), this->name(), this->doSerialize()); --> doSerialize() 查看EncLayer 子类的doSerialize多态做法。 找两个例子 DETJOIN_int --> DET_abstract_integer::doSerialize() --> getCInteger_().serialize(); --> CryptedInteger::serialize() 对以下字段序列化 serializeStrings({key,TypeText<enum enum_field_types>::toText(field_type),std::to_string(inclusiveRange.first),std::to_string(inclusiveRange.second)}); --> DETJOIN_int新增加了字段cinteger,重写getCInteger_()方法,在DETJOIN_int(const Create_field &cf, const std::string &seed_key)创建 注:DETJOIN_int(unsigned int id, const CryptedInteger &cinteger)读取时候用到的 DETJOIN_str --> std::string doSerialize() const {return rawkey;} --> rawkey(prng_expand(seed_key, key_bytes)) --> 都是找到seed_key --> DETJOINFactory::create(const Create_field &cf,const std::string &key) --> EncLayerFactory::encLayer(onion o, SECLEVEL sl, const Create_field &cf,const std::string &key) --> const std::string key = m_key ? getLayerKey(m_key, uniqueFieldName, l) : "plainkey"; --> OnionMeta::OnionMeta(onion o, std::vector<SECLEVEL> levels,const AES_KEY * const m_key,const Create_field &cf, unsigned long uniq_count,SECLEVEL minimum_seclevel) --> static bool init_onions_layout(const AES_KEY *const m_key, FieldMeta *const fm,const Create_field &cf, bool unique) --> FieldMeta::FieldMeta(const Create_field &field,const AES_KEY * const m_key,SECURITY_RATING sec_rating,unsigned long uniq_count,bool unique) --> a.getMasterKey().get() --> createAndRewriteField(Analysis &a,xxx) --> class CreateTableHandler::rewriteAndUpdate(Analysis &a, LEX *lex, const Preamble &pre) const --> AbstractQueryExecutor *DDLHandler::transformLex(Analysis &a, LEX *lex) const --> Rewriter::dispatchOnLex(Analysis &a, const std::string &query) --> Analysis analysis(default_db, schema, ps.getMasterKey(),ps.defaultSecurityRating()); --> ps.getMasterKey() --> Rewriter::rewrite(const std::string &q, const SchemaInfo &schema,const std::string &default_db, const ProxyState &ps) --> return shared.getMasterKey(); --> const SharedProxyState &shared; --> ProxyState *const ps = thread_ps = c_wrapper->ps.get(); --> WrapperState *const c_wrapper = clients[client]; clients[client]-->WrapperState-->ProxyState-->SharedProxyState --> clients[client]->ps = std::unique_ptr<ProxyState>(new ProxyState(*shared_ps)); --> SharedProxyState::SharedProxyState(ConnectionInfo ci,const std::string &embed_dir,const std::string &master_key,SECURITY_RATING default_sec_rating) : masterKey(std::unique_ptr<AES_KEY>(getKey(master_key))), embed_dir(embed_dir), mysql_dummy(SharedProxyState::db_init(embed_dir)), --> getKey(master_key)获得 AES_KEY --> const std::string &mkey = "113341234"; shared_ps = new SharedProxyState(ci, embed_dir, mkey, determineSecurityRating()); //shared_ps 包含conn e_conn
加解密元数据的读写 |
1、一个字段会扩展为多个字段,用于不同的同态加密。扩展后的一个字段,也就是一个洋葱,一个洋葱对应多层加密,每层加密就是一个洋葱层。 2、每个洋葱层,需要确定加密算法和秘钥。 3、加密算法是由所支持的同态运算所决定的,比如 支持int的同态加密,使用DET_int。 4、秘钥是怎么来的? 秘钥是创建表的时候生成的,转化的步骤很多。参数的来源在哪里? 5、秘钥需要持久化,保存在哪里? 在embedded_db,递归调用读取。
加解密元数据的读操作 |
1、类图 SharedProxyState<>——SchemaCache——>SchemaInfo<>——DatabaseMeta<>——TableMeta<>——FieldMeta<>——OnionMeta<>——EncLayer SchemaInfo对应一个数据库的加密元数据 2、递归调用,load加密元数据 std::function<DBMeta *(DBMeta *const)> loadChildren = [&loadChildren, &e_conn](DBMeta *const parent) { auto kids = parent->fetchChildren(e_conn); for (auto it : kids) { loadChildren(it); } return parent; /* lambda */ }; loadChildren(schema.get()); 堆栈可以看到,__lambda5::operator() rewrite_main.cc:607 构建秘钥,从数据库读取,然后反序列化。 3、数据的crud操作(增删改查)涉及到加解密,那就需要用到秘钥,每次从embedded_db读取,效率太低。 需要把数据load到内存中,这就是涉及到同步,保持一致性。怎么解决这个问题? a、SchemaCache有个字段no_loads表示是否加载元数据,初始化为 true,表示没有加载,启动proxy,第一次tlogin,no_loads设置为false b、同时【INSERT INTO embedded_db.generic_prefix_staleness (cache_id, stale) VALUES (2313589110, TRUE);】 stale表示过时的数据,表示需要更新。 c、每次判断是否需要重新读取,都是 【SELECT stale FROM embedded_db.generic_prefix_staleness WHERE cache_id = 3209647041;】检查这个取值。 d、在哪里更新stale? SchemaCache::updateStaleness,为了保证已经存在的记录,也需要重读,把之前的设置为true 4、哪些情况判断是否读取?直接看调用图 SchemaCache::getSchema rewrite 每次rewrite都要判断 OnionAdjustmentExecutor::nextImpl(const ResType &res, const NextParams &nparams) 洋葱层调整,需要再次判断 ShowTablesExecutor::nextImpl(const ResType &res, const NextParams &nparams) SpecialUpdateExecutor::nextImpl(const ResType &res, const NextParams &nparams) 5、哪些情况更新stale值 SchemaCache::updateStaleness AbstractQueryExecutor::next --> AbstractQueryExecutor::genericPreamble --> nparams.ps.getSchemaCache().updateStaleness(nparams.ps.getEConn(), this->stales());
和lua的交互流程 |
1、read_query read_query --> read_query_real --> next_handler --> CryptDB.next 接收客户端的请求sql,进行转化,return proxy.PROXY_SEND_QUERY 改写后的sql语句,通过 proxy.queries:append 传递过去。 2、read_query_result read_query_result --> read_query_result_real --> next_handler --> CryptDB.next 接收mysql的返回,进行处理,return proxy.PROXY_SEND_RESULT 处理后,如果有结果集需要返回,通过 proxy.response.resultset 传递过去。 3、proxy与mysql交互,从mysql返回之后,必定进入 read_query_result 分为几种情况: a、不需要处理,比如 show databases; 直接返回 b、只需要处理一次,比如 show tables; 解密一些表名即可 c、需要处理多次,比如create table; 4、分析show databases;的流程: a、客户端发给proxy请求show databases,read_query接口返回PROXY_SEND_QUERY,同时传递改写后的sql语句,还是show databases b、内部的next接口返回query-results,把skip置为true b、proxy和mysql交互,从mysql收到响应包,在read_query_result_real检查到是skip,直接返回。 5、分析show tables;的流程: a、客户端发给proxy请求show tables,read_query接口返回PROXY_SEND_QUERY,同时传递改写后的sql语句,还是show tables b、内部的next接口返回again c、proxy和mysql交互,从mysql收到响应包,在read_query_result_real,打印响应的结果,然后 next_handler("results", d、next返回"results",解密返回,return proxy.PROXY_SEND_RESULT,也就是说,先检查next的返回,再检查从哪里来的? 6、分析create table;的流程: a、客户端发给proxy请求create table,read_query接口返回PROXY_SEND_QUERY,同时传递改写后的sql语句,create tablexxx b、内部的next接口返回again c、proxy和mysql交互,从mysql收到响应包,在read_query_result_real,打印响应的结果,然后 next_handler("results", d、next返回"again",告诉proxy忽略mysql的返回。 e、proxy和mysql交互,从mysql收到响应包,next返回"results" 7、也就是说, 第一次的改写返回PROXY_SEND_QUERY, 中间过程的改写,返回PROXY_IGNORE_RESULT 最后一步的处理,返回PROXY_SEND_RESULT 8、CryptDB.next的返回有三个值: again 要求proxy和mysql交互,并且再次进来,处理mysql的响应 query-results mysql的响应,到lua之后,lua直接返回 results 返回最后处理的结果,要求proxy转发给客户端 9、proxy收到的回复有三个值: PROXY_SEND_QUERY 向mysql发送请求 PROXY_SEND_RESULT 向客户端发送最后的结果 PROXY_IGNORE_RESULT 忽略中间过程的结果 10、总结一下,也就是说: 第一步是改写,要求proxy和mysql交互, 中间步骤处理返回的结果,比如剥洋葱,或者插入到remote_db,再次要求proxy和mysql交互,并且proxy忽略mysql的返回 最后一步,改写mysql返回的结果集。
洋葱层调整测试 |
1、剥洋葱,已经插入的数据,通过update更新掉,新插入的数据,加密层也会发生变化,少一层加密 2、准备测试数据如下: start transaction; create table student(id int, name varchar(64)); insert into student(id ,name) value (1,"Andy"); insert into student(id ,name) value (2,"Bill"); insert into student(id ,name) value (3,"Caroline"); insert into student(id ,name) value (4,"David"); commit; 3、测试洋葱层调整 select * from student where id =2; 4、按道理,洋葱层会少一层,在哪里处理的? 之前查回来的结果,和现在查回来的结果,对照一下。 5、在哪里删除RND记录的? deltaOutputBeforeQuery-->bool DeleteDelta::apply " DELETE embedded_db.generic_prefix_BleedingMetaObject FROM embedded_db.generic_prefix_BleedingMetaObject WHERE embedded_db.generic_prefix_BleedingMetaObject.id = 252 AND embedded_db.generic_prefix_BleedingMetaObject.parent_id = 249;" deltaOutputAfterQuery-->DeleteDelta::apply " DELETE embedded_db.generic_prefix_MetaObject FROM embedded_db.generic_prefix_MetaObject WHERE embedded_db.generic_prefix_MetaObject.id = 252 AND embedded_db.generic_prefix_MetaObject.parent_id = 249;"
类的层次化结构 |
1、DBMeta是数据库的元数据类,子类MappedDBMeta是类模板,字段包括一个map结构,保存child数据结构。 2、MappedDBMeta会实例化一些模板类,比如MappedDBMeta<DatabaseMeta,IdentityMetaKey>,就是包含一组DatabaseMeta的集合 3、包含一组DatabaseMeta的集合,其实也就是 SchemaInfo,SchemaInfo继承 MappedDBMeta<DatabaseMeta,IdentityMetaKey> 4、DatabaseMeta、TableMeta、FieldMeta也是同样的道理。 5、TableMeta关注以下几个字段,分别为: counter 因为一个表的字段,是有顺序的,counter记录当前的counter值 anon_table_name 是加密后的表名 注意:IdentityMetaKey 是由明文的表名,序列化出来的 tm->addChild(IdentityMetaKey(name), std::move(fm)); 明文的表名-->IdentityMetaKey-->TableMeta-->anno_table_name 6、FieldMeta关注以下几个字段,分别为: fname 字段名称 salt_name 前缀加上随机值 onion_layout 是字段扩展后的洋葱,表示一个字段对应一组洋葱(map),以及每个洋葱对应的一组洋葱层(vector)。 7、OnionMeta不同于上面的结构,不是继承MappedDBMeta,而是直接继承DBMeta,因为OnionMeta直接关联vector的EncLayer,而不是map结构 onionname是洋葱字段名称 8、EncLayer就是叶子结点,继承了LeafDBMeta,在LeafDBMeta中对叶子节点 do nothing EncLayer代表了一个加密层次的抽象
Copyright (c) 2015~2016, Andy Niu @All rights reserved. By Andy Niu Edit.